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:
parent
be43c7f5c0
commit
48efcc449b
|
@ -404,7 +404,89 @@ std::set<long> FemMesh::getSurfaceNodes(long ElemId, short FaceId, float Angle)
|
||||||
return result;
|
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> FemMesh::getNodesByFace(const TopoDS_Face &face) const
|
||||||
{
|
{
|
||||||
std::set<int> result;
|
std::set<int> result;
|
||||||
|
|
|
@ -93,6 +93,8 @@ public:
|
||||||
std::set<int> getNodesByEdge(const TopoDS_Edge &edge) const;
|
std::set<int> getNodesByEdge(const TopoDS_Edge &edge) const;
|
||||||
/// retrieving by vertex
|
/// retrieving by vertex
|
||||||
std::set<int> getNodesByVertex(const TopoDS_Vertex &vertex) const;
|
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 */
|
/** @name Placement control */
|
||||||
|
|
|
@ -84,6 +84,11 @@
|
||||||
<UserDocu>Make a copy of this FEM mesh.</UserDocu>
|
<UserDocu>Make a copy of this FEM mesh.</UserDocu>
|
||||||
</Documentation>
|
</Documentation>
|
||||||
</Methode>
|
</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">
|
<Methode Name="getNodeById" Const="true">
|
||||||
<Documentation>
|
<Documentation>
|
||||||
<UserDocu>Get the node position vector by an Node-ID</UserDocu>
|
<UserDocu>Get the node position vector by an Node-ID</UserDocu>
|
||||||
|
|
|
@ -514,6 +514,38 @@ PyObject* FemMeshPy::setTransform(PyObject *args)
|
||||||
Py_Return;
|
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)
|
PyObject* FemMeshPy::getNodeById(PyObject *args)
|
||||||
{
|
{
|
||||||
int id;
|
int id;
|
||||||
|
|
|
@ -29,6 +29,7 @@ class inp_writer:
|
||||||
self.write_step_begin(inpfile)
|
self.write_step_begin(inpfile)
|
||||||
self.write_constraints_fixed(inpfile)
|
self.write_constraints_fixed(inpfile)
|
||||||
self.write_constraints_force(inpfile)
|
self.write_constraints_force(inpfile)
|
||||||
|
self.write_face_load(inpfile)
|
||||||
self.write_outputs_types(inpfile)
|
self.write_outputs_types(inpfile)
|
||||||
self.write_step_end(inpfile)
|
self.write_step_end(inpfile)
|
||||||
self.write_footer(inpfile)
|
self.write_footer(inpfile)
|
||||||
|
@ -89,10 +90,7 @@ class inp_writer:
|
||||||
for o, elem in frc_obj.References:
|
for o, elem in frc_obj.References:
|
||||||
fo = o.Shape.getElement(elem)
|
fo = o.Shape.getElement(elem)
|
||||||
n = []
|
n = []
|
||||||
if fo.ShapeType == 'Face':
|
if fo.ShapeType == 'Edge':
|
||||||
print ' AreaLoad (face load) on: ', elem
|
|
||||||
n = self.mesh_object.FemMesh.getNodesByFace(fo)
|
|
||||||
elif fo.ShapeType == 'Edge':
|
|
||||||
print ' Line Load (edge load) on: ', elem
|
print ' Line Load (edge load) on: ', elem
|
||||||
n = self.mesh_object.FemMesh.getNodesByEdge(fo)
|
n = self.mesh_object.FemMesh.getNodesByEdge(fo)
|
||||||
elif fo.ShapeType == 'Vertex':
|
elif fo.ShapeType == 'Vertex':
|
||||||
|
@ -177,6 +175,21 @@ class inp_writer:
|
||||||
f.write(frc_obj_name + ',2,' + v2 + '\n')
|
f.write(frc_obj_name + ',2,' + v2 + '\n')
|
||||||
f.write(frc_obj_name + ',3,' + v3 + '\n\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):
|
def write_outputs_types(self, f):
|
||||||
f.write('\n** outputs --> frd file\n')
|
f.write('\n** outputs --> frd file\n')
|
||||||
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))
|
f.write('** written by {} function\n'.format(sys._getframe().f_code.co_name))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user