gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
CGNSWrite.cpp
Go to the documentation of this file.
1 // Gmsh - Copyright (C) 1997-2022 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 //
6 // Contributor(s):
7 // Thomas Toulorge
8 
9 #include <sstream>
10 #include <string>
11 #include <map>
12 #include <utility>
13 #include "Context.h"
14 #include "GmshMessage.h"
15 #include "GModel.h"
16 #include "partitionRegion.h"
17 #include "partitionFace.h"
18 #include "partitionEdge.h"
19 #include "partitionVertex.h"
20 #include "nodalBasis.h"
21 #include "BasisFactory.h"
22 #include "affineTransformation.h"
23 #include "CGNSWrite.h"
24 #include "CGNSConventions.h"
25 
26 #if defined(HAVE_LIBCGNS)
27 
28 namespace {
29 
30  // Types for periodic and interface connectivities
31  typedef std::pair<unsigned int, unsigned int> PartitionInterface;
32  typedef std::pair<std::vector<cgsize_t>, std::vector<cgsize_t> >
33  NodeCorrespondence;
34 
35  static const char INTERPOLATION_ZONE_NAME[] = "ElementHighOrderNodes";
36 
37  // Retrieve all nodes (possibly including high-order ones) in the elements
38  // contained in the given entities
39  template <bool INCLUDE_HO_NODES>
40  void getNodesInEntities(const std::vector<GEntity *> &entities,
41  bool allElements, std::set<MVertex *> &nodeSet)
42  {
43  for(std::size_t i = 0; i < entities.size(); i++) {
44  GEntity *ge = entities[i];
45  std::vector<int> eleTypes;
46  ge->getElementTypes(eleTypes);
47  for(std::size_t eleType = 0; eleType < eleTypes.size(); eleType++) {
48  int numEle = ge->getNumMeshElementsByType(eleTypes[eleType]);
49  if(numEle && (allElements || ge->physicals.size())) {
50  for(int j = 0; j < numEle; j++) {
51  MElement *me = ge->getMeshElementByType(eleTypes[eleType], j);
52  int numEltVert = INCLUDE_HO_NODES ? me->getNumVertices() :
54  for(int k = 0; k < numEltVert; k++) {
55  nodeSet.insert(me->getVertex(k));
56  }
57  }
58  }
59  }
60  }
61  }
62 
63  std::string entTypeShortStr(int dim)
64  {
65  switch(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;
70  }
71 
72  return "";
73  }
74 
75  void getNameFromEntity(GEntity *ge, std::string &entityName)
76  {
77  // convention: start name with letter identifying dimension
78  const std::string entTypeStr = entTypeShortStr(ge->dim());
79 
80  // get parent entity and model
81  GEntity *geParent = ge->getParentEntity();
82  GModel *model = ge->model();
83 
84  // name for section: use given (potentially partitioned) entity in addition
85  // to the parent entity (if it exists) in order to avoid duplicate CGNS
86  // names
87  std::ostringstream ossEnt;
88  ossEnt << entTypeStr;
89  if(geParent != nullptr) ossEnt << "_" << geParent->tag();
90  ossEnt << "_" << ge->tag();
91  entityName = model->getElementaryName(ge->dim(), ge->tag());
92  if(!entityName.empty()) ossEnt << "_" << entityName;
93  entityName = ossEnt.str();
94  entityName = cgnsString(entityName);
95  }
96 
97 } // anonymous namespace
98 
99 // Get all partition interface entities
100 void getEntitiesToSave(const std::vector<GEntity *> &allEntities, bool saveAll,
101  std::vector<GEntity *> &entities)
102 {
103  entities.clear();
104  entities.reserve(allEntities.size());
105  for(std::size_t i = 0; i < allEntities.size(); i++) {
106  GEntity *ge = allEntities[i];
107  if(ge->getNumMeshElements() == 0) continue;
108  if(saveAll || (ge->physicals.size() > 0)) entities.push_back(ge);
109  }
110 }
111 
112 // Get all periodic entities
113 void getPeriodicEntities(const std::vector<GEntity *> &allEntities,
114  std::vector<GEntity *> &entitiesPer)
115 {
116  entitiesPer.clear();
117  for(std::size_t i = 0; i < allEntities.size(); i++) {
118  GEntity *slaveEnt = allEntities[i];
119  GEntity *masterEnt = slaveEnt->getMeshMaster();
120  if(slaveEnt != masterEnt) entitiesPer.push_back(slaveEnt);
121  }
122 }
123 
124 // Get all partition interface entities
125 void getPartitionInterfaceEntities(const std::vector<GEntity *> &entities,
126  bool saveAll,
127  std::vector<GEntity *> &entitiesInt)
128 {
129  for(std::size_t j = 0; j < entities.size(); j++) {
130  GEntity *ge = entities[j];
131  switch(ge->geomType()) {
133  partitionRegion *pr = static_cast<partitionRegion *>(ge);
134  const GEntity *pge = pr->getParentEntity();
135  if((pge->dim() != pr->dim()) && (saveAll || (pge->physicals.size() > 0)))
136  entitiesInt.push_back(ge);
137  } break;
139  partitionFace *pf = static_cast<partitionFace *>(ge);
140  const GEntity *pge = pf->getParentEntity();
141  if(pf->getParentEntity()->dim() != pf->dim()) entitiesInt.push_back(ge);
142  if((pge->dim() != pf->dim()) && (saveAll || (pge->physicals.size() > 0)))
143  entitiesInt.push_back(ge);
144  } break;
146  partitionEdge *pe = static_cast<partitionEdge *>(ge);
147  const GEntity *pge = pe->getParentEntity();
148  if((pge->dim() != pe->dim()) && (saveAll || (pge->physicals.size() > 0)))
149  entitiesInt.push_back(ge);
150  } break;
152  partitionVertex *pv = static_cast<partitionVertex *>(ge);
153  const GEntity *pge = pv->getParentEntity();
154  if((pge->dim() != pv->dim()) && (saveAll || (pge->physicals.size() > 0)))
155  entitiesInt.push_back(ge);
156  } break;
157  default: break;
158  } // switch
159  } // loop on entities
160 }
161 
162 // Initialize MVertex -> local data correspondence (only for primary vertices)
163 void initInterfVertex2LocalData(const std::vector<GEntity *> &entitiesPer,
164  const std::vector<GEntity *> &entitiesInterf,
165  Vertex2LocalData &interfVert2Local)
166 {
167  // Periodic entities
168  for(std::size_t i = 0; i < entitiesPer.size(); i++) {
169  auto &vv = entitiesPer[i]->correspondingVertices;
170  for(auto itV = vv.begin(); itV != vv.end(); itV++) {
171  interfVert2Local[itV->first] = std::vector<LocalData>();
172  interfVert2Local[itV->second] = std::vector<LocalData>();
173  }
174  }
175 
176  // Partition interface boundaries
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>();
181  }
182 }
183 
184 // create a single zone for a whole partition; nodes and elements are
185 // referenced with per-zone index (starting at 1) inside a zone
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)
192 {
193 #ifdef HAVE_LIBCGNS_CPEX0045
194  const bool useCPEX0045 = CTX::instance()->mesh.cgnsExportCPEX0045;
195 #else
196  static const bool useCPEX0045 = false;
197 #endif
198 
199  // build set of nodes first, use elements because nodes not all in
200  // GEntity::mesh_vertices if entities do not include partition interfaces
201  std::set<MVertex *> nodeSet;
202  getNodesInEntities<true>(entities, saveAll, nodeSet);
203 
204  // build global -> partition-local node index correspondence and
205  // store local data correspondence for periodic/interface nodes
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;
211  numNodes++;
212  LocalData &ld = global2Local[gInd];
213  ld.partition = partition;
214  ld.index = numNodes;
215  auto itPN = interfVert2Local.find(*itN);
216  if(itPN != interfVert2Local.end()) itPN->second.push_back(ld);
217  }
218 
219  // create lists of coordinates
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;
228  }
229 
230  // number of elements for highest spatial dimension
231  cgsize_t numElementsMaxDim = 0;
232  for(std::size_t i = 0; i < entities.size(); i++) {
233  GEntity *ge = entities[i];
234  if(ge->dim() == meshDim && (saveAll || ge->physicals.size())) {
235  numElementsMaxDim += ge->getNumMeshElements();
236  }
237  }
238 
239  // write zone CGNS node
240  int cgnsErr;
241  int cgIndexZone = 0;
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);
251 
252  // write ordinal (zone number) and family name for CPEX0045
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);
257  if(useCPEX0045) {
258  cgnsErr = cg_famname_write(INTERPOLATION_ZONE_NAME);
259  if(cgnsErr != CG_OK) return cgnsError(__FILE__, __LINE__, cgIndexFile);
260  }
261 
262  // create a CGNS grid with x, y and z coordinates of all the nodes (that are
263  // referenced by elements)
264  int cgIndexGrid = 0;
265  cgnsErr = cg_grid_write(cgIndexFile, cgIndexBase, cgIndexZone,
266  "GridCoordinates", &cgIndexGrid);
267  if(cgnsErr != CG_OK) return cgnsError(__FILE__, __LINE__, cgIndexFile);
268 
269  // write list of coordinates
270  int cgIndexCoord = 0;
271  cgnsErr = cg_coord_write(cgIndexFile, cgIndexBase, cgIndexZone,
272  CGNS_ENUMV(RealDouble), "CoordinateX", &xcoord[0],
273  &cgIndexCoord);
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],
277  &cgIndexCoord);
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],
281  &cgIndexCoord);
282  if(cgnsErr != CG_OK) return cgnsError(__FILE__, __LINE__, cgIndexFile);
283 
284  // write an element section for each entity, per element type
285  cgsize_t eleStart = 0, eleEnd = 0;
286  for(std::size_t i = 0; i < entities.size(); i++) {
287  // get entities
288  GEntity *ge = entities[i];
289  GEntity *geGeom = ge->getParentEntity();
290  if(geGeom == nullptr) geGeom = ge;
291 
292  // get or create the names for the entity
293  std::string entityName, geomEntityName;
294  getNameFromEntity(ge, entityName);
295  getNameFromEntity(geGeom, geomEntityName);
296  geomEntities[geGeom] = geomEntityName;
297 
298  // retrieve element types for this geometric entity
299  std::vector<int> eleTypes;
300  ge->getElementTypes(eleTypes);
301 
302  // Range of element indices in entity (for BC)
303  cgsize_t eleEntRange[2] = {eleEnd + 1, 0};
304 
305  // build list of connectivities
306  for(std::size_t eleType = 0; eleType < eleTypes.size(); eleType++) {
307  int numEle = ge->getNumMeshElementsByType(eleTypes[eleType]);
308  if((numEle == 0) || ((ge->physicals.size() == 0) && (!saveAll))) continue;
309  eleStart = eleEnd + 1;
310  eleEnd += numEle;
311  MElement *me = ge->getMeshElementByType(eleTypes[eleType], 0);
312  int mshType = me->getTypeForMSH();
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);
316  break;
317  }
318  if(useCPEX0045) eleMshTypes.insert(mshType);
319  std::vector<int> mshNodeInd = cgns2MshNodeIndex(mshType);
320 
321  // build connectivity for each element
322  int numNodesPerEle = me->getNumVertices();
323  std::vector<cgsize_t> elemNodes(numEle * numNodesPerEle);
324  std::size_t n = 0;
325  for(int j = 0; j < numEle; j++) {
326  me = ge->getMeshElementByType(eleTypes[eleType], j);
327  for(int k = 0; k < numNodesPerEle; k++) {
328  const int kk = useCPEX0045 ? k : mshNodeInd[k];
329  const int gInd = me->getVertex(kk)->getIndex();
330  elemNodes[n] = global2Local[gInd].index;
331  n++;
332  }
333  }
334 
335  // write section
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);
343  }
344 
345  // write elementary entity as BC and geometrical entity as BC family name
346  eleEntRange[1] = eleEnd;
347  int iZoneBC;
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);
352  // GridLocation not clear: can "Vertex" be understood as "point" elements?
353  // const CGNS_ENUMT(GridLocation_t) loc =
354  // (entDim == 2) ? CGNS_ENUMV(FaceCenter) :
355  // (entDim == 1) ? CGNS_ENUMV(EdgeCenter) :
356  // (entDim == 0) ? CGNS_ENUMV(Vertex) : CGNS_ENUMV(CellCenter);
357  const CGNS_ENUMT(GridLocation_t) loc = CGNS_ENUMV(CellCenter);
358  cgnsErr = cg_boco_gridlocation_write(cgIndexFile, cgIndexBase, cgIndexZone,
359  iZoneBC, loc);
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);
366  }
367 
368  return 1;
369 }
370 
371 // create periodic connections for all entities in all partitions
372 int writePeriodic(const std::vector<GEntity *> &entitiesPer, int cgIndexFile,
373  int cgIndexBase, const std::vector<std::string> &zoneName,
374  Vertex2LocalData &interfVert2Local)
375 {
376  // Types for periodic connectivity
377  typedef std::pair<GEntity *, GEntity *> EntityInterface;
378  typedef std::pair<PartitionInterface, EntityInterface> PeriodicInterface;
379  typedef std::map<PeriodicInterface, NodeCorrespondence> PeriodicConnection;
380 
381  // Construct interfaces [slave (entity, part.) <-> master (entity, part.)]
382  // with corresponding nodes
383  Msg::Info("Constructing connectivities for %i periodic entities",
384  entitiesPer.size());
385  PeriodicConnection connect;
386  for(std::size_t iEnt = 0; iEnt < entitiesPer.size(); iEnt++) {
387  GEntity *slaveEnt = entitiesPer[iEnt];
388  GEntity *masterEnt = slaveEnt->getMeshMaster();
389  auto &vv = slaveEnt->correspondingVertices;
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);
412  }
413  }
414  }
415  }
416 
417  // write periodic interfaces
418  int cgnsErr;
419  for(auto it = connect.begin(); it != connect.end(); ++it) {
420  printProgress("Writing periodic interface",
421  std::distance(connect.begin(), it) + 1, connect.size());
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())
437  << ent2->tag();
438  const std::string interfaceName = cgnsString(ossInt.str());
439  int connIdx;
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);
447  // get parameters from transformation (CGNS transfo = inverse Gmsh transfo)
448  float rotCenter[3], rotAngle[3], trans[3];
449  if(ent1->getMeshMaster() == ent2) {
450  const std::vector<double> &perTransfo = ent1->affineTransform;
451  getAffineTransformationParameters(perTransfo, rotCenter, rotAngle, trans);
452  for(int i = 0; i < 3; i++) {
453  rotAngle[i] = -rotAngle[i];
454  trans[i] = -trans[i];
455  }
456  }
457  else if(ent2->getMeshMaster() == ent1) {
458  const std::vector<double> &perTransfo = ent2->affineTransform;
459  getAffineTransformationParameters(perTransfo, rotCenter, rotAngle, trans);
460  }
461  else {
462  Msg::Error("Error in periodic connection between entities %i (dim %i) "
463  "and %i (dim %i)",
464  ent1->tag(), ent1->dim(), ent2->tag(), ent2->dim());
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.;
468  }
469  cgnsErr = cg_conn_periodic_write(cgIndexFile, cgIndexBase, slaveZone,
470  connIdx, rotCenter, rotAngle, trans);
471  if(cgnsErr != CG_OK) return cgnsError(__FILE__, __LINE__, cgIndexFile);
472  }
473 
474  return 1;
475 }
476 
477 // Get entities in each partition, except partition interfaces
478 void getEntitiesInPartitions(const std::vector<GEntity *> &entities,
479  std::vector<std::vector<GEntity *> > &entitiesPart)
480 {
481  for(std::size_t j = 0; j < entities.size(); j++) {
482  GEntity *ge = entities[j];
483  const std::vector<int> *parts = nullptr;
484  switch(ge->geomType()) {
486  partitionRegion *pr = static_cast<partitionRegion *>(ge);
487  if(pr->getParentEntity()->dim() != pr->dim())
488  continue; // Skip partition interfaces
489  parts = &(pr->getPartitions());
490  } break;
492  partitionFace *pf = static_cast<partitionFace *>(ge);
493  if(pf->getParentEntity()->dim() != pf->dim())
494  continue; // Skip partition interfaces
495  parts = &(pf->getPartitions());
496  } break;
498  partitionEdge *pe = static_cast<partitionEdge *>(ge);
499  if(pe->getParentEntity()->dim() != pe->dim())
500  continue; // Skip partition interfaces
501  parts = &(pe->getPartitions());
502  } break;
504  partitionVertex *pv = static_cast<partitionVertex *>(ge);
505  if(pv->getParentEntity()->dim() != pv->dim())
506  continue; // Skip partition interfaces
507  parts = &(pv->getPartitions());
508  } break;
509  default: break;
510  } // switch
511  if(parts != nullptr) {
512  for(std::size_t iPart = 0; iPart < parts->size(); iPart++) {
513  entitiesPart[(*parts)[iPart]].push_back(ge);
514  }
515  }
516  } // loop on entities
517 }
518 
519 // create partition interfaces
520 int writeInterfaces(const std::vector<GEntity *> &entitiesInterf,
521  int cgIndexFile, int cgIndexBase,
522  const std::vector<std::string> &zoneName,
523  Vertex2LocalData &interfVert2Local)
524 {
525  // type for partition connectivity
526  typedef std::map<PartitionInterface, NodeCorrespondence> PartitionConnection;
527 
528  // get nodes in partition interface entities
529  std::set<MVertex *> nodeSet;
530  getNodesInEntities<false>(entitiesInterf, true, nodeSet);
531 
532  // construct (two-way) partition connectivities with corresponding nodes
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);
548  }
549  }
550  }
551 
552  // write partition interfaces
553  int cgnsErr;
554  std::size_t iPartConnect = 0;
555  for(auto it = connect.begin(); it != connect.end(); ++it) {
556  iPartConnect++;
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());
566  int dum;
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);
574  }
575 
576  return 1;
577 }
578 
579 // write element high-orper point info according to CPEX0045 convention
580 int writeHOPointInfo(const std::set<int> &eleMshTypes, int cgIndexFile,
581  int cgIndexBase)
582 {
583 #ifdef HAVE_LIBCGNS_CPEX0045
584  int cgnsErr;
585 
586  // Write family containing all node sets
587  int cgIndexFam;
588  cgnsErr = cg_family_write(cgIndexFile, cgIndexBase, INTERPOLATION_ZONE_NAME,
589  &cgIndexFam);
590  if(cgnsErr != CG_OK) return cgnsError(__FILE__, __LINE__, cgIndexFile);
591 
592  // write node sets for each element type
593  for(auto it = eleMshTypes.begin(); it != eleMshTypes.end(); ++it) {
594  // get node set
595  const int mshType = *it;
596  const nodalBasis *basis = BasisFactory::getNodalBasis(mshType);
597  const fullMatrix<double> &mshPts = basis->getReferenceNodes();
598  if(mshType == MSH_PNT) continue;
599 
600  // convert nodes to CGNS reference element if needed
601  std::size_t nbPts = mshPts.size1();
602  std::vector<double> u(nbPts), v(nbPts), w(nbPts);
603  msh2CgnsReferenceElement(mshType, mshPts, u, v, w);
604 
605  // write nodal set
606  CGNS_ENUMT(ElementType_t) cgnsType = msh2CgnsEltType(mshType);
607  std::ostringstream ossInterp;
608  ossInterp << "Element_" << cgnsType;
609  std::string interpName = ossInterp.str();
610  int indexInterp;
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(),
617  w.data());
618  if(cgnsErr != CG_OK) return cgnsError(__FILE__, __LINE__, cgIndexFile);
619  }
620 
621  return 1;
622 #else
623  Msg::Error("Gmsh is not compiled with CGNS CPEX0045 capability");
624  return 0;
625 #endif
626 }
627 
628 int writeGeomEntities(std::map<GEntity *, std::string> &geomEntities,
629  int cgIndexFile, int cgIndexBase)
630 {
631  int cgnsErr;
632 
633  for(auto it = geomEntities.begin(); it != geomEntities.end(); ++it) {
634  // get geometric entity
635  GEntity *ge = it->first;
636  std::string &geomName = it->second;
637  GModel *model = ge->model();
638 
639  // Write family containing all node sets
640  int cgIndexFam;
641  cgnsErr =
642  cg_family_write(cgIndexFile, cgIndexBase, geomName.c_str(), &cgIndexFam);
643  if(cgnsErr != CG_OK) return cgnsError(__FILE__, __LINE__, cgIndexFile);
644 
645  // write physical tags or names
646  std::vector<int> phys = ge->getPhysicalEntities();
647  for(std::size_t iPhys = 0; iPhys < phys.size(); iPhys++) {
648  // get name if exists, otherwise tag
649  const int physTag = phys[iPhys];
650  std::string physName = model->getPhysicalName(ge->dim(), physTag);
651  if(physName == "") {
652  std::ostringstream oss;
653  oss << physTag;
654  physName = oss.str();
655  }
656 
657  // write to family name
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);
661  }
662  }
663 
664  return 1;
665 }
666 
667 #endif // HAVE_LIBCGNS
GEntity::getMeshElementByType
virtual MElement * getMeshElementByType(const int familyType, const std::size_t index) const
Definition: GEntity.h:365
GEntity::affineTransform
std::vector< double > affineTransform
Definition: GEntity.h:403
partitionEdge
Definition: partitionEdge.h:12
distance
double distance(MVertex *v1, MVertex *v2)
Definition: MVertex.h:245
MSH_PNT
#define MSH_PNT
Definition: GmshDefines.h:94
MElement::getTypeForMSH
virtual int getTypeForMSH() const
Definition: MElement.h:488
Msg::Info
static void Info(const char *fmt,...)
Definition: GmshMessage.cpp:587
GEntity::model
GModel * model() const
Definition: GEntity.h:277
nodalBasis.h
GEntity::getParentEntity
virtual GEntity * getParentEntity()
Definition: GEntity.h:199
GModel::getName
std::string getName() const
Definition: GModel.h:329
Msg::Error
static void Error(const char *fmt,...)
Definition: GmshMessage.cpp:482
GEntity::physicals
std::vector< int > physicals
Definition: GEntity.h:65
Vertex
Definition: Geo.h:29
partitionEdge::getParentEntity
virtual GEntity * getParentEntity()
Definition: partitionEdge.h:36
partitionFace
Definition: partitionFace.h:12
partitionRegion::getPartitions
virtual const std::vector< int > & getPartitions() const
Definition: partitionRegion.h:39
GmshMessage.h
nodalBasis::getReferenceNodes
void getReferenceNodes(fullMatrix< double > &nodes) const
Definition: nodalBasis.h:23
partitionFace::getPartitions
virtual const std::vector< int > & getPartitions() const
Definition: partitionFace.h:39
GFace::dim
virtual int dim() const
Definition: GFace.h:175
GEntity
Definition: GEntity.h:31
partitionVertex::getPartitions
virtual const std::vector< int > & getPartitions() const
Definition: partitionVertex.h:39
GEntity::getMeshMaster
GEntity * getMeshMaster() const
Definition: GEntity.h:291
GEntity::PartitionVolume
@ PartitionVolume
Definition: GEntity.h:124
MElement::getNumVertices
virtual std::size_t getNumVertices() const =0
GEdge::dim
virtual int dim() const
Definition: GEdge.h:86
GEntity::PartitionCurve
@ PartitionCurve
Definition: GEntity.h:122
CTX::instance
static CTX * instance()
Definition: Context.cpp:122
MElement::getVertex
virtual const MVertex * getVertex(int num) const =0
fullMatrix< double >
GModel::getPhysicalName
std::string getPhysicalName(int dim, int num) const
Definition: GModel.cpp:961
affineTransformation.h
BasisFactory::getNodalBasis
static const nodalBasis * getNodalBasis(int tag)
Definition: BasisFactory.cpp:23
GEntity::getNumMeshElements
virtual std::size_t getNumMeshElements() const
Definition: GEntity.h:348
CGNSWrite.h
partitionRegion.h
GModel
Definition: GModel.h:44
getEntitiesToSave
static void getEntitiesToSave(GModel *const model, bool partitioned, int partitionToSave, bool saveAll, std::set< GRegion *, GEntityPtrLessThan > &regions, std::set< GFace *, GEntityPtrLessThan > &faces, std::set< GEdge *, GEntityPtrLessThan > &edges, std::set< GVertex *, GEntityPtrLessThan > &vertices)
Definition: GModelIO_MSH4.cpp:2211
partitionRegion
Definition: partitionRegion.h:12
GEntity::geomType
virtual GeomType geomType() const
Definition: GEntity.h:238
partitionRegion::getParentEntity
virtual GEntity * getParentEntity()
Definition: partitionRegion.h:34
CTX::mesh
contextMeshOptions mesh
Definition: Context.h:313
GModel::getElementaryName
std::string getElementaryName(int dim, int tag)
Definition: GModel.cpp:1007
MElement
Definition: MElement.h:30
GEntity::tag
int tag() const
Definition: GEntity.h:280
GRegion::dim
virtual int dim() const
Definition: GRegion.h:45
partitionFace.h
partitionEdge.h
GEntity::getElementTypes
virtual void getElementTypes(std::vector< int > &types) const
Definition: GEntity.h:345
contextMeshOptions::cgnsExportCPEX0045
int cgnsExportCPEX0045
Definition: Context.h:69
partitionEdge::getPartitions
virtual const std::vector< int > & getPartitions() const
Definition: partitionEdge.h:41
getAffineTransformationParameters
bool getAffineTransformationParameters(const std::vector< double > &tfo, FLOAT *rc, FLOAT *ra, FLOAT *tr)
Definition: affineTransformation.cpp:75
CGNSConventions.h
GEntity::PartitionSurface
@ PartitionSurface
Definition: GEntity.h:123
MVertex::getIndex
long int getIndex() const
Definition: MVertex.h:93
Context.h
nodalBasis
Definition: nodalBasis.h:12
fullMatrix::size1
int size1() const
Definition: fullMatrix.h:274
partitionVertex::getParentEntity
virtual GEntity * getParentEntity()
Definition: partitionVertex.h:34
GEntity::getNumMeshElementsByType
virtual std::size_t getNumMeshElementsByType(const int familyType) const
Definition: GEntity.h:349
MElement::getNumPrimaryVertices
std::size_t getNumPrimaryVertices() const
Definition: MElement.h:160
GEntity::getPhysicalEntities
virtual std::vector< int > getPhysicalEntities()
Definition: GEntity.h:288
partitionVertex
Definition: partitionVertex.h:12
GEntity::PartitionPoint
@ PartitionPoint
Definition: GEntity.h:121
GModel.h
partitionFace::getParentEntity
virtual GEntity * getParentEntity()
Definition: partitionFace.h:34
GEntity::dim
virtual int dim() const
Definition: GEntity.h:196
partitionVertex.h
GEntity::correspondingVertices
std::map< MVertex *, MVertex * > correspondingVertices
Definition: GEntity.h:406
GVertex::dim
virtual int dim() const
Definition: GVertex.h:63
BasisFactory.h