diff --git a/src/Mod/Fem/App/FemMesh.cpp b/src/Mod/Fem/App/FemMesh.cpp index 3d9bc164f5..dc5e93e2ed 100644 --- a/src/Mod/Fem/App/FemMesh.cpp +++ b/src/Mod/Fem/App/FemMesh.cpp @@ -1929,7 +1929,12 @@ void FemMesh::read(const char* FileName) } } -void FemMesh::writeABAQUS(const std::string& Filename, int elemParam, bool groupParam) const +void FemMesh::writeABAQUS(const std::string& Filename, + int elemParam, + bool groupParam, + ABAQUS_VolumeVariant volVariant, + ABAQUS_FaceVariant faceVariant, + ABAQUS_EdgeVariant edgeVariant) const { /* * elemParam: @@ -1940,121 +1945,220 @@ void FemMesh::writeABAQUS(const std::string& Filename, int elemParam, bool group * groupParam: * true = write group data * false = do not write group data + + * volVariant, faceVariant, edgeVariant: + * Element type according to availability in CalculiX */ - static std::map> elemOrderMap; - static std::map edgeTypeMap; - static std::map faceTypeMap; - static std::map volTypeMap; - if (elemOrderMap.empty()) { - // node order fits with node order in importCcxFrdResults.py module to import - // CalculiX result meshes + std::map variants; - // dimension 1 - // - // seg2 FreeCAD --> CalculiX B31 - // N1, N2 - std::vector b31 = boost::assign::list_of(0)(1); - // - // seg3 FreeCAD --> CalculiX B32 - // N1, N3, N2 - std::vector b32 = boost::assign::list_of(0)(2)(1); + // volume elements + variants["Tetra4"] = "C3D4"; + variants["Penta6"] = "C3D6"; + variants["Hexa8"] = "C3D8"; + variants["Tetra10"] = "C3D10"; + variants["Penta15"] = "C3D15"; + variants["Hexa20"] = "C3D20"; - elemOrderMap.insert(std::make_pair("B31", b31)); - edgeTypeMap.insert(std::make_pair(elemOrderMap["B31"].size(), "B31")); - elemOrderMap.insert(std::make_pair("B32", b32)); - edgeTypeMap.insert(std::make_pair(elemOrderMap["B32"].size(), "B32")); - - // dimension 2 - // - // tria3 FreeCAD --> S3 CalculiX - // N1, N2, N3 - std::vector s3 = boost::assign::list_of(0)(1)(2); - // - // tria6 FreeCAD --> S6 CalculiX - // N1, N2, N3, N4, N5, N6 - std::vector s6 = boost::assign::list_of(0)(1)(2)(3)(4)(5); - // - // quad4 FreeCAD --> S4 CalculiX - // N1, N2, N3, N4 - std::vector s4 = boost::assign::list_of(0)(1)(2)(3); - // - // quad8 FreeCAD --> S8 CalculiX - // N1, N2, N3, N4, N5, N6, N7, N8 - std::vector s8 = boost::assign::list_of(0)(1)(2)(3)(4)(5)(6)(7); - - elemOrderMap.insert(std::make_pair("S3", s3)); - faceTypeMap.insert(std::make_pair(elemOrderMap["S3"].size(), "S3")); - elemOrderMap.insert(std::make_pair("S6", s6)); - faceTypeMap.insert(std::make_pair(elemOrderMap["S6"].size(), "S6")); - elemOrderMap.insert(std::make_pair("S4", s4)); - faceTypeMap.insert(std::make_pair(elemOrderMap["S4"].size(), "S4")); - elemOrderMap.insert(std::make_pair("S8", s8)); - faceTypeMap.insert(std::make_pair(elemOrderMap["S8"].size(), "S8")); - - // dimension 3 - // - // tetras - // master 0.14 release - // changed to this in August 2013, committed by juergen (jriedel) - // https://github.com/FreeCAD/FreeCAD/commit/af56b324b9566b20f3b6e7880c29354c1dbe7a99 - // std::vector c3d4 = boost::assign::list_of(0)(3)(1)(2); - // std::vector c3d10 = boost::assign::list_of(0)(2)(1)(3)(6)(5)(4)(7)(9)(8); - - // since master 0.15 - // added by werner (wmayer) March 2015, - // https://forum.freecad.org/viewtopic.php?f=18&t=10110&start=10#p81681 - // https://github.com/FreeCAD/FreeCAD/commit/5d159f5cf352a93b1aff4fb7b82e8b747ee4f35b - // https://github.com/FreeCAD/FreeCAD/commit/b007bd19e4e4608caa4cdad350a9f480287fac6b - // tetra4 FreeCAD --> C3D4 CalculiX - // N2, N1, N3, N4 - std::vector c3d4 = boost::assign::list_of(1)(0)(2)(3); - // tetra10: FreeCAD --> C3D10 CalculiX - // N2, N1, N3, N4, N5, N7, N6, N9, N8, N10 - std::vector c3d10 = boost::assign::list_of(1)(0)(2)(3)(4)(6)(5)(8)(7)(9); - - // tetra node order for the system which is used for hexa8, hexa20, penta6 and penda15 - // be careful with activating because of method getccxVolumesByFace()) - // tetra4 FreeCAD --> C3D4 CalculiX - // N2, N3, N4, N1 - // std::vector c3d4 = boost::assign::list_of(1)(2)(3)(0); - // - // tetra10: FreeCAD --> C3D10 CalculiX - // N2, N3, N4, N1, N6, N10, N9, N5, N7, N8 - // std::vector c3d10 = boost::assign::list_of(1)(2)(3)(0)(5)(9)(8)(4)(6)(7); - - // hexa8 FreeCAD --> C3D8 CalculiX - // N6, N7, N8, N5, N2, N3, N4, N1 - std::vector c3d8 = boost::assign::list_of(5)(6)(7)(4)(1)(2)(3)(0); - // - // hexa20 FreeCAD --> C3D20 CalculiX - // N6, N7, N8, N5, N2, N3, N4, N1, N14, N15, N16, N13, N10, N11, N12, N9, N18, N19, N20, N17 - std::vector c3d20 = boost::assign::list_of(5)(6)(7)(4)(1)(2)(3)(0)(13)(14)(15)(12)(9)( - 10)(11)(8)(17)(18)(19)(16); - // - // penta6 FreeCAD --> C3D6 CalculiX - // N5, N6, N4, N2, N3, N1 - std::vector c3d6 = boost::assign::list_of(4)(5)(3)(1)(2)(0); - // - // penta15 FreeCAD --> C3D15 CalculiX - // N5, N6, N4, N2, N3, N1, N11, N12, N10, N8, N9, N7, N14, N15, N13 - std::vector c3d15 = - boost::assign::list_of(4)(5)(3)(1)(2)(0)(10)(11)(9)(7)(8)(6)(13)(14)(12); - - elemOrderMap.insert(std::make_pair("C3D4", c3d4)); - volTypeMap.insert(std::make_pair(elemOrderMap["C3D4"].size(), "C3D4")); - elemOrderMap.insert(std::make_pair("C3D10", c3d10)); - volTypeMap.insert(std::make_pair(elemOrderMap["C3D10"].size(), "C3D10")); - elemOrderMap.insert(std::make_pair("C3D8", c3d8)); - volTypeMap.insert(std::make_pair(elemOrderMap["C3D8"].size(), "C3D8")); - elemOrderMap.insert(std::make_pair("C3D20", c3d20)); - volTypeMap.insert(std::make_pair(elemOrderMap["C3D20"].size(), "C3D20")); - elemOrderMap.insert(std::make_pair("C3D6", c3d6)); - volTypeMap.insert(std::make_pair(elemOrderMap["C3D6"].size(), "C3D6")); - elemOrderMap.insert(std::make_pair("C3D15", c3d15)); - volTypeMap.insert(std::make_pair(elemOrderMap["C3D15"].size(), "C3D15")); + switch (volVariant) { + case ABAQUS_VolumeVariant::Standard: + break; + case ABAQUS_VolumeVariant::Reduced: + variants["Hexa8"] = "C3D8R"; + variants["Hexa20"] = "C3D20R"; + break; + case ABAQUS_VolumeVariant::Incompatible: + variants["Hexa8"] = "C3D8I"; + break; + case ABAQUS_VolumeVariant::Modified: + variants["Tetra10"] = "C3D10T"; + break; + case ABAQUS_VolumeVariant::Fluid: + variants["Tetra4"] = "F3D4"; + variants["Penta6"] = "F3D6"; + variants["Hexa8"] = "F3D8"; + break; } + // face elements + switch (faceVariant) { + case ABAQUS_FaceVariant::Shell: + variants["Tria3"] = "S3"; + variants["Quad4"] = "S4"; + variants["Tria6"] = "S6"; + variants["Quad8"] = "S8"; + break; + case ABAQUS_FaceVariant::Shell_Reduced: + variants["Tria3"] = "S3"; + variants["Quad4"] = "S4R"; + variants["Tria6"] = "S6"; + variants["Quad8"] = "S8R"; + break; + case ABAQUS_FaceVariant::Membrane: + variants["Tria3"] = "M3D3"; + variants["Quad4"] = "M3D4"; + variants["Tria6"] = "M3D6"; + variants["Quad8"] = "M3D8"; + break; + case ABAQUS_FaceVariant::Membrane_Reduced: + variants["Tria3"] = "M3D3"; + variants["Quad4"] = "M3D4R"; + variants["Tria6"] = "M3D6"; + variants["Quad8"] = "M3D8R"; + break; + case ABAQUS_FaceVariant::Stress: + variants["Tria3"] = "CPS3"; + variants["Quad4"] = "CPS4"; + variants["Tria6"] = "CPS6"; + variants["Quad8"] = "CPS8"; + break; + case ABAQUS_FaceVariant::Stress_Reduced: + variants["Tria3"] = "CPS3"; + variants["Quad4"] = "CPS4R"; + variants["Tria6"] = "CPS6"; + variants["Quad8"] = "CPS8R"; + break; + case ABAQUS_FaceVariant::Strain: + variants["Tria3"] = "CPE3"; + variants["Quad4"] = "CPE4"; + variants["Tria6"] = "CPE6"; + variants["Quad8"] = "CPE8"; + break; + case ABAQUS_FaceVariant::Strain_Reduced: + variants["Tria3"] = "CPE3"; + variants["Quad4"] = "CPE4R"; + variants["Tria6"] = "CPE6"; + variants["Quad8"] = "CPE8R"; + break; + case ABAQUS_FaceVariant::Axisymmetric: + variants["Tria3"] = "CAX3"; + variants["Quad4"] = "CAX4"; + variants["Tria6"] = "CAX6"; + variants["Quad8"] = "CAX8"; + break; + case ABAQUS_FaceVariant::Axisymmetric_Reduced: + variants["Tria3"] = "CAX3"; + variants["Quad4"] = "CAX4R"; + variants["Tria6"] = "CAX6"; + variants["Quad8"] = "CAX8R"; + break; + } + + // edge elements + switch (edgeVariant) { + case ABAQUS_EdgeVariant::Beam: + variants["Seg2"] = "B31"; + variants["Seg3"] = "B32"; + break; + case ABAQUS_EdgeVariant::Beam_Reduced: + variants["Seg2"] = "B31R"; + variants["Seg3"] = "B32R"; + break; + case ABAQUS_EdgeVariant::Truss: + variants["Seg2"] = "T3D2"; + variants["Seg3"] = "T3D3"; + break; + case ABAQUS_EdgeVariant::Network: + variants["Seg2"] = "B31"; + variants["Seg3"] = "D"; + break; + } + + std::map> elemOrderMap; + std::map edgeTypeMap; + std::map faceTypeMap; + std::map volTypeMap; + + + // node order fits with node order in importCcxFrdResults.py module to import + // CalculiX result meshes + + // dimension 1 + // + // seg2 FreeCAD --> B31, B31R, T3D2 CalculiX + // N1, N2 + std::vector seg2 = boost::assign::list_of(0)(1); + // + // seg3 FreeCAD --> B32, B32R, T3D3 D CalculiX + // N1, N3, N2 + std::vector seg3 = boost::assign::list_of(0)(2)(1); + + elemOrderMap.insert(std::make_pair(variants["Seg2"], seg2)); + edgeTypeMap.insert(std::make_pair(seg2.size(), variants["Seg2"])); + elemOrderMap.insert(std::make_pair(variants["Seg3"], seg3)); + edgeTypeMap.insert(std::make_pair(seg3.size(), variants["Seg3"])); + + // dimension 2 + // + // tria3 FreeCAD --> S3, M3D3, CPS3, CPE3, CAX3 CalculiX + // N1, N2, N3 + std::vector tria3 = boost::assign::list_of(0)(1)(2); + // + // tria6 FreeCAD --> S6 M3D6, CPS6, CPE6, CAX6 CalculiX + // N1, N2, N3, N4, N5, N6 + std::vector tria6 = boost::assign::list_of(0)(1)(2)(3)(4)(5); + // + // quad4 FreeCAD --> S4, S4R, M3D4, M3D4R, CPS4, CPS4R, CPE4, CPE4R, CAX4, CAX4R CalculiX + // N1, N2, N3, N4 + std::vector quad4 = boost::assign::list_of(0)(1)(2)(3); + // + // quad8 FreeCAD --> S8, S8R, M3D8, M3D8R, CPS8, CPS8R, CPE8, CPE8R, CAX8, CAX8R CalculiX + // N1, N2, N3, N4, N5, N6, N7, N8 + std::vector quad8 = boost::assign::list_of(0)(1)(2)(3)(4)(5)(6)(7); + + elemOrderMap.insert(std::make_pair(variants["Tria3"], tria3)); + faceTypeMap.insert(std::make_pair(tria3.size(), variants["Tria3"])); + elemOrderMap.insert(std::make_pair(variants["Tria6"], tria6)); + faceTypeMap.insert(std::make_pair(tria6.size(), variants["Tria6"])); + elemOrderMap.insert(std::make_pair(variants["Quad4"], quad4)); + faceTypeMap.insert(std::make_pair(quad4.size(), variants["Quad4"])); + elemOrderMap.insert(std::make_pair(variants["Quad8"], quad8)); + faceTypeMap.insert(std::make_pair(quad8.size(), variants["Quad8"])); + + + // dimension 3 + // + // tetra4 FreeCAD --> C3D4, F3D4 CalculiX + // N2, N1, N3, N4 + std::vector tetra4 = boost::assign::list_of(1)(0)(2)(3); + // tetra10: FreeCAD --> C3D10, C3D10T CalculiX + // N2, N1, N3, N4, N5, N7, N6, N9, N8, N10 + std::vector tetra10 = boost::assign::list_of(1)(0)(2)(3)(4)(6)(5)(8)(7)(9); + + // tetra node order for the system which is used for hexa8, hexa20, penta6 and penta15 + // be careful with activating because of method getccxVolumesByFace()) + // hexa8 FreeCAD --> C3D8, C3D8R, C3D8I, F3D8 CalculiX + // N6, N7, N8, N5, N2, N3, N4, N1 + std::vector hexa8 = boost::assign::list_of(5)(6)(7)(4)(1)(2)(3)(0); + // + // hexa20 FreeCAD --> C3D20, C3D20R CalculiX + // N6, N7, N8, N5, N2, N3, N4, N1, N14, N15, N16, N13, N10, N11, N12, N9, N18, N19, N20, N17 + std::vector hexa20 = boost::assign::list_of(5)(6)(7)(4)(1)(2)(3)(0)(13)(14)(15)(12)(9)(10)( + 11)(8)(17)(18)(19)(16); + // + // penta6 FreeCAD --> C3D6, F3D6 CalculiX + // N5, N6, N4, N2, N3, N1 + std::vector penta6 = boost::assign::list_of(4)(5)(3)(1)(2)(0); + // + // penta15 FreeCAD --> C3D15 CalculiX + // N5, N6, N4, N2, N3, N1, N11, N12, N10, N8, N9, N7, N14, N15, N13 + std::vector penta15 = + boost::assign::list_of(4)(5)(3)(1)(2)(0)(10)(11)(9)(7)(8)(6)(13)(14)(12); + + elemOrderMap.insert(std::make_pair(variants["Tetra4"], tetra4)); + volTypeMap.insert(std::make_pair(tetra4.size(), variants["Tetra4"])); + elemOrderMap.insert(std::make_pair(variants["Tetra10"], tetra10)); + volTypeMap.insert(std::make_pair(tetra10.size(), variants["Tetra10"])); + elemOrderMap.insert(std::make_pair(variants["Hexa8"], hexa8)); + volTypeMap.insert(std::make_pair(hexa8.size(), variants["Hexa8"])); + elemOrderMap.insert(std::make_pair(variants["Hexa20"], hexa20)); + volTypeMap.insert(std::make_pair(hexa20.size(), variants["Hexa20"])); + elemOrderMap.insert(std::make_pair(variants["Penta6"], penta6)); + volTypeMap.insert(std::make_pair(penta6.size(), variants["Penta6"])); + elemOrderMap.insert(std::make_pair(variants["Penta15"], penta15)); + volTypeMap.insert(std::make_pair(penta15.size(), variants["Penta15"])); + + // get all data --> Extract Nodes and Elements of the current SMESH datastructure using VertexMap = std::map; using NodesMap = std::map>; diff --git a/src/Mod/Fem/App/FemMesh.h b/src/Mod/Fem/App/FemMesh.h index 8c3431a869..4ef1144983 100644 --- a/src/Mod/Fem/App/FemMesh.h +++ b/src/Mod/Fem/App/FemMesh.h @@ -47,6 +47,35 @@ class TopoDS_Solid; namespace Fem { +enum class ABAQUS_VolumeVariant +{ + Standard, + Reduced, + Incompatible, + Modified, + Fluid +}; +enum class ABAQUS_FaceVariant +{ + Shell, + Shell_Reduced, + Membrane, + Membrane_Reduced, + Stress, + Stress_Reduced, + Strain, + Strain_Reduced, + Axisymmetric, + Axisymmetric_Reduced +}; +enum class ABAQUS_EdgeVariant +{ + Beam, + Beam_Reduced, + Truss, + Network +}; + using SMESH_HypothesisPtr = std::shared_ptr; /** The representation of a FemMesh @@ -172,7 +201,12 @@ public: /// import from files void read(const char* FileName); void write(const char* FileName) const; - void writeABAQUS(const std::string& Filename, int elemParam, bool groupParam) const; + void writeABAQUS(const std::string& Filename, + int elemParam, + bool groupParam, + ABAQUS_VolumeVariant volVariant = ABAQUS_VolumeVariant::Standard, + ABAQUS_FaceVariant faceVariant = ABAQUS_FaceVariant::Shell, + ABAQUS_EdgeVariant edgeVariant = ABAQUS_EdgeVariant::Beam) const; void writeZ88(const std::string& FileName) const; private: diff --git a/src/Mod/Fem/App/FemMeshPy.xml b/src/Mod/Fem/App/FemMeshPy.xml index f45ffacc3a..d101aaf584 100755 --- a/src/Mod/Fem/App/FemMeshPy.xml +++ b/src/Mod/Fem/App/FemMeshPy.xml @@ -74,13 +74,40 @@ - + Write out as ABAQUS inp writeABAQUS(file, int elemParam, bool groupParam) elemParam: 0 = all elements, 1 = highest elements only, 2 = FEM elements only (only edges not belonging to faces and faces not belonging to volumes) groupParam: true = write group data, false = do not write group data - + volVariant: Volume elements + "standard": Tetra4 -> C3D4, Penta6 -> C3D6, Hexa8 -> C3D8, Tetra10 -> C3D10, Penta15 -> C3D15, Hexa20 -> C3D20 + "reduced": Hexa8 -> C3D8R, Hexa20 -> C3D20R + "incompatible": Hexa8 -> C3D8I + "modified": Tetra10 -> C3D10T + "fluid": Tetra4 -> F3D4, Penta6 -> F3D6, Hexa8 -> F3D8 + + faceVariant: Face elements + "shell": Tria3 -> S3, Quad4 -> S4, Tria6 -> S6, Quad8 -> S8 + "shell reduced": Tria3 -> S3, Quad4 -> S4R, Tria6 -> S6, Quad8 -> S8R + "membrane": Tria3 -> M3D3, Quad4 -> M3D4, Tria6 -> M3D6, Quad8 -> M3D8 + "membrane reduced": Tria3 -> M3D3, Quad4 -> M3D4R, Tria6 -> M3D6, Quad8 -> M3D8R + "stress": Tria3 -> CPS3, Quad4 -> CPS4, Tria6 -> CPS6, Quad8 -> CPS8 + "stress reduced": Tria3 -> CPS3, Quad4 -> CPS4R, Tria6 -> CPS6, Quad8 -> CPS8R + "strain": Tria3 -> CPE3, Quad4 -> CPE4, Tria6 -> CPE6, Quad8 -> CPE8 + "strain reduced": Tria3 -> CPE3, Quad4 -> CPE4R, Tria6 -> CPE6, Quad8 -> CPE8R + "axisymmetric": Tria3 -> CAX3, Quad4 -> CAX4, Tria6 -> CAX6, Quad8 -> CAX8 + "axisymmetric reduced": Tria3 -> CAX3, Quad4 -> CAX4R, Tria6 -> CAX6, Quad8 -> CAX8R + + edgeVariant: Edge elements + "beam": Seg2 -> B31, Seg3 -> B32 + "beam reduced": Seg2 -> B31R, Seg3 -> B32R + "truss": Seg2 -> T3D2, eg3 -> T3D3 + "network": Seg3 -> D + + Elements are selected according to CalculiX availability. + For example if volume variant "modified" is selected, Tetra10 mesh + elements are assigned to C3D10T and remain elements uses "standard" diff --git a/src/Mod/Fem/App/FemMeshPyImp.cpp b/src/Mod/Fem/App/FemMeshPyImp.cpp index 0a0d764135..9f3bda927c 100644 --- a/src/Mod/Fem/App/FemMeshPyImp.cpp +++ b/src/Mod/Fem/App/FemMeshPyImp.cpp @@ -39,6 +39,7 @@ #include "Mod/Fem/App/FemMesh.h" #include +#include #include #include #include @@ -856,20 +857,88 @@ PyObject* FemMeshPy::write(PyObject* args) Py_Return; } -PyObject* FemMeshPy::writeABAQUS(PyObject* args) +namespace +{ + +std::map volVariantPyMap = { + {"standard", ABAQUS_VolumeVariant::Standard}, + {"reduced", ABAQUS_VolumeVariant::Reduced}, + {"incompatible", ABAQUS_VolumeVariant::Incompatible}, + {"modified", ABAQUS_VolumeVariant::Modified}, + {"fluid", ABAQUS_VolumeVariant::Fluid}}; + +std::map faceVariantPyMap = { + {"shell", ABAQUS_FaceVariant::Shell}, + {"shell reduced", ABAQUS_FaceVariant::Shell_Reduced}, + {"membrane", ABAQUS_FaceVariant::Membrane}, + {"membrane reduced", ABAQUS_FaceVariant::Membrane_Reduced}, + {"stress", ABAQUS_FaceVariant::Stress}, + {"stress reduced", ABAQUS_FaceVariant::Stress_Reduced}, + {"strain", ABAQUS_FaceVariant::Strain}, + {"strain reduced", ABAQUS_FaceVariant::Strain_Reduced}, + {"axisymmetric", ABAQUS_FaceVariant::Axisymmetric}, + {"axisymmetric reduced", ABAQUS_FaceVariant::Axisymmetric_Reduced}}; + +std::map edgeVariantPyMap = { + {"beam", ABAQUS_EdgeVariant::Beam}, + {"beam reduced", ABAQUS_EdgeVariant::Beam_Reduced}, + {"truss", ABAQUS_EdgeVariant::Truss}, + {"network", ABAQUS_EdgeVariant::Network}}; + +} // namespace + +PyObject* FemMeshPy::writeABAQUS(PyObject* args, PyObject* kwd) { char* Name; int elemParam; PyObject* groupParam; - if (!PyArg_ParseTuple(args, "etiO!", "utf-8", &Name, &elemParam, &PyBool_Type, &groupParam)) { + const char* volVariant = "standard"; + const char* faceVariant = "shell"; + const char* edgeVariant = "beam"; + + const std::array kwlist {"fileName", + "elemParam", + "groupParam", + "volVariant", + "faceVariant", + "edgeVariant", + nullptr}; + + if (!Base::Wrapped_ParseTupleAndKeywords(args, + kwd, + "etiO!|sss", + kwlist, + "utf-8", + &Name, + &elemParam, + &PyBool_Type, + &groupParam, + &volVariant, + &faceVariant, + &edgeVariant)) { return nullptr; } + std::string EncodedName = std::string(Name); PyMem_Free(Name); bool grpParam = Base::asBoolean(groupParam); + auto itVol = volVariantPyMap.find(volVariant); + auto itFace = faceVariantPyMap.find(faceVariant); + auto itEdge = edgeVariantPyMap.find(edgeVariant); + + if (itVol == volVariantPyMap.end() || itFace == faceVariantPyMap.end() + || itEdge == edgeVariantPyMap.end()) { + PyErr_SetString(PyExc_ValueError, "Invalid variant value"); + return nullptr; + } try { - getFemMeshPtr()->writeABAQUS(EncodedName.c_str(), elemParam, grpParam); + getFemMeshPtr()->writeABAQUS(EncodedName.c_str(), + elemParam, + grpParam, + itVol->second, + itFace->second, + itEdge->second); } catch (const std::exception& e) { PyErr_SetString(Base::PyExc_FC_GeneralError, e.what()); diff --git a/src/Mod/Fem/femmesh/meshtools.py b/src/Mod/Fem/femmesh/meshtools.py index 35af3b8c93..845119f25e 100644 --- a/src/Mod/Fem/femmesh/meshtools.py +++ b/src/Mod/Fem/femmesh/meshtools.py @@ -2343,24 +2343,6 @@ def get_three_non_colinear_nodes( return [node_1, node_2, node_3] -# ************************************************************************************************ -def write_D_network_element_to_inputfile( - fileName -): - # replace B32 elements with D elements for fluid section - f = open(fileName, "r+") - lines = f.readlines() - f.seek(0) - for line in lines: - if line.find("B32") == -1: - f.write(line) - else: - dummy = line.replace("B32", "D") - f.write(dummy) - f.truncate() - f.close() - - # ************************************************************************************************ def use_correct_fluidinout_ele_def( FluidInletoutlet_ele, @@ -2505,85 +2487,6 @@ def compact_mesh( # may be return another value if the mesh was compacted, just check last map entries return (new_mesh, node_map, elem_map) -# ************************************************************************************************ -def beam_reduced_integration( - fileName -): - # replace B3x elements with B3xR elements - f = open(fileName, "r+") - lines = f.readlines() - f.seek(0) - for line in lines: - if line.find("B32") != -1: - line = line.replace("B32", "B32R") - if line.find("B31") != -1: - line = line.replace("B31", "B31R") - f.write(line) - - f.truncate() - f.close() - -def plane_stress( - fileName -): - # replace shell elements with plane stress elements - f = open(fileName, "r+") - lines = f.readlines() - f.seek(0) - for line in lines: - if line.find("S3") != -1: - line = line.replace("S3", "CPS3") - if line.find("S6") != -1: - line = line.replace("S6", "CPS6") - if line.find("S4") != -1: - line = line.replace("S4", "CPS4") - if line.find("S8") != -1: - line = line.replace("S8", "CPS8") - f.write(line) - - f.truncate() - f.close() -def plane_strain( - fileName -): - # replace shell elements with plane strain elements - f = open(fileName, "r+") - lines = f.readlines() - f.seek(0) - for line in lines: - if line.find("S3") != -1: - line = line.replace("S3", "CPE3") - if line.find("S6") != -1: - line = line.replace("S6", "CPE6") - if line.find("S4") != -1: - line = line.replace("S4", "CPE4") - if line.find("S8") != -1: - line = line.replace("S8", "CPE8") - f.write(line) - - f.truncate() - f.close() -def axisymmetric( - fileName -): - # replace shell elements with axisymmetric elements - f = open(fileName, "r+") - lines = f.readlines() - f.seek(0) - for line in lines: - if line.find("S3") != -1: - line = line.replace("S3", "CAX3") - if line.find("S6") != -1: - line = line.replace("S6", "CAX6") - if line.find("S4") != -1: - line = line.replace("S4", "CAX4") - if line.find("S8") != -1: - line = line.replace("S8", "CAX8") - f.write(line) - - f.truncate() - f.close() - # ************************************************************************************************ def sub_shape_at_global_placement(obj, sub_name): sub_sh = obj.getSubObject(sub_name) diff --git a/src/Mod/Fem/femsolver/calculix/write_mesh.py b/src/Mod/Fem/femsolver/calculix/write_mesh.py index aa17bd4533..4a4b632974 100644 --- a/src/Mod/Fem/femsolver/calculix/write_mesh.py +++ b/src/Mod/Fem/femsolver/calculix/write_mesh.py @@ -36,7 +36,27 @@ def write_mesh(ccxwriter): element_param = 1 # highest element order only group_param = False # do not write mesh group data - if ccxwriter.split_inpfile is True: + + # Use reduced integration beam elements if this option is enabled in ccx solver settings + vol_variant = "standard" + edge_variant = "beam" + if ccxwriter.solver_obj.BeamReducedIntegration: + edge_variant = "beam reduced" + # Check to see if fluid sections are in analysis and use D network element type + if ccxwriter.member.geos_fluidsection: + edge_variant = "network" + + # Use 2D elements if model space is not set to 3D + if ccxwriter.solver_obj.ModelSpace == "3D": + face_variant = "shell" + elif ccxwriter.solver_obj.ModelSpace == "plane stress": + face_variant = "stress" + elif ccxwriter.solver_obj.ModelSpace == "plane strain": + face_variant = "strain" + elif ccxwriter.solver_obj.ModelSpace == "axisymmetric": + face_variant = "axisymmetric" + + if ccxwriter.split_inpfile: write_name = "femesh" file_name_split = ccxwriter.mesh_name + "_" + write_name + ".inp" ccxwriter.femmesh_file = join(ccxwriter.dir_name, file_name_split) @@ -44,25 +64,12 @@ def write_mesh(ccxwriter): ccxwriter.femmesh.writeABAQUS( ccxwriter.femmesh_file, element_param, - group_param + group_param, + volVariant=vol_variant, + faceVariant=face_variant, + edgeVariant=edge_variant ) - # Check to see if fluid sections are in analysis and use D network element type - if ccxwriter.member.geos_fluidsection: - meshtools.write_D_network_element_to_inputfile(ccxwriter.femmesh_file) - - # Use reduced integration beam elements if this option is enabled in ccx solver settings - if ccxwriter.solver_obj.BeamReducedIntegration: - meshtools.beam_reduced_integration(ccxwriter.femmesh_file) - - # Use 2D elements if model space is not set to 3D - if ccxwriter.solver_obj.ModelSpace == "plane stress": - meshtools.plane_stress(ccxwriter.femmesh_file) - if ccxwriter.solver_obj.ModelSpace == "plane strain": - meshtools.plane_strain(ccxwriter.femmesh_file) - if ccxwriter.solver_obj.ModelSpace == "axisymmetric": - meshtools.axisymmetric(ccxwriter.femmesh_file) - inpfile = codecs.open(ccxwriter.file_name, "w", encoding="utf-8") inpfile.write("{}\n".format(59 * "*")) inpfile.write("** {}\n".format(write_name)) @@ -73,26 +80,12 @@ def write_mesh(ccxwriter): ccxwriter.femmesh.writeABAQUS( ccxwriter.femmesh_file, element_param, - group_param + group_param, + volVariant=vol_variant, + faceVariant=face_variant, + edgeVariant=edge_variant ) - # Check to see if fluid sections are in analysis and use D network element type - if ccxwriter.member.geos_fluidsection: - # inpfile is closed - meshtools.write_D_network_element_to_inputfile(ccxwriter.femmesh_file) - - # Use reduced integration beam elements if this option is enabled in ccx solver settings - if ccxwriter.solver_obj.BeamReducedIntegration: - meshtools.beam_reduced_integration(ccxwriter.femmesh_file) - - # Use 2D elements if model space is not set to 3D - if ccxwriter.solver_obj.ModelSpace == "plane stress": - meshtools.plane_stress(ccxwriter.femmesh_file) - if ccxwriter.solver_obj.ModelSpace == "plane strain": - meshtools.plane_strain(ccxwriter.femmesh_file) - if ccxwriter.solver_obj.ModelSpace == "axisymmetric": - meshtools.axisymmetric(ccxwriter.femmesh_file) - # reopen file with "append" to add all the rest inpfile = codecs.open(ccxwriter.femmesh_file, "a", encoding="utf-8") inpfile.write("\n\n")