12 #include <unordered_map>
21 #include "GmshVersion.h"
27 static const unsigned GAMBIT_TYPE_HEX = 4;
28 static const unsigned GAMBIT_TYPE_PRI = 5;
29 static const unsigned GAMBIT_TYPE_TET = 6;
30 static const unsigned GAMBIT_TYPE_PYR = 7;
34 template <
typename Key,
typename Value>
struct hashMap {
35 typedef std::unordered_map<Key, Value> _;
38 const hashMap<std::string, unsigned>::_::value_type rawData[] = {
39 hashMap<std::string, unsigned>::_::value_type(
"UNSPECIFIED", 0),
40 hashMap<std::string, unsigned>::_::value_type(
"AXIS", 1),
41 hashMap<std::string, unsigned>::_::value_type(
"CONJUGATE", 2),
42 hashMap<std::string, unsigned>::_::value_type(
"CONVECTION", 3),
43 hashMap<std::string, unsigned>::_::value_type(
"CYCLIC", 4),
44 hashMap<std::string, unsigned>::_::value_type(
"DEAD", 5),
45 hashMap<std::string, unsigned>::_::value_type(
"ELEMENT_SID", 6),
46 hashMap<std::string, unsigned>::_::value_type(
"ESPECIES", 7),
47 hashMap<std::string, unsigned>::_::value_type(
"EXHAUST_FAN", 8),
48 hashMap<std::string, unsigned>::_::value_type(
"FAN", 9),
49 hashMap<std::string, unsigned>::_::value_type(
"FREE_SURFACE", 10),
50 hashMap<std::string, unsigned>::_::value_type(
"GAP", 11),
51 hashMap<std::string, unsigned>::_::value_type(
"INFLOW", 12),
52 hashMap<std::string, unsigned>::_::value_type(
"INLET", 13),
53 hashMap<std::string, unsigned>::_::value_type(
"INLET_VENT", 14),
54 hashMap<std::string, unsigned>::_::value_type(
"INTAKE_FAN", 15),
55 hashMap<std::string, unsigned>::_::value_type(
"INTERFACE", 16),
56 hashMap<std::string, unsigned>::_::value_type(
"INTERIOR", 17),
57 hashMap<std::string, unsigned>::_::value_type(
"INTERNAL", 18),
58 hashMap<std::string, unsigned>::_::value_type(
"LIVE", 19),
59 hashMap<std::string, unsigned>::_::value_type(
"MASS_FLOW_INLET", 20),
60 hashMap<std::string, unsigned>::_::value_type(
"MELT", 21),
61 hashMap<std::string, unsigned>::_::value_type(
"MELT_INTERFACE", 22),
62 hashMap<std::string, unsigned>::_::value_type(
"MOVING_BOUNDARY", 23),
63 hashMap<std::string, unsigned>::_::value_type(
"NODE", 24),
64 hashMap<std::string, unsigned>::_::value_type(
"OUTFLOW", 25),
65 hashMap<std::string, unsigned>::_::value_type(
"OUTLET", 26),
66 hashMap<std::string, unsigned>::_::value_type(
"OUTLET_VENT", 27),
67 hashMap<std::string, unsigned>::_::value_type(
"PERIODIC", 28),
68 hashMap<std::string, unsigned>::_::value_type(
"PLOT", 29),
69 hashMap<std::string, unsigned>::_::value_type(
"POROUS", 30),
70 hashMap<std::string, unsigned>::_::value_type(
"POROUS_JUMP", 31),
71 hashMap<std::string, unsigned>::_::value_type(
"PRESSURE", 32),
72 hashMap<std::string, unsigned>::_::value_type(
"PRESSURE_FAR_FIELD", 33),
73 hashMap<std::string, unsigned>::_::value_type(
"PRESSURE_INFLOW", 34),
74 hashMap<std::string, unsigned>::_::value_type(
"PRESSURE_INLET", 35),
75 hashMap<std::string, unsigned>::_::value_type(
"PRESSURE_OUTFLOW", 36),
76 hashMap<std::string, unsigned>::_::value_type(
"PRESSURE_OUTLET", 37),
77 hashMap<std::string, unsigned>::_::value_type(
"RADIATION", 38),
78 hashMap<std::string, unsigned>::_::value_type(
"RADIATOR", 39),
79 hashMap<std::string, unsigned>::_::value_type(
"RECIRCULATION_INLET", 40),
80 hashMap<std::string, unsigned>::_::value_type(
"RECIRCULATION_OUTLET", 41),
81 hashMap<std::string, unsigned>::_::value_type(
"SLIP", 42),
82 hashMap<std::string, unsigned>::_::value_type(
"SREACTION", 43),
83 hashMap<std::string, unsigned>::_::value_type(
"SURFACE", 44),
84 hashMap<std::string, unsigned>::_::value_type(
"SYMMETRY", 45),
85 hashMap<std::string, unsigned>::_::value_type(
"TRACTION", 46),
86 hashMap<std::string, unsigned>::_::value_type(
"TRAJECTORY", 47),
87 hashMap<std::string, unsigned>::_::value_type(
"VELOCITY", 48),
88 hashMap<std::string, unsigned>::_::value_type(
"VELOCITY_INLET", 49),
89 hashMap<std::string, unsigned>::_::value_type(
"VENT", 50),
90 hashMap<std::string, unsigned>::_::value_type(
"WALL", 51),
91 hashMap<std::string, unsigned>::_::value_type(
"SPRING", 52),
93 static const hashMap<std::string, unsigned>::_
94 boundaryCodeMap(rawData, rawData + (
sizeof rawData /
sizeof rawData[0]));
97 static const unsigned GAMBIT_FACE_TET_MAP[4] = {1, 2, 4, 3};
98 static const unsigned GAMBIT_FACE_PYR_MAP[5] = {5, 2, 4, 3, 1};
99 static const unsigned GAMBIT_FACE_PRI_MAP[5] = {4, 5, 1, 3, 2};
100 static const unsigned GAMBIT_FACE_HEX_MAP[6] = {5, 1, 4, 2, 3, 6};
102 unsigned const gambitBoundaryCode(std::string name)
104 std::transform(name.begin(), name.end(), name.begin(), ::toupper);
105 auto code = boundaryCodeMap.find(name);
106 return code == boundaryCodeMap.end() ? 0 : code->second;
109 typedef std::pair<unsigned, unsigned> FacePair;
110 typedef hashMap<unsigned, std::vector<FacePair> >::_ IDFaceMap;
112 bool const sortBCs(FacePair
const &lhs, FacePair
const &rhs)
114 return lhs.first < rhs.first;
122 double scalingFactor)
124 FILE *fp =
Fopen(name.c_str(),
"w");
126 Msg::Error(
"Unable to open file '%s'", name.c_str());
131 unsigned numTetrahedra = 0;
132 unsigned numHexahedra = 0;
133 unsigned numPrisms = 0;
134 unsigned numPyramids = 0;
136 unsigned lowestId = std::numeric_limits<int>::max();
137 hashMap<unsigned, std::vector<unsigned> >::_ elementGroups;
140 if(saveAll || (*it)->physicals.size()) {
141 numTetrahedra += (*it)->tetrahedra.size();
142 numHexahedra += (*it)->hexahedra.size();
143 numPrisms += (*it)->prisms.size();
144 numPyramids += (*it)->pyramids.size();
146 for(std::size_t phys = 0; phys < (*it)->physicals.size(); ++phys) {
147 for(std::size_t i = 0; i < (*it)->getNumMeshElements(); ++i) {
149 unsigned n = (unsigned)
elem->getNum();
150 elementGroups[(*it)->physicals[phys]].push_back(n);
151 if(n < lowestId) lowestId = n - 1;
157 if(lowestId == std::numeric_limits<int>::max()) {
162 unsigned numElements = numTetrahedra + numHexahedra + numPrisms + numPyramids;
165 std::vector<unsigned char> vertex_phys(nVertex);
167 hashMap<unsigned, std::vector<unsigned> >::_ vertmap;
169 for(
auto &tri : (*it)->triangles) {
170 for(std::size_t j = 0; j < tri->getNumVertices(); ++j) {
171 unsigned numVertex = tri->getVertex(j)->getNum();
172 vertmap[numVertex].push_back(tri->getNum());
173 vertex_phys[numVertex] = 1;
177 for(
auto &quad : (*it)->quadrangles) {
178 for(std::size_t j = 0; j < quad->getNumVertices(); ++j) {
179 unsigned numVertex = quad->getVertex(j)->getNum();
180 vertmap[numVertex].push_back(quad->getNum());
181 vertex_phys[numVertex] = 1;
188 for(
auto &it : vertmap) { std::sort(it.second.begin(), it.second.end()); }
190 std::vector<unsigned char> elem_phys(numElements);
192 if(saveAll || (*it)->physicals.size()) {
193 for(std::size_t i = 0; i < (*it)->getNumMeshElements(); ++i) {
194 unsigned num = (*it)->getMeshElement(i)->getNum();
196 for(
unsigned j = 0; j < (*it)->getMeshElement(i)->getNumVertices();
198 unsigned vertex = (*it)->getMeshElement(i)->getVertex(j)->getNum();
200 if(vertex_phys[vertex]) { sum++; }
203 if(sum >= 3) { elem_phys[num - lowestId - 1] = 1; }
211 for(std::size_t i = 0; i < (*it)->getNumMeshElements(); ++i) {
213 unsigned num =
element->getNum();
214 if(elem_phys[num - lowestId - 1]) {
215 unsigned numFaces =
element->getNumFaces();
217 for(
unsigned faceNum = 0; faceNum < numFaces; ++faceNum) {
218 std::vector<MVertex *> verts;
219 element->getFaceVertices(faceNum, verts);
221 std::vector<unsigned>
current = vertmap[verts[0]->getNum()];
222 for(std::size_t j = 1; j < verts.size() &&
current.size() != 0; ++j) {
223 std::vector<unsigned> common_data;
225 vertmap[verts[j]->getNum()].begin(),
226 vertmap[verts[j]->getNum()].end(),
227 std::back_inserter(common_data));
232 unsigned type =
element->getType();
235 case TYPE_TET: face = GAMBIT_FACE_TET_MAP[faceNum];
break;
236 case TYPE_HEX: face = GAMBIT_FACE_HEX_MAP[faceNum];
break;
237 case TYPE_PRI: face = GAMBIT_FACE_PRI_MAP[faceNum];
break;
238 case TYPE_PYR: face = GAMBIT_FACE_PYR_MAP[faceNum];
break;
241 facemap[
current[0]].push_back(FacePair(num, face));
251 IDFaceMap boundaryConditions;
253 if((*it)->physicals.size()) {
254 for(std::size_t i = 0; i < (*it)->physicals.size(); ++i) {
255 unsigned phys = (*it)->physicals[i];
257 for(std::size_t j = 0; j < (*it)->triangles.size(); ++j) {
259 auto tets = facemap.find(tri->
getNum());
260 if(tets != facemap.end()) {
261 for(std::size_t tet = 0; tet < tets->second.size(); ++tet) {
262 boundaryConditions[phys].push_back(tets->second[tet]);
267 for(std::size_t j = 0; j < (*it)->quadrangles.size(); ++j) {
269 auto tets = facemap.find(quad->
getNum());
270 if(tets != facemap.end()) {
271 for(std::size_t tet = 0; tet < tets->second.size(); ++tet) {
272 boundaryConditions[phys].push_back(tets->second[tet]);
281 fprintf(fp,
" CONTROL INFO 2.0.0\n");
282 fprintf(fp,
"** GAMBIT NEUTRAL FILE\n");
283 fprintf(fp,
"Gmsh mesh in GAMBIT neutral file format\n");
284 fprintf(fp,
"PROGRAM: Gmsh VERSION: %s\n", GMSH_VERSION);
288 fprintf(fp,
"%s", ctime(&rawtime));
290 fprintf(fp,
" NUMNP NELEM NGRPS NBSETS NDFCD NDFVL\n");
292 fprintf(fp,
" %9ld %9d %9lu %9lu %9d %9d\n",
294 elementGroups.size(), boundaryConditions.size(),
getDim(),
getDim());
296 fprintf(fp,
"ENDOFSECTION\n");
299 fprintf(fp,
" NODAL COORDINATES 2.0.0\n");
300 std::vector<GEntity *> entities;
302 for(std::size_t i = 0; i < entities.size(); ++i) {
303 for(std::size_t j = 0; j < entities[i]->mesh_vertices.size(); ++j) {
304 entities[i]->mesh_vertices[j]->writeNEU(fp,
getDim(), scalingFactor);
307 fprintf(fp,
"ENDOFSECTION\n");
310 fprintf(fp,
" ELEMENTS/CELLS 2.0.0\n");
312 std::size_t numPhys = (*it)->physicals.size();
313 if(saveAll || numPhys) {
314 for(
auto cell : (*it)->tetrahedra) {
315 cell->writeNEU(fp, GAMBIT_TYPE_TET, lowestId,
316 numPhys ? (*it)->physicals[0] : 0);
318 for(
auto cell : (*it)->hexahedra) {
319 cell->writeNEU(fp, GAMBIT_TYPE_HEX, lowestId,
320 numPhys ? (*it)->physicals[0] : 0);
322 for(
auto cell : (*it)->prisms) {
323 cell->writeNEU(fp, GAMBIT_TYPE_PRI, lowestId,
324 numPhys ? (*it)->physicals[0] : 0);
326 for(
auto cell : (*it)->pyramids) {
327 cell->writeNEU(fp, GAMBIT_TYPE_PYR, lowestId,
328 numPhys ? (*it)->physicals[0] : 0);
332 fprintf(fp,
"ENDOFSECTION\n");
336 for(
auto it = elementGroups.begin(); it != elementGroups.end(); ++it) {
337 fprintf(fp,
" ELEMENT GROUP 2.0.0\n");
339 "GROUP: %10d ELEMENTS: %10lu MATERIAL: 0 NFLAGS: %10d\n",
340 it->first, it->second.size(), 1);
343 if(volumeName.empty()) {
345 sprintf(tmp,
"Material group %d", it->first);
348 fprintf(fp,
"%32s\n", volumeName.c_str());
352 for(
unsigned i = 0; i < it->second.size(); ++i) {
353 if(i % 10 == 0) { fprintf(fp,
"\n"); }
354 fprintf(fp,
"%8d", it->second[i] - lowestId);
357 fprintf(fp,
"ENDOFSECTION\n");
363 for(
unsigned iphys = 1; iphys <= nphys; ++iphys) {
364 for(
auto it = boundaryConditions.begin(); it != boundaryConditions.end();
366 if(it->first == iphys) {
367 fprintf(fp,
" BOUNDARY CONDITIONS 2.0.0\n");
369 if(regionName.empty()) {
371 sprintf(tmp,
"PhysicalSurface%d", it->first);
375 fprintf(fp,
"%32s%8d%8lu%8d%8d\n", regionName.c_str(), 1,
376 it->second.size(), 0, gambitBoundaryCode(regionName));
377 std::sort(it->second.begin(), it->second.end(), sortBCs);
378 for(
auto tfp = it->second.begin(); tfp != it->second.end(); ++tfp) {
380 unsigned type =
element->getType();
381 unsigned gambit_type = 0;
383 case TYPE_TET: gambit_type = GAMBIT_TYPE_TET;
break;
384 case TYPE_PYR: gambit_type = GAMBIT_TYPE_PYR;
break;
385 case TYPE_PRI: gambit_type = GAMBIT_TYPE_PRI;
break;
386 case TYPE_HEX: gambit_type = GAMBIT_TYPE_HEX;
break;
390 fprintf(fp,
"%10d %5d %5d\n", tfp->first - lowestId, gambit_type,
396 fprintf(fp,
"ENDOFSECTION\n");