26 #if defined(HAVE_LIBCGNS)
31 typedef std::pair<unsigned int, unsigned int> PartitionInterface;
32 typedef std::pair<std::vector<cgsize_t>, std::vector<cgsize_t> >
35 static const char INTERPOLATION_ZONE_NAME[] =
"ElementHighOrderNodes";
39 template <
bool INCLUDE_HO_NODES>
40 void getNodesInEntities(
const std::vector<GEntity *> &entities,
41 bool allElements, std::set<MVertex *> &nodeSet)
43 for(std::size_t i = 0; i < entities.size(); i++) {
45 std::vector<int> eleTypes;
47 for(std::size_t eleType = 0; eleType < eleTypes.size(); eleType++) {
49 if(numEle && (allElements || ge->
physicals.size())) {
50 for(
int j = 0; j < numEle; j++) {
54 for(
int k = 0; k < numEltVert; k++) {
63 std::string entTypeShortStr(
int dim)
66 case 0:
return "P";
break;
67 case 1:
return "L";
break;
68 case 2:
return "S";
break;
69 case 3:
return "V";
break;
75 void getNameFromEntity(
GEntity *ge, std::string &entityName)
78 const std::string entTypeStr = entTypeShortStr(ge->
dim());
87 std::ostringstream ossEnt;
89 if(geParent !=
nullptr) ossEnt <<
"_" << geParent->
tag();
90 ossEnt <<
"_" << ge->
tag();
92 if(!entityName.empty()) ossEnt <<
"_" << entityName;
93 entityName = ossEnt.str();
94 entityName = cgnsString(entityName);
101 std::vector<GEntity *> &entities)
104 entities.reserve(allEntities.size());
105 for(std::size_t i = 0; i < allEntities.size(); i++) {
108 if(saveAll || (ge->
physicals.size() > 0)) entities.push_back(ge);
113 void getPeriodicEntities(
const std::vector<GEntity *> &allEntities,
114 std::vector<GEntity *> &entitiesPer)
117 for(std::size_t i = 0; i < allEntities.size(); i++) {
118 GEntity *slaveEnt = allEntities[i];
120 if(slaveEnt != masterEnt) entitiesPer.push_back(slaveEnt);
125 void getPartitionInterfaceEntities(
const std::vector<GEntity *> &entities,
127 std::vector<GEntity *> &entitiesInt)
129 for(std::size_t j = 0; j < entities.size(); j++) {
135 if((pge->
dim() != pr->
dim()) && (saveAll || (pge->
physicals.size() > 0)))
136 entitiesInt.push_back(ge);
142 if((pge->
dim() != pf->
dim()) && (saveAll || (pge->
physicals.size() > 0)))
143 entitiesInt.push_back(ge);
148 if((pge->
dim() != pe->
dim()) && (saveAll || (pge->
physicals.size() > 0)))
149 entitiesInt.push_back(ge);
154 if((pge->
dim() != pv->
dim()) && (saveAll || (pge->
physicals.size() > 0)))
155 entitiesInt.push_back(ge);
163 void initInterfVertex2LocalData(
const std::vector<GEntity *> &entitiesPer,
164 const std::vector<GEntity *> &entitiesInterf,
165 Vertex2LocalData &interfVert2Local)
168 for(std::size_t i = 0; i < entitiesPer.size(); i++) {
170 for(
auto itV = vv.begin(); itV != vv.end(); itV++) {
171 interfVert2Local[itV->first] = std::vector<LocalData>();
172 interfVert2Local[itV->second] = std::vector<LocalData>();
177 std::set<MVertex *> nodeSet;
178 getNodesInEntities<false>(entitiesInterf,
true, nodeSet);
179 for(
auto itN = nodeSet.begin(); itN != nodeSet.end(); ++itN) {
180 interfVert2Local[*itN] = std::vector<LocalData>();
186 int writeZone(
GModel *model,
bool saveAll,
double scalingFactor,
int meshDim,
187 std::size_t numNodesTotal, std::size_t partition,
188 const std::vector<GEntity *> &entities,
int cgIndexFile,
189 int cgIndexBase, std::vector<std::string> &zoneName,
190 Vertex2LocalData &interfVert2Local, std::set<int> &eleMshTypes,
191 std::map<GEntity *, std::string> &geomEntities)
193 #ifdef HAVE_LIBCGNS_CPEX0045
196 static const bool useCPEX0045 =
false;
201 std::set<MVertex *> nodeSet;
202 getNodesInEntities<true>(entities, saveAll, nodeSet);
206 std::vector<LocalData> global2Local(numNodesTotal + 1);
207 cgsize_t numNodes = 0;
208 for(
auto itN = nodeSet.begin(); itN != nodeSet.end(); ++itN) {
209 const long gInd = (*itN)->getIndex();
210 if(gInd < 0)
continue;
212 LocalData &ld = global2Local[gInd];
213 ld.partition = partition;
215 auto itPN = interfVert2Local.find(*itN);
216 if(itPN != interfVert2Local.end()) itPN->second.push_back(ld);
220 std::vector<double> xcoord(numNodes), ycoord(numNodes), zcoord(numNodes);
221 for(
auto itN = nodeSet.begin(); itN != nodeSet.end(); ++itN) {
222 const long gInd = (*itN)->getIndex();
223 if(gInd < 0)
continue;
224 const int ln = global2Local[gInd].index;
225 xcoord[ln - 1] = (*itN)->x() * scalingFactor;
226 ycoord[ln - 1] = (*itN)->y() * scalingFactor;
227 zcoord[ln - 1] = (*itN)->z() * scalingFactor;
231 cgsize_t numElementsMaxDim = 0;
232 for(std::size_t i = 0; i < entities.size(); i++) {
234 if(ge->
dim() == meshDim && (saveAll || ge->
physicals.size())) {
242 cgsize_t cgZoneSize[3] = {numNodes, numElementsMaxDim, 0};
243 std::ostringstream ossPart;
244 ossPart <<
"_Part" << partition;
245 std::string partSuffix = ossPart.str();
246 std::string modelName = cgnsString(model->
getName(), 32 - partSuffix.size());
247 zoneName[partition] = modelName + partSuffix;
248 cgnsErr = cg_zone_write(cgIndexFile, cgIndexBase, zoneName[partition].c_str(),
249 cgZoneSize, CGNS_ENUMV(Unstructured), &cgIndexZone);
250 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
253 cgnsErr = cg_goto(cgIndexFile, cgIndexBase,
"Zone_t", cgIndexZone,
"end");
254 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
255 cgnsErr = cg_ordinal_write(cgIndexZone);
256 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
258 cgnsErr = cg_famname_write(INTERPOLATION_ZONE_NAME);
259 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
265 cgnsErr = cg_grid_write(cgIndexFile, cgIndexBase, cgIndexZone,
266 "GridCoordinates", &cgIndexGrid);
267 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
270 int cgIndexCoord = 0;
271 cgnsErr = cg_coord_write(cgIndexFile, cgIndexBase, cgIndexZone,
272 CGNS_ENUMV(RealDouble),
"CoordinateX", &xcoord[0],
274 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
275 cgnsErr = cg_coord_write(cgIndexFile, cgIndexBase, cgIndexZone,
276 CGNS_ENUMV(RealDouble),
"CoordinateY", &ycoord[0],
278 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
279 cgnsErr = cg_coord_write(cgIndexFile, cgIndexBase, cgIndexZone,
280 CGNS_ENUMV(RealDouble),
"CoordinateZ", &zcoord[0],
282 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
285 cgsize_t eleStart = 0, eleEnd = 0;
286 for(std::size_t i = 0; i < entities.size(); i++) {
290 if(geGeom ==
nullptr) geGeom = ge;
293 std::string entityName, geomEntityName;
294 getNameFromEntity(ge, entityName);
295 getNameFromEntity(geGeom, geomEntityName);
296 geomEntities[geGeom] = geomEntityName;
299 std::vector<int> eleTypes;
303 cgsize_t eleEntRange[2] = {eleEnd + 1, 0};
306 for(std::size_t eleType = 0; eleType < eleTypes.size(); eleType++) {
308 if((numEle == 0) || ((ge->
physicals.size() == 0) && (!saveAll)))
continue;
309 eleStart = eleEnd + 1;
313 CGNS_ENUMT(ElementType_t) cgType = msh2CgnsEltType(mshType);
314 if(cgType == CGNS_ENUMV(ElementTypeNull)) {
315 Msg::Error(
"Unhandled element type in CGNS ouput (%d)", mshType);
318 if(useCPEX0045) eleMshTypes.insert(mshType);
319 std::vector<int> mshNodeInd = cgns2MshNodeIndex(mshType);
323 std::vector<cgsize_t> elemNodes(numEle * numNodesPerEle);
325 for(
int j = 0; j < numEle; j++) {
327 for(
int k = 0; k < numNodesPerEle; k++) {
328 const int kk = useCPEX0045 ? k : mshNodeInd[k];
330 elemNodes[n] = global2Local[gInd].index;
336 std::ostringstream ossSection;
337 ossSection << eleTypes[eleType] <<
"_" << entityName;
338 int cgIndexSection = 0;
339 cgnsErr = cg_section_write(cgIndexFile, cgIndexBase, cgIndexZone,
340 ossSection.str().c_str(), cgType, eleStart,
341 eleEnd, 0, &elemNodes[0], &cgIndexSection);
342 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
346 eleEntRange[1] = eleEnd;
348 cgnsErr = cg_boco_write(cgIndexFile, cgIndexBase, cgIndexZone,
349 entityName.c_str(), CGNS_ENUMV(FamilySpecified),
350 CGNS_ENUMV(PointRange), 2, eleEntRange, &iZoneBC);
351 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
357 const CGNS_ENUMT(GridLocation_t) loc = CGNS_ENUMV(CellCenter);
358 cgnsErr = cg_boco_gridlocation_write(cgIndexFile, cgIndexBase, cgIndexZone,
360 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
361 cgnsErr = cg_goto(cgIndexFile, cgIndexBase,
"Zone_t", cgIndexZone,
362 "ZoneBC_t", 1,
"BC_t", iZoneBC,
"end");
363 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
364 cgnsErr = cg_famname_write(geomEntityName.c_str());
365 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
372 int writePeriodic(
const std::vector<GEntity *> &entitiesPer,
int cgIndexFile,
373 int cgIndexBase,
const std::vector<std::string> &zoneName,
374 Vertex2LocalData &interfVert2Local)
377 typedef std::pair<GEntity *, GEntity *> EntityInterface;
378 typedef std::pair<PartitionInterface, EntityInterface> PeriodicInterface;
379 typedef std::map<PeriodicInterface, NodeCorrespondence> PeriodicConnection;
383 Msg::Info(
"Constructing connectivities for %i periodic entities",
385 PeriodicConnection connect;
386 for(std::size_t iEnt = 0; iEnt < entitiesPer.size(); iEnt++) {
387 GEntity *slaveEnt = entitiesPer[iEnt];
390 for(
auto itV = vv.begin(); itV != vv.end(); itV++) {
391 const std::vector<LocalData> &allSlaveData = interfVert2Local[itV->first];
392 const std::vector<LocalData> &allMasterData =
393 interfVert2Local[itV->second];
394 for(std::size_t iS = 0; iS < allSlaveData.size(); iS++) {
395 const LocalData &slaveData = allSlaveData[iS];
396 for(std::size_t iM = 0; iM < allMasterData.size(); iM++) {
397 const LocalData &masterData = allMasterData[iM];
398 PartitionInterface partInt =
399 std::make_pair(slaveData.partition, masterData.partition);
400 EntityInterface entInt = std::make_pair(slaveEnt, masterEnt);
401 PeriodicInterface perInt = std::make_pair(partInt, entInt);
402 NodeCorrespondence &nc = connect[perInt];
403 nc.first.push_back(slaveData.index);
404 nc.second.push_back(masterData.index);
405 PartitionInterface partInt2 =
406 std::make_pair(masterData.partition, slaveData.partition);
407 EntityInterface entInt2 = std::make_pair(masterEnt, slaveEnt);
408 PeriodicInterface perInt2 = std::make_pair(partInt2, entInt2);
409 NodeCorrespondence &nc2 = connect[perInt2];
410 nc2.first.push_back(masterData.index);
411 nc2.second.push_back(slaveData.index);
419 for(
auto it = connect.begin(); it != connect.end(); ++it) {
420 printProgress(
"Writing periodic interface",
422 const PeriodicInterface &perInt = it->first;
423 const PartitionInterface &partInt = perInt.first;
424 const EntityInterface &entInt = perInt.second;
425 const std::size_t &part1 = partInt.first;
426 const GEntity *ent1 = entInt.first;
427 const std::size_t &part2 = partInt.second;
428 const GEntity *ent2 = entInt.second;
429 const NodeCorrespondence &nc = it->second;
430 const std::vector<cgsize_t> &nodes1 = nc.first;
431 const std::vector<cgsize_t> &nodes2 = nc.second;
432 int slaveZone = (part1 == 0) ? 1 : part1;
433 const std::string &masterZoneName = zoneName[part2];
434 std::ostringstream ossInt;
435 ossInt <<
"Per_" << part1 <<
"-" << entTypeShortStr(ent1->
dim())
436 << ent1->
tag() <<
"_" << part2 <<
"-" << entTypeShortStr(ent2->
dim())
438 const std::string interfaceName = cgnsString(ossInt.str());
440 cgnsErr = cg_conn_write(
441 cgIndexFile, cgIndexBase, slaveZone, interfaceName.c_str(),
442 CGNS_ENUMV(
Vertex), CGNS_ENUMV(Abutting1to1), CGNS_ENUMV(PointList),
443 nodes1.size(), nodes1.data(), masterZoneName.c_str(),
444 CGNS_ENUMV(Unstructured), CGNS_ENUMV(PointListDonor),
445 CGNS_ENUMV(DataTypeNull), nodes2.size(), nodes2.data(), &connIdx);
446 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
448 float rotCenter[3], rotAngle[3], trans[3];
452 for(
int i = 0; i < 3; i++) {
453 rotAngle[i] = -rotAngle[i];
454 trans[i] = -trans[i];
462 Msg::Error(
"Error in periodic connection between entities %i (dim %i) "
465 for(
int i = 0; i < 3; i++) rotCenter[i] = 0.;
466 for(
int i = 0; i < 3; i++) rotAngle[i] = 0.;
467 for(
int i = 0; i < 3; i++) trans[i] = 0.;
469 cgnsErr = cg_conn_periodic_write(cgIndexFile, cgIndexBase, slaveZone,
470 connIdx, rotCenter, rotAngle, trans);
471 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
478 void getEntitiesInPartitions(
const std::vector<GEntity *> &entities,
479 std::vector<std::vector<GEntity *> > &entitiesPart)
481 for(std::size_t j = 0; j < entities.size(); j++) {
483 const std::vector<int> *parts =
nullptr;
511 if(parts !=
nullptr) {
512 for(std::size_t iPart = 0; iPart < parts->size(); iPart++) {
513 entitiesPart[(*parts)[iPart]].push_back(ge);
520 int writeInterfaces(
const std::vector<GEntity *> &entitiesInterf,
521 int cgIndexFile,
int cgIndexBase,
522 const std::vector<std::string> &zoneName,
523 Vertex2LocalData &interfVert2Local)
526 typedef std::map<PartitionInterface, NodeCorrespondence> PartitionConnection;
529 std::set<MVertex *> nodeSet;
530 getNodesInEntities<false>(entitiesInterf,
true, nodeSet);
533 Msg::Info(
"Constructing connectivities for %i partition interface entities",
534 entitiesInterf.size());
535 PartitionConnection connect;
536 for(
auto itN = nodeSet.begin(); itN != nodeSet.end(); ++itN) {
537 const std::vector<LocalData> &allLocalData = interfVert2Local[*itN];
538 for(std::size_t iLD1 = 0; iLD1 < allLocalData.size(); iLD1++) {
539 const LocalData &localData1 = allLocalData[iLD1];
540 for(std::size_t iLD2 = 0; iLD2 < allLocalData.size(); iLD2++) {
541 if(iLD2 == iLD1)
continue;
542 const LocalData &localData2 = allLocalData[iLD2];
543 std::pair<unsigned int, unsigned int> partInt(localData1.partition,
544 localData2.partition);
545 NodeCorrespondence &nc = connect[partInt];
546 nc.first.push_back(localData1.index);
547 nc.second.push_back(localData2.index);
554 std::size_t iPartConnect = 0;
555 for(
auto it = connect.begin(); it != connect.end(); ++it) {
557 printProgress(
"Writing partition interface", iPartConnect, connect.size());
558 const std::pair<unsigned int, unsigned int> &partInt = it->first;
559 const std::size_t &part1 = partInt.first;
560 const std::size_t &part2 = partInt.second;
561 const NodeCorrespondence &nc = it->second;
562 const std::string &masterZoneName = zoneName[part2];
563 std::ostringstream ossInt;
564 ossInt <<
"Part" << part1 <<
"_Part" << part2;
565 const std::string interfaceName = cgnsString(ossInt.str());
567 cgnsErr = cg_conn_write(
568 cgIndexFile, cgIndexBase, part1, interfaceName.c_str(),
569 CGNS_ENUMV(
Vertex), CGNS_ENUMV(Abutting1to1), CGNS_ENUMV(PointList),
570 nc.first.size(), nc.first.data(), masterZoneName.c_str(),
571 CGNS_ENUMV(Unstructured), CGNS_ENUMV(PointListDonor),
572 CGNS_ENUMV(DataTypeNull), nc.second.size(), nc.second.data(), &dum);
573 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
580 int writeHOPointInfo(
const std::set<int> &eleMshTypes,
int cgIndexFile,
583 #ifdef HAVE_LIBCGNS_CPEX0045
588 cgnsErr = cg_family_write(cgIndexFile, cgIndexBase, INTERPOLATION_ZONE_NAME,
590 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
593 for(
auto it = eleMshTypes.begin(); it != eleMshTypes.end(); ++it) {
595 const int mshType = *it;
598 if(mshType ==
MSH_PNT)
continue;
601 std::size_t nbPts = mshPts.
size1();
602 std::vector<double> u(nbPts), v(nbPts), w(nbPts);
603 msh2CgnsReferenceElement(mshType, mshPts, u, v, w);
606 CGNS_ENUMT(ElementType_t) cgnsType = msh2CgnsEltType(mshType);
607 std::ostringstream ossInterp;
608 ossInterp <<
"Element_" << cgnsType;
609 std::string interpName = ossInterp.str();
611 cgnsErr = cg_element_interpolation_write(cgIndexFile, cgIndexBase,
612 cgIndexFam, interpName.c_str(),
613 cgnsType, &indexInterp);
614 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
615 cgnsErr = cg_element_interpolation_points_write(
616 cgIndexFile, cgIndexBase, cgIndexFam, indexInterp, u.data(), v.data(),
618 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
623 Msg::Error(
"Gmsh is not compiled with CGNS CPEX0045 capability");
628 int writeGeomEntities(std::map<GEntity *, std::string> &geomEntities,
629 int cgIndexFile,
int cgIndexBase)
633 for(
auto it = geomEntities.begin(); it != geomEntities.end(); ++it) {
636 std::string &geomName = it->second;
642 cg_family_write(cgIndexFile, cgIndexBase, geomName.c_str(), &cgIndexFam);
643 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
647 for(std::size_t iPhys = 0; iPhys < phys.size(); iPhys++) {
649 const int physTag = phys[iPhys];
652 std::ostringstream oss;
654 physName = oss.str();
658 cgnsErr = cg_family_name_write(cgIndexFile, cgIndexBase, cgIndexFam,
659 physName.c_str(), physName.c_str());
660 if(cgnsErr != CG_OK)
return cgnsError(__FILE__, __LINE__, cgIndexFile);
667 #endif // HAVE_LIBCGNS