Skip to content

Commit 9f1d265

Browse files
committed
Fem: Add element types to ABAQUS writer
1 parent 88b0ec5 commit 9f1d265

File tree

4 files changed

+353
-117
lines changed

4 files changed

+353
-117
lines changed

src/Mod/Fem/App/FemMesh.cpp

+217-111
Original file line numberDiff line numberDiff line change
@@ -1929,7 +1929,12 @@ void FemMesh::read(const char* FileName)
19291929
}
19301930
}
19311931

1932-
void FemMesh::writeABAQUS(const std::string& Filename, int elemParam, bool groupParam) const
1932+
void FemMesh::writeABAQUS(const std::string& Filename,
1933+
int elemParam,
1934+
bool groupParam,
1935+
ABAQUS_VolumeVariant volVariant,
1936+
ABAQUS_FaceVariant faceVariant,
1937+
ABAQUS_EdgeVariant edgeVariant) const
19331938
{
19341939
/*
19351940
* elemParam:
@@ -1940,121 +1945,222 @@ void FemMesh::writeABAQUS(const std::string& Filename, int elemParam, bool group
19401945
* groupParam:
19411946
* true = write group data
19421947
* false = do not write group data
1948+
1949+
* volVariant, faceVariant, edgeVariant:
1950+
* Element type according to availability in CalculiX
19431951
*/
19441952

1945-
static std::map<std::string, std::vector<int>> elemOrderMap;
1946-
static std::map<int, std::string> edgeTypeMap;
1947-
static std::map<int, std::string> faceTypeMap;
1948-
static std::map<int, std::string> volTypeMap;
1949-
if (elemOrderMap.empty()) {
1950-
// node order fits with node order in importCcxFrdResults.py module to import
1951-
// CalculiX result meshes
1952-
1953-
// dimension 1
1954-
//
1955-
// seg2 FreeCAD --> CalculiX B31
1956-
// N1, N2
1957-
std::vector<int> b31 = boost::assign::list_of(0)(1);
1958-
//
1959-
// seg3 FreeCAD --> CalculiX B32
1960-
// N1, N3, N2
1961-
std::vector<int> b32 = boost::assign::list_of(0)(2)(1);
1962-
1963-
elemOrderMap.insert(std::make_pair("B31", b31));
1964-
edgeTypeMap.insert(std::make_pair(elemOrderMap["B31"].size(), "B31"));
1965-
elemOrderMap.insert(std::make_pair("B32", b32));
1966-
edgeTypeMap.insert(std::make_pair(elemOrderMap["B32"].size(), "B32"));
1967-
1968-
// dimension 2
1969-
//
1970-
// tria3 FreeCAD --> S3 CalculiX
1971-
// N1, N2, N3
1972-
std::vector<int> s3 = boost::assign::list_of(0)(1)(2);
1973-
//
1974-
// tria6 FreeCAD --> S6 CalculiX
1975-
// N1, N2, N3, N4, N5, N6
1976-
std::vector<int> s6 = boost::assign::list_of(0)(1)(2)(3)(4)(5);
1977-
//
1978-
// quad4 FreeCAD --> S4 CalculiX
1979-
// N1, N2, N3, N4
1980-
std::vector<int> s4 = boost::assign::list_of(0)(1)(2)(3);
1981-
//
1982-
// quad8 FreeCAD --> S8 CalculiX
1983-
// N1, N2, N3, N4, N5, N6, N7, N8
1984-
std::vector<int> s8 = boost::assign::list_of(0)(1)(2)(3)(4)(5)(6)(7);
1985-
1986-
elemOrderMap.insert(std::make_pair("S3", s3));
1987-
faceTypeMap.insert(std::make_pair(elemOrderMap["S3"].size(), "S3"));
1988-
elemOrderMap.insert(std::make_pair("S6", s6));
1989-
faceTypeMap.insert(std::make_pair(elemOrderMap["S6"].size(), "S6"));
1990-
elemOrderMap.insert(std::make_pair("S4", s4));
1991-
faceTypeMap.insert(std::make_pair(elemOrderMap["S4"].size(), "S4"));
1992-
elemOrderMap.insert(std::make_pair("S8", s8));
1993-
faceTypeMap.insert(std::make_pair(elemOrderMap["S8"].size(), "S8"));
1994-
1995-
// dimension 3
1996-
//
1997-
// tetras
1998-
// master 0.14 release
1999-
// changed to this in August 2013, committed by juergen (jriedel)
2000-
// https://github.com/FreeCAD/FreeCAD/commit/af56b324b9566b20f3b6e7880c29354c1dbe7a99
2001-
// std::vector<int> c3d4 = boost::assign::list_of(0)(3)(1)(2);
2002-
// std::vector<int> c3d10 = boost::assign::list_of(0)(2)(1)(3)(6)(5)(4)(7)(9)(8);
2003-
2004-
// since master 0.15
2005-
// added by werner (wmayer) March 2015,
2006-
// https://forum.freecad.org/viewtopic.php?f=18&t=10110&start=10#p81681
2007-
// https://github.com/FreeCAD/FreeCAD/commit/5d159f5cf352a93b1aff4fb7b82e8b747ee4f35b
2008-
// https://github.com/FreeCAD/FreeCAD/commit/b007bd19e4e4608caa4cdad350a9f480287fac6b
2009-
// tetra4 FreeCAD --> C3D4 CalculiX
2010-
// N2, N1, N3, N4
2011-
std::vector<int> c3d4 = boost::assign::list_of(1)(0)(2)(3);
2012-
// tetra10: FreeCAD --> C3D10 CalculiX
2013-
// N2, N1, N3, N4, N5, N7, N6, N9, N8, N10
2014-
std::vector<int> c3d10 = boost::assign::list_of(1)(0)(2)(3)(4)(6)(5)(8)(7)(9);
1953+
std::map<std::string, std::string> variants;
1954+
1955+
// volume elements
1956+
variants["Tetra4"] = "C3D4";
1957+
variants["Penta6"] = "C3D6";
1958+
variants["Hexa8"] = "C3D8";
1959+
variants["Tetra10"] = "C3D10";
1960+
variants["Penta15"] = "C3D15";
1961+
variants["Hexa20"] = "C3D20";
1962+
1963+
switch (volVariant) {
1964+
case ABAQUS_VolumeVariant::Standard:
1965+
break;
1966+
case ABAQUS_VolumeVariant::Reduced:
1967+
variants["Hexa8"] = "C3D8R";
1968+
variants["Hexa20"] = "C3D20R";
1969+
break;
1970+
case ABAQUS_VolumeVariant::Incompatible:
1971+
variants["Hexa8"] = "C3D8I";
1972+
break;
1973+
case ABAQUS_VolumeVariant::Modified:
1974+
variants["Tetra10"] = "C3D10T";
1975+
break;
1976+
case ABAQUS_VolumeVariant::Fluid:
1977+
variants["Tetra4"] = "F3D4";
1978+
variants["Penta6"] = "F3D6";
1979+
variants["Hexa8"] = "F3D8";
1980+
break;
1981+
}
20151982

2016-
// tetra node order for the system which is used for hexa8, hexa20, penta6 and penda15
2017-
// be careful with activating because of method getccxVolumesByFace())
2018-
// tetra4 FreeCAD --> C3D4 CalculiX
2019-
// N2, N3, N4, N1
2020-
// std::vector<int> c3d4 = boost::assign::list_of(1)(2)(3)(0);
2021-
//
2022-
// tetra10: FreeCAD --> C3D10 CalculiX
2023-
// N2, N3, N4, N1, N6, N10, N9, N5, N7, N8
2024-
// std::vector<int> c3d10 = boost::assign::list_of(1)(2)(3)(0)(5)(9)(8)(4)(6)(7);
2025-
2026-
// hexa8 FreeCAD --> C3D8 CalculiX
2027-
// N6, N7, N8, N5, N2, N3, N4, N1
2028-
std::vector<int> c3d8 = boost::assign::list_of(5)(6)(7)(4)(1)(2)(3)(0);
2029-
//
2030-
// hexa20 FreeCAD --> C3D20 CalculiX
2031-
// N6, N7, N8, N5, N2, N3, N4, N1, N14, N15, N16, N13, N10, N11, N12, N9, N18, N19, N20, N17
2032-
std::vector<int> c3d20 = boost::assign::list_of(5)(6)(7)(4)(1)(2)(3)(0)(13)(14)(15)(12)(9)(
2033-
10)(11)(8)(17)(18)(19)(16);
2034-
//
2035-
// penta6 FreeCAD --> C3D6 CalculiX
2036-
// N5, N6, N4, N2, N3, N1
2037-
std::vector<int> c3d6 = boost::assign::list_of(4)(5)(3)(1)(2)(0);
2038-
//
2039-
// penta15 FreeCAD --> C3D15 CalculiX
2040-
// N5, N6, N4, N2, N3, N1, N11, N12, N10, N8, N9, N7, N14, N15, N13
2041-
std::vector<int> c3d15 =
2042-
boost::assign::list_of(4)(5)(3)(1)(2)(0)(10)(11)(9)(7)(8)(6)(13)(14)(12);
2043-
2044-
elemOrderMap.insert(std::make_pair("C3D4", c3d4));
2045-
volTypeMap.insert(std::make_pair(elemOrderMap["C3D4"].size(), "C3D4"));
2046-
elemOrderMap.insert(std::make_pair("C3D10", c3d10));
2047-
volTypeMap.insert(std::make_pair(elemOrderMap["C3D10"].size(), "C3D10"));
2048-
elemOrderMap.insert(std::make_pair("C3D8", c3d8));
2049-
volTypeMap.insert(std::make_pair(elemOrderMap["C3D8"].size(), "C3D8"));
2050-
elemOrderMap.insert(std::make_pair("C3D20", c3d20));
2051-
volTypeMap.insert(std::make_pair(elemOrderMap["C3D20"].size(), "C3D20"));
2052-
elemOrderMap.insert(std::make_pair("C3D6", c3d6));
2053-
volTypeMap.insert(std::make_pair(elemOrderMap["C3D6"].size(), "C3D6"));
2054-
elemOrderMap.insert(std::make_pair("C3D15", c3d15));
2055-
volTypeMap.insert(std::make_pair(elemOrderMap["C3D15"].size(), "C3D15"));
1983+
// face elements
1984+
switch (faceVariant) {
1985+
case ABAQUS_FaceVariant::Shell:
1986+
variants["Tria3"] = "S3";
1987+
variants["Quad4"] = "S4";
1988+
variants["Tria6"] = "S6";
1989+
variants["Quad8"] = "S8";
1990+
break;
1991+
case ABAQUS_FaceVariant::Shell_Reduced:
1992+
variants["Tria3"] = "S3";
1993+
variants["Quad4"] = "S4R";
1994+
variants["Tria6"] = "S6";
1995+
variants["Quad8"] = "S8R";
1996+
break;
1997+
case ABAQUS_FaceVariant::Membrane:
1998+
variants["Tria3"] = "M3D3";
1999+
variants["Quad4"] = "M3D4";
2000+
variants["Tria6"] = "M3D6";
2001+
variants["Quad8"] = "M3D8";
2002+
break;
2003+
case ABAQUS_FaceVariant::Membrane_Reduced:
2004+
variants["Tria3"] = "M3D3";
2005+
variants["Quad4"] = "M3D4R";
2006+
variants["Tria6"] = "M3D6";
2007+
variants["Quad8"] = "M3D8R";
2008+
break;
2009+
case ABAQUS_FaceVariant::Stress:
2010+
variants["Tria3"] = "CPS3";
2011+
variants["Quad4"] = "CPS4";
2012+
variants["Tria6"] = "CPS6";
2013+
variants["Quad8"] = "CPS8";
2014+
break;
2015+
case ABAQUS_FaceVariant::Stress_Reduced:
2016+
variants["Tria3"] = "CPS3";
2017+
variants["Quad4"] = "CPS4R";
2018+
variants["Tria6"] = "CPS6";
2019+
variants["Quad8"] = "CPS8R";
2020+
break;
2021+
case ABAQUS_FaceVariant::Strain:
2022+
variants["Tria3"] = "CPE3";
2023+
variants["Quad4"] = "CPE4";
2024+
variants["Tria6"] = "CPE6";
2025+
variants["Quad8"] = "CPE8";
2026+
break;
2027+
case ABAQUS_FaceVariant::Strain_Reduced:
2028+
variants["Tria3"] = "CPE3";
2029+
variants["Quad4"] = "CPE4R";
2030+
variants["Tria6"] = "CPE6";
2031+
variants["Quad8"] = "CPE8R";
2032+
break;
2033+
case ABAQUS_FaceVariant::Axisymmetric:
2034+
variants["Tria3"] = "CAX3";
2035+
variants["Quad4"] = "CAX4";
2036+
variants["Tria6"] = "CAX6";
2037+
variants["Quad8"] = "CAX8";
2038+
break;
2039+
case ABAQUS_FaceVariant::Axisymmetric_Reduced:
2040+
variants["Tria3"] = "CAX3";
2041+
variants["Quad4"] = "CAX4R";
2042+
variants["Tria6"] = "CAX6";
2043+
variants["Quad8"] = "CAX8R";
2044+
break;
20562045
}
20572046

2047+
// edge elements
2048+
switch (edgeVariant) {
2049+
case ABAQUS_EdgeVariant::Beam:
2050+
variants["Seg2"] = "B31";
2051+
variants["Seg3"] = "B32";
2052+
break;
2053+
case ABAQUS_EdgeVariant::Beam_Reduced:
2054+
variants["Seg2"] = "B31R";
2055+
variants["Seg3"] = "B32R";
2056+
break;
2057+
case ABAQUS_EdgeVariant::Truss:
2058+
variants["Seg2"] = "T3D2";
2059+
variants["Seg3"] = "T3D3";
2060+
break;
2061+
case ABAQUS_EdgeVariant::Network:
2062+
variants["Seg2"] = "B31";
2063+
variants["Seg3"] = "D";
2064+
break;
2065+
}
2066+
2067+
std::map<std::string, std::vector<int>> elemOrderMap;
2068+
std::map<int, std::string> edgeTypeMap;
2069+
std::map<int, std::string> faceTypeMap;
2070+
std::map<int, std::string> volTypeMap;
2071+
2072+
2073+
// node order fits with node order in importCcxFrdResults.py module to import
2074+
// CalculiX result meshes
2075+
2076+
// dimension 1
2077+
//
2078+
// seg2 FreeCAD --> B31, B31R, T3D2 CalculiX
2079+
// N1, N2
2080+
std::vector<int> seg2 = boost::assign::list_of(0)(1);
2081+
//
2082+
// seg3 FreeCAD --> B32, B32R, T3D3 D CalculiX
2083+
// N1, N3, N2
2084+
std::vector<int> seg3 = boost::assign::list_of(0)(2)(1);
2085+
2086+
elemOrderMap.insert(std::make_pair(variants["Seg2"], seg2));
2087+
edgeTypeMap.insert(std::make_pair(elemOrderMap[variants["Seg2"]].size(), variants["Seg2"]));
2088+
elemOrderMap.insert(std::make_pair(variants["Seg3"], seg3));
2089+
edgeTypeMap.insert(std::make_pair(elemOrderMap[variants["Seg3"]].size(), variants["Seg3"]));
2090+
2091+
// dimension 2
2092+
//
2093+
// tria3 FreeCAD --> S3, M3D3, CPS3, CPE3, CAX3 CalculiX
2094+
// N1, N2, N3
2095+
std::vector<int> tria3 = boost::assign::list_of(0)(1)(2);
2096+
//
2097+
// tria6 FreeCAD --> S6 M3D6, CPS6, CPE6, CAX6 CalculiX
2098+
// N1, N2, N3, N4, N5, N6
2099+
std::vector<int> tria6 = boost::assign::list_of(0)(1)(2)(3)(4)(5);
2100+
//
2101+
// quad4 FreeCAD --> S4, S4R, M3D4, M3D4R, CPS4, CPS4R, CPE4, CPE4R, CAX4, CAX4R CalculiX
2102+
// N1, N2, N3, N4
2103+
std::vector<int> quad4 = boost::assign::list_of(0)(1)(2)(3);
2104+
//
2105+
// quad8 FreeCAD --> S8, S8R, M3D8, M3D8R, CPS8, CPS8R, CPE8, CPE8R, CAX8, CAX8R CalculiX
2106+
// N1, N2, N3, N4, N5, N6, N7, N8
2107+
std::vector<int> quad8 = boost::assign::list_of(0)(1)(2)(3)(4)(5)(6)(7);
2108+
2109+
elemOrderMap.insert(std::make_pair(variants["Tria3"], tria3));
2110+
faceTypeMap.insert(std::make_pair(elemOrderMap[variants["Tria3"]].size(), variants["Tria3"]));
2111+
elemOrderMap.insert(std::make_pair(variants["Tria6"], tria6));
2112+
faceTypeMap.insert(std::make_pair(elemOrderMap[variants["Tria6"]].size(), variants["Tria6"]));
2113+
elemOrderMap.insert(std::make_pair(variants["Quad4"], quad4));
2114+
faceTypeMap.insert(std::make_pair(elemOrderMap[variants["Quad4"]].size(), variants["Quad4"]));
2115+
elemOrderMap.insert(std::make_pair(variants["Quad8"], quad8));
2116+
faceTypeMap.insert(std::make_pair(elemOrderMap[variants["Quad8"]].size(), variants["Quad8"]));
2117+
2118+
2119+
// dimension 3
2120+
//
2121+
// tetra4 FreeCAD --> C3D4, F3D4 CalculiX
2122+
// N2, N1, N3, N4
2123+
std::vector<int> tetra4 = boost::assign::list_of(1)(0)(2)(3);
2124+
// tetra10: FreeCAD --> C3D10, C3D10T CalculiX
2125+
// N2, N1, N3, N4, N5, N7, N6, N9, N8, N10
2126+
std::vector<int> tetra10 = boost::assign::list_of(1)(0)(2)(3)(4)(6)(5)(8)(7)(9);
2127+
2128+
// tetra node order for the system which is used for hexa8, hexa20, penta6 and penta15
2129+
// be careful with activating because of method getccxVolumesByFace())
2130+
// hexa8 FreeCAD --> C3D8, C3D8R, C3D8I, F3D8 CalculiX
2131+
// N6, N7, N8, N5, N2, N3, N4, N1
2132+
std::vector<int> hexa8 = boost::assign::list_of(5)(6)(7)(4)(1)(2)(3)(0);
2133+
//
2134+
// hexa20 FreeCAD --> C3D20, C3D20R CalculiX
2135+
// N6, N7, N8, N5, N2, N3, N4, N1, N14, N15, N16, N13, N10, N11, N12, N9, N18, N19, N20, N17
2136+
std::vector<int> hexa20 = boost::assign::list_of(5)(6)(7)(4)(1)(2)(3)(0)(13)(14)(15)(12)(9)(10)(
2137+
11)(8)(17)(18)(19)(16);
2138+
//
2139+
// penta6 FreeCAD --> C3D6, F3D6 CalculiX
2140+
// N5, N6, N4, N2, N3, N1
2141+
std::vector<int> penta6 = boost::assign::list_of(4)(5)(3)(1)(2)(0);
2142+
//
2143+
// penta15 FreeCAD --> C3D15 CalculiX
2144+
// N5, N6, N4, N2, N3, N1, N11, N12, N10, N8, N9, N7, N14, N15, N13
2145+
std::vector<int> penta15 =
2146+
boost::assign::list_of(4)(5)(3)(1)(2)(0)(10)(11)(9)(7)(8)(6)(13)(14)(12);
2147+
2148+
elemOrderMap.insert(std::make_pair(variants["Tetra4"], tetra4));
2149+
volTypeMap.insert(std::make_pair(elemOrderMap[variants["Tetra4"]].size(), variants["Tetra4"]));
2150+
elemOrderMap.insert(std::make_pair(variants["Tetra10"], tetra10));
2151+
volTypeMap.insert(
2152+
std::make_pair(elemOrderMap[variants["Tetra10"]].size(), variants["Tetra10"]));
2153+
elemOrderMap.insert(std::make_pair(variants["Hexa8"], hexa8));
2154+
volTypeMap.insert(std::make_pair(elemOrderMap[variants["Hexa8"]].size(), variants["Hexa8"]));
2155+
elemOrderMap.insert(std::make_pair(variants["Hexa20"], hexa20));
2156+
volTypeMap.insert(std::make_pair(elemOrderMap[variants["Hexa20"]].size(), variants["Hexa20"]));
2157+
elemOrderMap.insert(std::make_pair(variants["Penta6"], penta6));
2158+
volTypeMap.insert(std::make_pair(elemOrderMap[variants["Penta6"]].size(), variants["Penta6"]));
2159+
elemOrderMap.insert(std::make_pair(variants["Penta15"], penta15));
2160+
volTypeMap.insert(
2161+
std::make_pair(elemOrderMap[variants["Penta15"]].size(), variants["Penta15"]));
2162+
2163+
20582164
// get all data --> Extract Nodes and Elements of the current SMESH datastructure
20592165
using VertexMap = std::map<int, Base::Vector3d>;
20602166
using NodesMap = std::map<int, std::vector<int>>;

src/Mod/Fem/App/FemMesh.h

+35-1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,35 @@ class TopoDS_Solid;
4747
namespace Fem
4848
{
4949

50+
enum class ABAQUS_VolumeVariant
51+
{
52+
Standard,
53+
Reduced,
54+
Incompatible,
55+
Modified,
56+
Fluid
57+
};
58+
enum class ABAQUS_FaceVariant
59+
{
60+
Shell,
61+
Shell_Reduced,
62+
Membrane,
63+
Membrane_Reduced,
64+
Stress,
65+
Stress_Reduced,
66+
Strain,
67+
Strain_Reduced,
68+
Axisymmetric,
69+
Axisymmetric_Reduced
70+
};
71+
enum class ABAQUS_EdgeVariant
72+
{
73+
Beam,
74+
Beam_Reduced,
75+
Truss,
76+
Network
77+
};
78+
5079
using SMESH_HypothesisPtr = std::shared_ptr<SMESH_Hypothesis>;
5180

5281
/** The representation of a FemMesh
@@ -172,7 +201,12 @@ class FemExport FemMesh: public Data::ComplexGeoData
172201
/// import from files
173202
void read(const char* FileName);
174203
void write(const char* FileName) const;
175-
void writeABAQUS(const std::string& Filename, int elemParam, bool groupParam) const;
204+
void writeABAQUS(const std::string& Filename,
205+
int elemParam,
206+
bool groupParam,
207+
ABAQUS_VolumeVariant volVariant = ABAQUS_VolumeVariant::Standard,
208+
ABAQUS_FaceVariant faceVariant = ABAQUS_FaceVariant::Shell,
209+
ABAQUS_EdgeVariant edgeVariant = ABAQUS_EdgeVariant::Beam) const;
176210
void writeZ88(const std::string& FileName) const;
177211

178212
private:

0 commit comments

Comments
 (0)