FEM: Add getccxVolumesByFace and write_face_load functions

getccxVolumesByFace returns std::map<int, int> with ID of volume
and a number of face as per CalculiX definition. The same function is
accessible for python and returns list with the same information, like
this: [[229, 3], [230, 3], [233, 2], [238, 2]]

write_face_load produces something like this in the .inp file:

***********************************************************
** element + CalculiX face + load in [MPa]
** written by write_face_load function
*DLOAD
** Load on face Face2
229,P3,10.0
230,P3,10.0
233,P2,10.0
238,P2,10.0

Optimised by wmayer

Signed-off-by: wmayer
Signed-off-by: Przemo Firszt <przemo@firszt.eu>
This commit is contained in:
Przemo Firszt 2015-05-05 20:27:20 +01:00 committed by wmayer
parent be43c7f5c0
commit 48efcc449b
5 changed files with 138 additions and 4 deletions

View File

@ -404,7 +404,89 @@ std::set<long> FemMesh::getSurfaceNodes(long ElemId, short FaceId, float Angle)
return result;
}
/* That function returns map containing volume ID and face number
* as per CalculiX definition for tetrahedral elements. See CalculiX
* documentation for the details.
*/
std::map<int, int> FemMesh::getccxVolumesByFace(const TopoDS_Face &face) const
{
std::map<int, int> result;
std::set<int> nodes_on_face = FemMesh::getNodesByFace(face);
static std::map<int, std::vector<int> > elem_order;
if (elem_order.empty()) {
std::vector<int> c3d4 = boost::assign::list_of(1)(0)(2)(3);
std::vector<int> c3d10 = boost::assign::list_of(1)(0)(2)(3)(4)(6)(5)(8)(7)(9);
elem_order.insert(std::make_pair(c3d4.size(), c3d4));
elem_order.insert(std::make_pair(c3d10.size(), c3d10));
}
SMDS_VolumeIteratorPtr vol_iter = myMesh->GetMeshDS()->volumesIterator();
std::set<int> element_nodes;
int num_of_nodes;
while (vol_iter->more()) {
const SMDS_MeshVolume* vol = vol_iter->next();
num_of_nodes = vol->NbNodes();
std::pair<int, std::vector<int> > apair;
apair.first = vol->GetID();
std::map<int, std::vector<int> >::iterator it = elem_order.find(num_of_nodes);
if (it != elem_order.end()) {
const std::vector<int>& order = it->second;
for (std::vector<int>::const_iterator jt = order.begin(); jt != order.end(); ++jt) {
int vid = vol->GetNode(*jt)->GetID();
apair.second.push_back(vid);
}
}
// Get volume nodes on face
std::vector<int> element_face_nodes;
std::set<int> element_nodes;
element_nodes.insert(apair.second.begin(), apair.second.end());
std::set_intersection(nodes_on_face.begin(), nodes_on_face.end(), element_nodes.begin(), element_nodes.end(),
std::back_insert_iterator<std::vector<int> >(element_face_nodes));
if ((element_face_nodes.size() == 3 && num_of_nodes == 4) ||
(element_face_nodes.size() == 6 && num_of_nodes == 10)) {
int missing_node = 0;
for (int i=0; i<4; i++) {
// search for the ID of the volume which is not part of 'element_face_nodes'
if (std::find(element_face_nodes.begin(), element_face_nodes.end(), apair.second[i]) == element_face_nodes.end()) {
missing_node = i + 1;
break;
}
}
/* for tetrahedral elements as per CalculiX definition:
Face 1: 1-2-3, missing point 4 means it's face P1
Face 2: 1-4-2, missing point 3 means it's face P2
Face 3: 2-4-3, missing point 1 means it's face P3
Face 4: 3-4-1, missing point 2 means it's face P4 */
int face_ccx;
switch (missing_node) {
case 1:
face_ccx = 3;
break;
case 2:
face_ccx = 4;
break;
case 3:
face_ccx = 2;
break;
case 4:
face_ccx = 1;
break;
default:
assert(false); // should never happen
break;
}
result[apair.first] = face_ccx;
}
}
return result;
}
std::set<int> FemMesh::getNodesByFace(const TopoDS_Face &face) const
{
std::set<int> result;

View File

@ -93,6 +93,8 @@ public:
std::set<int> getNodesByEdge(const TopoDS_Edge &edge) const;
/// retrieving by vertex
std::set<int> getNodesByVertex(const TopoDS_Vertex &vertex) const;
/// retrieving volume IDs and CalculiX face number by face
std::map<int, int> getccxVolumesByFace(const TopoDS_Face &face) const;
//@}
/** @name Placement control */

View File

@ -84,6 +84,11 @@
<UserDocu>Make a copy of this FEM mesh.</UserDocu>
</Documentation>
</Methode>
<Methode Name="getccxVolumesByFace" Const="true">
<Documentation>
<UserDocu>Return a list of volume IDs which belong to a TopoFace</UserDocu>
</Documentation>
</Methode>
<Methode Name="getNodeById" Const="true">
<Documentation>
<UserDocu>Get the node position vector by an Node-ID</UserDocu>

View File

@ -514,6 +514,38 @@ PyObject* FemMeshPy::setTransform(PyObject *args)
Py_Return;
}
PyObject* FemMeshPy::getccxVolumesByFace(PyObject *args)
{
PyObject *pW;
if (!PyArg_ParseTuple(args, "O!", &(Part::TopoShapeFacePy::Type), &pW))
return 0;
try {
const TopoDS_Shape& sh = static_cast<Part::TopoShapeFacePy*>(pW)->getTopoShapePtr()->_Shape;
const TopoDS_Face& fc = TopoDS::Face(sh);
if (sh.IsNull()) {
PyErr_SetString(Base::BaseExceptionFreeCADError, "Face is empty");
return 0;
}
Py::List ret;
std::map<int, int> resultSet = getFemMeshPtr()->getccxVolumesByFace(fc);
for (std::map<int, int>::const_iterator it = resultSet.begin();it!=resultSet.end();++it) {
Py::List vol_face;
vol_face.append(Py::Int(it->first));
vol_face.append(Py::Int(it->second));
ret.append(vol_face);
}
return Py::new_reference_to(ret);
}
catch (Standard_Failure) {
Handle_Standard_Failure e = Standard_Failure::Caught();
PyErr_SetString(Base::BaseExceptionFreeCADError, e->GetMessageString());
return 0;
}
}
PyObject* FemMeshPy::getNodeById(PyObject *args)
{
int id;

View File

@ -29,6 +29,7 @@ class inp_writer:
self.write_step_begin(inpfile)
self.write_constraints_fixed(inpfile)
self.write_constraints_force(inpfile)
self.write_face_load(inpfile)
self.write_outputs_types(inpfile)
self.write_step_end(inpfile)
self.write_footer(inpfile)
@ -89,10 +90,7 @@ class inp_writer:
for o, elem in frc_obj.References:
fo = o.Shape.getElement(elem)
n = []
if fo.ShapeType == 'Face':
print ' AreaLoad (face load) on: ', elem
n = self.mesh_object.FemMesh.getNodesByFace(fo)
elif fo.ShapeType == 'Edge':
if fo.ShapeType == 'Edge':
print ' Line Load (edge load) on: ', elem
n = self.mesh_object.FemMesh.getNodesByEdge(fo)
elif fo.ShapeType == 'Vertex':
@ -177,6 +175,21 @@ class inp_writer:
f.write(frc_obj_name + ',2,' + v2 + '\n')
f.write(frc_obj_name + ',3,' + v3 + '\n\n')
def write_face_load(self, f):
f.write('***********************************************************\n')
f.write('** element + CalculiX face + load in [MPa]\n')
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))
for fobj in self.force_objects:
frc_obj = fobj['Object']
f.write('*DLOAD\n')
for o, e in frc_obj.References:
elem = o.Shape.getElement(e)
if elem.ShapeType == 'Face':
v = self.mesh_object.FemMesh.getccxVolumesByFace(elem)
f.write("** Load on face {}\n".format(e))
for i in v:
f.write("{},P{},{}\n".format(i[0], i[1], frc_obj.Force))
def write_outputs_types(self, f):
f.write('\n** outputs --> frd file\n')
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))