gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
GModelIO_MSH4.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 // Anthony Royer
8 
9 #include <cstdio>
10 #include <fstream>
11 #include <vector>
12 #include <map>
13 #include <algorithm>
14 #include <sstream>
15 #include <string>
16 #include <cstdlib>
17 #include <limits>
18 #include <stdexcept>
19 
20 #include "GmshDefines.h"
21 #include "OS.h"
22 #include "Context.h"
23 #include "GModel.h"
24 #include "GEntity.h"
25 #include "partitionRegion.h"
26 #include "partitionFace.h"
27 #include "partitionEdge.h"
28 #include "partitionVertex.h"
29 #include "discreteEdge.h"
30 #include "ghostFace.h"
31 #include "ghostEdge.h"
32 #include "ghostRegion.h"
33 #include "MPoint.h"
34 #include "MLine.h"
35 #include "MTriangle.h"
36 #include "MQuadrangle.h"
37 #include "MTetrahedron.h"
38 #include "MHexahedron.h"
39 #include "MPrism.h"
40 #include "MPyramid.h"
41 #include "MTrihedron.h"
42 #include "StringUtils.h"
43 
44 static bool readMSH4Physicals(GModel *const model, FILE *fp,
45  GEntity *const entity, bool binary, char *str,
46  bool swap)
47 {
48  std::size_t numPhy = 0;
49  if(binary) {
50  if(fread(&numPhy, sizeof(std::size_t), 1, fp) != 1) { return false; }
51  if(swap) SwapBytes((char *)&numPhy, sizeof(std::size_t), 1);
52 
53  std::vector<int> phyTags(numPhy);
54  if(fread(&phyTags[0], sizeof(int), numPhy, fp) != numPhy) { return false; }
55  if(swap) SwapBytes((char *)&phyTags[0], sizeof(int), numPhy);
56 
57  for(std::size_t i = 0; i < numPhy; i++) {
58  entity->addPhysicalEntity(phyTags[i]);
59  }
60  }
61  else {
62  sscanf(str, "%lu %[0-9- ]", &numPhy, str);
63  for(std::size_t i = 0; i < numPhy; i++) {
64  int phyTag = 0;
65 
66  if(i == numPhy - 1 && entity->dim() == 0) {
67  if(sscanf(str, "%d", &phyTag) != 1) { return false; }
68  }
69  else {
70  if(sscanf(str, "%d %[0-9- ]", &phyTag, str) != 2) { return false; }
71  }
72 
73  entity->addPhysicalEntity(phyTag);
74  }
75  }
76  return true;
77 }
78 
79 static bool readMSH4BoundingEntities(GModel *const model, FILE *fp,
80  GEntity *const entity, bool binary,
81  char *str, bool swap)
82 {
83  std::size_t numBrep = 0;
84  std::vector<GEntity *> boundingEntities;
85  std::vector<int> boundingSign;
86 
87  if(binary) {
88  if(fread(&numBrep, sizeof(std::size_t), 1, fp) != 1) { return false; }
89  if(swap) SwapBytes((char *)&numBrep, sizeof(std::size_t), 1);
90 
91  std::vector<int> brepTags(numBrep);
92  if(fread(&brepTags[0], sizeof(int), numBrep, fp) != numBrep) {
93  return false;
94  }
95  if(swap) SwapBytes((char *)&brepTags[0], sizeof(int), numBrep);
96 
97  for(std::size_t i = 0; i < numBrep; i++) {
98  GEntity *brep =
99  model->getEntityByTag(entity->dim() - 1, std::abs(brepTags[i]));
100  if(!brep) {
101  Msg::Warning("Entity %d not found in the Brep of entity %d",
102  brepTags[i], entity->tag());
103  }
104  else {
105  boundingEntities.push_back(brep);
106  boundingSign.push_back((std::abs(brepTags[i]) == brepTags[i] ? 1 : -1));
107  }
108  }
109  }
110  else {
111  sscanf(str, "%lu %[0-9- ]", &numBrep, str);
112  for(std::size_t i = 0; i < numBrep; i++) {
113  int entityTag = 0;
114 
115  if(i != numBrep - 1) {
116  if(sscanf(str, "%d %[0-9- ]", &entityTag, str) != 2) { return false; }
117  }
118  else {
119  if(sscanf(str, "%d", &entityTag) != 1) { return false; }
120  }
121 
122  GEntity *brep =
123  model->getEntityByTag(entity->dim() - 1, std::abs(entityTag));
124  if(!brep) {
125  Msg::Warning("Entity %d not found in the Brep of entity %d", entityTag,
126  entity->tag());
127  }
128  else {
129  boundingEntities.push_back(brep);
130  boundingSign.push_back((std::abs(entityTag) == entityTag ? 1 : -1));
131  }
132  }
133  }
134 
135  switch(entity->dim()) {
136  case 1:
137  if(boundingEntities.size() == 2) {
138  reinterpret_cast<GEdge *>(entity)->setBeginVertex(
139  reinterpret_cast<GVertex *>(boundingEntities[0]));
140  reinterpret_cast<GEdge *>(entity)->setEndVertex(
141  reinterpret_cast<GVertex *>(boundingEntities[1]));
142  }
143  else if(boundingEntities.size() == 1) {
144  if(boundingSign[0] == 1) {
145  reinterpret_cast<GEdge *>(entity)->setBeginVertex(
146  reinterpret_cast<GVertex *>(boundingEntities[0]));
147  }
148  else {
149  reinterpret_cast<GEdge *>(entity)->setEndVertex(
150  reinterpret_cast<GVertex *>(boundingEntities[0]));
151  }
152  }
153  break;
154  case 2: {
155  std::vector<int> tags(boundingEntities.size());
156  for(std::size_t i = 0; i < boundingEntities.size(); i++)
157  tags[i] = std::abs(boundingEntities[i]->tag());
158  reinterpret_cast<GFace *>(entity)->setBoundEdges(tags, boundingSign);
159  } break;
160  case 3: {
161  std::vector<int> tags(boundingEntities.size());
162  for(std::size_t i = 0; i < boundingEntities.size(); i++)
163  tags[i] = std::abs(boundingEntities[i]->tag());
164  reinterpret_cast<GRegion *>(entity)->setBoundFaces(tags, boundingSign);
165  } break;
166  default: break;
167  }
168  return true;
169 }
170 
171 static bool readMSH4EntityInfo(FILE *fp, bool binary, char *str, int sizeofstr,
172  bool swap, double version, bool partition,
173  int dim, int &tag, int &parentDim,
174  int &parentTag, std::vector<int> &partitions,
175  double &minX, double &minY, double &minZ,
176  double &maxX, double &maxY, double &maxZ)
177 {
178  if(partition) {
179  if(binary) {
180  int dataInt[3];
181  if(fread(dataInt, sizeof(int), 3, fp) != 3) { return false; }
182  if(swap) SwapBytes((char *)dataInt, sizeof(int), 3);
183  tag = dataInt[0];
184  parentDim = dataInt[1];
185  parentTag = dataInt[2];
186  std::size_t numPart;
187  if(fread(&numPart, sizeof(std::size_t), 1, fp) != 1) { return false; }
188  partitions.resize(numPart, 0);
189  if(fread(&partitions[0], sizeof(int), numPart, fp) != numPart) {
190  return false;
191  }
192  if(swap) SwapBytes((char *)&partitions[0], sizeof(int), numPart);
193  double dataDouble[6];
194  const std::size_t nbb = (dim > 0) ? 6 : 3;
195  if(fread(dataDouble, sizeof(double), nbb, fp) != nbb) { return false; }
196  if(swap) SwapBytes((char *)dataDouble, sizeof(double), nbb);
197  minX = dataDouble[0];
198  minY = dataDouble[1];
199  minZ = dataDouble[2];
200  maxX = dataDouble[(nbb == 6) ? 3 : 0];
201  maxY = dataDouble[(nbb == 6) ? 4 : 1];
202  maxZ = dataDouble[(nbb == 6) ? 5 : 2];
203  }
204  else {
205  std::size_t numPart = 0;
206  if(fscanf(fp, "%d %d %d %lu", &tag, &parentDim, &parentTag, &numPart) !=
207  4) {
208  return false;
209  }
210  partitions.resize(numPart, 0);
211  for(std::size_t i = 0; i < numPart; i++) {
212  if(fscanf(fp, "%d", &partitions[i]) != 1) { return false; }
213  }
214  if(version < 4.1 || dim > 0) {
215  if(fscanf(fp, "%lf %lf %lf %lf %lf %lf", &minX, &minY, &minZ, &maxX,
216  &maxY, &maxZ) != 6) {
217  return false;
218  }
219  }
220  else {
221  if(fscanf(fp, "%lf %lf %lf", &minX, &minY, &minZ) != 3) {
222  return false;
223  }
224  maxX = minX;
225  maxY = minY;
226  maxZ = minZ;
227  }
228  if(!fgets(str, sizeofstr, fp)) { return false; }
229  }
230  }
231  else {
232  if(binary) {
233  int dataInt;
234  if(fread(&dataInt, sizeof(int), 1, fp) != 1) { return false; }
235  if(swap) SwapBytes((char *)&dataInt, sizeof(int), 1);
236  double dataDouble[6];
237  const std::size_t nbb = (dim > 0) ? 6 : 3;
238  if(fread(dataDouble, sizeof(double), nbb, fp) != nbb) { return false; }
239  if(swap) SwapBytes((char *)dataDouble, sizeof(double), nbb);
240  tag = dataInt;
241  minX = dataDouble[0];
242  minY = dataDouble[1];
243  minZ = dataDouble[2];
244  maxX = dataDouble[(nbb == 6) ? 3 : 0];
245  maxY = dataDouble[(nbb == 6) ? 4 : 1];
246  maxZ = dataDouble[(nbb == 6) ? 5 : 2];
247  }
248  else {
249  if(version < 4.1 || dim > 0) {
250  if(fscanf(fp, "%d %lf %lf %lf %lf %lf %lf", &tag, &minX, &minY, &minZ,
251  &maxX, &maxY, &maxZ) != 7) {
252  return false;
253  }
254  }
255  else {
256  if(fscanf(fp, "%d %lf %lf %lf", &tag, &minX, &minY, &minZ) != 4) {
257  return false;
258  }
259  maxX = minX;
260  maxY = minY;
261  maxZ = minZ;
262  }
263  if(!fgets(str, sizeofstr, fp)) { return false; }
264  }
265  }
266  return true;
267 }
268 
269 static bool readMSH4Entities(GModel *const model, FILE *fp, bool partition,
270  bool binary, bool swap, double version)
271 {
272  if(partition) {
273  std::size_t numPartitions = 0;
274  std::size_t ghostSize = 0;
275  std::vector<int> ghostTags;
276 
277  if(binary) {
278  if(fread(&numPartitions, sizeof(std::size_t), 1, fp) != 1) {
279  return false;
280  }
281  if(swap) SwapBytes((char *)&numPartitions, sizeof(std::size_t), 1);
282 
283  if(fread(&ghostSize, sizeof(std::size_t), 1, fp) != 1) { return false; }
284  if(swap) SwapBytes((char *)&ghostSize, sizeof(std::size_t), 1);
285  if(ghostSize) {
286  ghostTags.resize(2 * ghostSize);
287  if(fread(&ghostTags[0], sizeof(int), 2 * ghostSize, fp) !=
288  2 * ghostSize) {
289  return false;
290  }
291  if(swap) SwapBytes((char *)&ghostTags[0], sizeof(int), 2 * ghostSize);
292  }
293  }
294  else {
295  if(fscanf(fp, "%lu", &numPartitions) != 1) { return false; }
296  if(fscanf(fp, "%lu", &ghostSize) != 1) { return false; }
297  if(ghostSize) {
298  ghostTags.resize(2 * ghostSize);
299  for(std::size_t i = 0; i < 2 * ghostSize; i += 2) {
300  if(fscanf(fp, "%d %d", &ghostTags[i], &ghostTags[i + 1]) != 2) {
301  return false;
302  }
303  }
304  }
305  }
306 
307  model->setNumPartitions(numPartitions);
308  Msg::Info("%lu partitions", model->getNumPartitions());
309  for(std::size_t i = 0; i < 2 * ghostSize; i += 2) {
310  switch(model->getDim()) {
311  case 1: {
312  ghostEdge *ghostEntities =
313  new ghostEdge(model, ghostTags[i], ghostTags[i + 1]);
314  model->add(ghostEntities);
315  } break;
316  case 2: {
317  ghostFace *ghostEntities =
318  new ghostFace(model, ghostTags[i], ghostTags[i + 1]);
319  model->add(ghostEntities);
320  } break;
321  case 3: {
322  ghostRegion *ghostEntities =
323  new ghostRegion(model, ghostTags[i], ghostTags[i + 1]);
324  model->add(ghostEntities);
325  } break;
326  default: break;
327  }
328  }
329  }
330 
331  std::size_t numEntities[4] = {0, 0, 0, 0};
332  if(binary) {
333  if(fread(numEntities, sizeof(std::size_t), 4, fp) != 4) { return false; }
334  if(swap) SwapBytes((char *)numEntities, sizeof(std::size_t), 4);
335  }
336  else {
337  if(fscanf(fp, "%lu %lu %lu %lu", &numEntities[0], &numEntities[1],
338  &numEntities[2], &numEntities[3]) != 4) {
339  return false;
340  }
341  }
342 
343  // max length of line for ascii input file (should be large enough to handle
344  // entities with many entities on their boundary)
345  int nume = numEntities[0] + numEntities[1] + numEntities[2] + numEntities[3];
346  std::size_t strl = std::max(4096, 128 * nume);
347  char *str = new char[strl];
348 
349  if(partition)
350  Msg::Info("%d partition entit%s", nume, nume > 1 ? "ies" : "y");
351  else
352  Msg::Info("%d entit%s", nume, nume > 1 ? "ies" : "y");
353 
354  for(int dim = 0; dim < 4; dim++) {
355  for(std::size_t i = 0; i < numEntities[dim]; i++) {
356  int tag = 0, parentDim = 0, parentTag = 0;
357  std::vector<int> partitions;
358  double minX = 0., minY = 0., minZ = 0., maxX = 0., maxY = 0., maxZ = 0.;
359  if(!readMSH4EntityInfo(fp, binary, str, strl, swap, version, partition,
360  dim, tag, parentDim, parentTag, partitions, minX,
361  minY, minZ, maxX, maxY, maxZ)) {
362  delete[] str;
363  return false;
364  }
365 
366  switch(dim) {
367  case 0: {
368  GVertex *gv = model->getVertexByTag(tag);
369  if(!gv) {
370  if(partition) {
371  gv = new partitionVertex(model, tag, partitions);
372  if(parentTag)
373  static_cast<partitionVertex *>(gv)->setParentEntity(
374  model->getEntityByTag(parentDim, parentTag));
375  }
376  else {
377  gv = new discreteVertex(model, tag, minX, minY, minZ);
378  }
379  model->add(gv);
380  }
381  if(!readMSH4Physicals(model, fp, gv, binary, str, swap)) {
382  delete[] str;
383  return false;
384  }
385  } break;
386  case 1: {
387  GEdge *ge = model->getEdgeByTag(tag);
388  if(!ge) {
389  if(partition) {
390  ge = new partitionEdge(model, tag, nullptr, nullptr, partitions);
391  if(parentTag)
392  static_cast<partitionEdge *>(ge)->setParentEntity(
393  model->getEntityByTag(parentDim, parentTag));
394  }
395  else {
396  ge = new discreteEdge(model, tag, nullptr, nullptr);
397  }
398  model->add(ge);
399  }
400  if(!readMSH4Physicals(model, fp, ge, binary, str, swap)) {
401  delete[] str;
402  return false;
403  }
404  if(!readMSH4BoundingEntities(model, fp, ge, binary, str, swap)) {
405  delete[] str;
406  return false;
407  }
408  } break;
409  case 2: {
410  GFace *gf = model->getFaceByTag(tag);
411  if(!gf) {
412  if(partition) {
413  gf = new partitionFace(model, tag, partitions);
414  if(parentTag)
415  static_cast<partitionFace *>(gf)->setParentEntity(
416  model->getEntityByTag(parentDim, parentTag));
417  }
418  else {
419  gf = new discreteFace(model, tag);
420  }
421  model->add(gf);
422  }
423  if(!readMSH4Physicals(model, fp, gf, binary, str, swap)) {
424  delete[] str;
425  return false;
426  }
427  if(!readMSH4BoundingEntities(model, fp, gf, binary, str, swap)) {
428  delete[] str;
429  return false;
430  }
431  } break;
432  case 3: {
433  GRegion *gr = model->getRegionByTag(tag);
434  if(!gr) {
435  if(partition) {
436  gr = new partitionRegion(model, tag, partitions);
437  if(parentTag)
438  static_cast<partitionRegion *>(gr)->setParentEntity(
439  model->getEntityByTag(parentDim, parentTag));
440  }
441  else {
442  gr = new discreteRegion(model, tag);
443  }
444  model->add(gr);
445  }
446  if(!readMSH4Physicals(model, fp, gr, binary, str, swap)) {
447  delete[] str;
448  return false;
449  }
450  if(!readMSH4BoundingEntities(model, fp, gr, binary, str, swap)) {
451  delete[] str;
452  return false;
453  }
454  } break;
455  }
456  }
457  }
458  delete[] str;
459  return true;
460 }
461 
462 static std::pair<std::size_t, MVertex *> *
463 readMSH4Nodes(GModel *const model, FILE *fp, bool binary, bool &dense,
464  std::size_t &totalNumNodes, std::size_t &maxNodeNum, bool swap,
465  double version)
466 {
467  std::size_t numBlock = 0, minTag = 0, maxTag = 0;
468  totalNumNodes = 0;
469  maxNodeNum = 0;
470 
471  if(binary) {
472  std::size_t data[4];
473  if(fread(data, sizeof(std::size_t), 4, fp) != 4) { return nullptr; }
474  if(swap) SwapBytes((char *)data, sizeof(std::size_t), 4);
475  numBlock = data[0];
476  totalNumNodes = data[1];
477  minTag = data[2];
478  maxTag = data[3];
479  }
480  else {
481  if(version >= 4.1) {
482  if(fscanf(fp, "%lu %lu %lu %lu", &numBlock, &totalNumNodes, &minTag,
483  &maxTag) != 4) {
484  return nullptr;
485  }
486  }
487  else {
488  if(fscanf(fp, "%lu %lu", &numBlock, &totalNumNodes) != 2) {
489  return nullptr;
490  }
491  }
492  }
493 
494  std::size_t nodeRead = 0;
495  std::size_t minNodeNum = std::numeric_limits<std::size_t>::max();
496 
497  std::pair<std::size_t, MVertex *> *vertexCache =
498  new std::pair<std::size_t, MVertex *>[totalNumNodes];
499 
500  Msg::Info("%lu node%s", totalNumNodes, totalNumNodes > 1 ? "s" : "");
501  Msg::StartProgressMeter(totalNumNodes);
502 
503  for(std::size_t i = 0; i < numBlock; i++) {
504  int parametric = 0;
505  int entityTag = 0, entityDim = 0;
506  std::size_t numNodes = 0;
507 
508  if(binary) {
509  int data[3];
510  if(fread(data, sizeof(int), 3, fp) != 3) {
511  delete[] vertexCache;
512  return nullptr;
513  }
514  if(swap) SwapBytes((char *)data, sizeof(int), 3);
515  entityDim = data[0];
516  entityTag = data[1];
517  parametric = data[2];
518 
519  if(fread(&numNodes, sizeof(std::size_t), 1, fp) != 1) {
520  delete[] vertexCache;
521  return nullptr;
522  }
523  if(swap) SwapBytes((char *)&numNodes, sizeof(std::size_t), 1);
524  }
525  else {
526  if(version >= 4.1) {
527  if(fscanf(fp, "%d %d %d %lu", &entityDim, &entityTag, &parametric,
528  &numNodes) != 4) {
529  delete[] vertexCache;
530  return nullptr;
531  }
532  }
533  else {
534  if(fscanf(fp, "%d %d %d %lu", &entityTag, &entityDim, &parametric,
535  &numNodes) != 4) {
536  delete[] vertexCache;
537  return nullptr;
538  }
539  }
540  }
541 
542  GEntity *entity = model->getEntityByTag(entityDim, entityTag);
543  if(!entity) {
544  switch(entityDim) {
545  case 0: {
546  Msg::Info("Creating discrete point %d", entityTag);
547  GVertex *gv = new discreteVertex(model, entityTag);
548  GModel::current()->add(gv);
549  entity = gv;
550  break;
551  }
552  case 1: {
553  Msg::Info("Creating discrete curve %d", entityTag);
554  GEdge *ge = new discreteEdge(model, entityTag, nullptr, nullptr);
555  GModel::current()->add(ge);
556  entity = ge;
557  break;
558  }
559  case 2: {
560  Msg::Info("Creating discrete surface %d", entityTag);
561  GFace *gf = new discreteFace(model, entityTag);
562  GModel::current()->add(gf);
563  entity = gf;
564  break;
565  }
566  case 3: {
567  Msg::Info("Creating discrete volume %d", entityTag);
568  GRegion *gr = new discreteRegion(model, entityTag);
569  GModel::current()->add(gr);
570  entity = gr;
571  break;
572  }
573  default: {
574  Msg::Error("Invalid dimension %d to create discrete entity", entityDim);
575  delete[] vertexCache;
576  return nullptr;
577  }
578  }
579  }
580 
581  std::size_t n = 3;
582  if(parametric) n += entityDim;
583 
584  std::vector<std::size_t> tags(numNodes);
585  if(binary) {
586  if(fread(&tags[0], sizeof(std::size_t), numNodes, fp) != numNodes) {
587  delete[] vertexCache;
588  return nullptr;
589  }
590  if(swap) SwapBytes((char *)&tags[0], sizeof(std::size_t), numNodes);
591  std::vector<double> coord(n * numNodes);
592  if(fread(&coord[0], sizeof(double), n * numNodes, fp) != n * numNodes) {
593  delete[] vertexCache;
594  return nullptr;
595  }
596  if(swap) SwapBytes((char *)&coord[0], sizeof(double), n * numNodes);
597  std::size_t k = 0;
598  for(std::size_t j = 0; j < numNodes; j++) {
599  MVertex *mv = nullptr;
600  std::size_t tagNode = tags[j];
601  if(n == 5) {
602  mv = new MFaceVertex(coord[k], coord[k + 1], coord[k + 2], entity,
603  coord[k + 3], coord[k + 4], tagNode);
604  }
605  else if(n == 4) {
606  mv = new MEdgeVertex(coord[k], coord[k + 1], coord[k + 2], entity,
607  coord[k + 3], tagNode);
608  }
609  else {
610  mv =
611  new MVertex(coord[k], coord[k + 1], coord[k + 2], entity, tagNode);
612  }
613  k += n;
614  entity->addMeshVertex(mv);
615  mv->setEntity(entity);
616  minNodeNum = std::min(minNodeNum, tagNode);
617  maxNodeNum = std::max(maxNodeNum, tagNode);
618  vertexCache[nodeRead] = std::make_pair(tagNode, mv);
619  nodeRead++;
620  if(totalNumNodes > 100000)
621  Msg::ProgressMeter(nodeRead, true, "Reading nodes");
622  }
623  }
624  else {
625  if(version >= 4.1) {
626  for(std::size_t j = 0; j < numNodes; j++) {
627  if(fscanf(fp, "%lu", &tags[j]) != 1) {
628  delete[] vertexCache;
629  return nullptr;
630  }
631  }
632  }
633  for(std::size_t j = 0; j < numNodes; j++) {
634  std::size_t tagNode = 0;
635  if(version >= 4.1) { tagNode = tags[j]; }
636  else {
637  if(fscanf(fp, "%lu", &tagNode) != 1) {
638  delete[] vertexCache;
639  return nullptr;
640  }
641  }
642  MVertex *mv = nullptr;
643  if(n == 5) {
644  double x, y, z, u, v;
645  if(fscanf(fp, "%lf %lf %lf %lf %lf", &x, &y, &z, &u, &v) != 5) {
646  delete[] vertexCache;
647  return nullptr;
648  }
649  mv = new MFaceVertex(x, y, z, entity, u, v, tagNode);
650  }
651  else if(n == 4) {
652  double x, y, z, u;
653  if(fscanf(fp, "%lf %lf %lf %lf", &x, &y, &z, &u) != 4) {
654  delete[] vertexCache;
655  return nullptr;
656  }
657  mv = new MEdgeVertex(x, y, z, entity, u, tagNode);
658  }
659  else {
660  double x, y, z;
661  if(fscanf(fp, "%lf %lf %lf", &x, &y, &z) != 3) {
662  delete[] vertexCache;
663  return nullptr;
664  }
665  // discard extra parametric coordinates, as Gmsh does not use them
666  for(std::size_t k = 3; k < n; k++) {
667  double dummy;
668  if(fscanf(fp, "%lf", &dummy) != 1) {
669  delete[] vertexCache;
670  return nullptr;
671  }
672  }
673  mv = new MVertex(x, y, z, entity, tagNode);
674  }
675  entity->addMeshVertex(mv);
676  mv->setEntity(entity);
677  minNodeNum = std::min(minNodeNum, tagNode);
678  maxNodeNum = std::max(maxNodeNum, tagNode);
679  vertexCache[nodeRead] = std::make_pair(tagNode, mv);
680  nodeRead++;
681  if(totalNumNodes > 100000)
682  Msg::ProgressMeter(nodeRead, true, "Reading nodes");
683  }
684  }
685  }
686 
687  if(version >= 4.1) { // consistency check
688  if(minTag != minNodeNum || maxTag != maxNodeNum)
689  Msg::Warning("Min/Max node tags reported in section header are wrong: "
690  "(%d/%d) != (%d/%d)",
691  minTag, maxTag, minNodeNum, maxNodeNum);
692  }
693 
694  // if the vertex numbering is (fairly) dense, we fill the vector cache,
695  // otherwise we fill the map cache
696  if(minNodeNum == 1 && maxNodeNum == totalNumNodes) {
697  Msg::Debug("Vertex numbering is dense");
698  dense = true;
699  }
700  else if(maxNodeNum < 10 * totalNumNodes) {
701  Msg::Debug(
702  "Vertex numbering is fairly dense - still caching with a vector");
703  dense = true;
704  }
705  else {
706  Msg::Debug("Vertex numbering is not dense");
707  dense = false;
708  }
709 
710  return vertexCache;
711 }
712 
713 static std::pair<std::size_t, std::pair<MElement *, int> > *
714 readMSH4Elements(GModel *const model, FILE *fp, bool binary, bool &dense,
715  std::size_t &totalNumElements, std::size_t &maxElementNum,
716  bool swap, double version)
717 {
718  char str[10000]; // 1000 nodes for order 9 hex, 10 digits each
719  std::size_t numBlock = 0, minTag = 0, maxTag = 0;
720  totalNumElements = 0;
721  maxElementNum = 0;
722 
723  if(binary) {
724  std::size_t data[4];
725  if(fread(data, sizeof(std::size_t), 4, fp) != 4) { return nullptr; }
726  if(swap) SwapBytes((char *)data, sizeof(std::size_t), 4);
727  numBlock = data[0];
728  totalNumElements = data[1];
729  minTag = data[2];
730  maxTag = data[3];
731  }
732  else {
733  if(version >= 4.1) {
734  if(fscanf(fp, "%lu %lu %lu %lu", &numBlock, &totalNumElements, &minTag,
735  &maxTag) != 4) {
736  return nullptr;
737  }
738  }
739  else {
740  if(fscanf(fp, "%lu %lu", &numBlock, &totalNumElements) != 2) {
741  return nullptr;
742  }
743  }
744  }
745 
746  std::size_t elementRead = 0;
747  std::size_t minElementNum = std::numeric_limits<std::size_t>::max();
748 
749  std::pair<std::size_t, std::pair<MElement *, int> > *elementCache =
750  new std::pair<std::size_t, std::pair<MElement *, int> >[totalNumElements];
751  Msg::Info("%lu element%s", totalNumElements, totalNumElements > 1 ? "s" : "");
752  Msg::StartProgressMeter(totalNumElements);
753 
754  for(std::size_t i = 0; i < numBlock; i++) {
755  int entityTag = 0, entityDim = 0, elmType = 0;
756  std::size_t numElements = 0;
757 
758  if(binary) {
759  int data[3];
760  if(fread(data, sizeof(int), 3, fp) != 3) {
761  delete[] elementCache;
762  return nullptr;
763  }
764  if(swap) SwapBytes((char *)data, sizeof(int), 3);
765  entityDim = data[0];
766  entityTag = data[1];
767  elmType = data[2];
768 
769  if(fread(&numElements, sizeof(std::size_t), 1, fp) != 1) {
770  delete[] elementCache;
771  return nullptr;
772  }
773  if(swap) SwapBytes((char *)&numElements, sizeof(std::size_t), 1);
774  }
775  else {
776  if(version >= 4.1) {
777  if(fscanf(fp, "%d %d %d %lu", &entityDim, &entityTag, &elmType,
778  &numElements) != 4) {
779  delete[] elementCache;
780  return nullptr;
781  }
782  }
783  else {
784  if(fscanf(fp, "%d %d %d %lu", &entityTag, &entityDim, &elmType,
785  &numElements) != 4) {
786  delete[] elementCache;
787  return nullptr;
788  }
789  }
790  }
791 
792  GEntity *entity = model->getEntityByTag(entityDim, entityTag);
793  if(!entity) {
794  Msg::Error("Unknown entity %d of dimension %d", entityTag, entityDim);
795  delete[] elementCache;
796  return nullptr;
797  }
798  if(entity->geomType() == GEntity::GhostCurve) {
799  static_cast<ghostEdge *>(entity)->haveMesh(true);
800  }
801  else if(entity->geomType() == GEntity::GhostSurface) {
802  static_cast<ghostFace *>(entity)->haveMesh(true);
803  }
804  else if(entity->geomType() == GEntity::GhostVolume) {
805  static_cast<ghostRegion *>(entity)->haveMesh(true);
806  }
807 
808  const int numVertPerElm = MElement::getInfoMSH(elmType);
809  if(binary) {
810  std::size_t n = 1 + numVertPerElm;
811  std::vector<std::size_t> data(numElements * n);
812  if(fread(&data[0], sizeof(std::size_t), numElements * n, fp) !=
813  numElements * n) {
814  delete[] elementCache;
815  return nullptr;
816  }
817  if(swap)
818  SwapBytes((char *)&data[0], sizeof(std::size_t), numElements * n);
819 
820  std::vector<MVertex *> vertices(numVertPerElm, (MVertex *)nullptr);
821  for(std::size_t j = 0; j < numElements * n; j += n) {
822  for(int k = 0; k < numVertPerElm; k++) {
823  vertices[k] = model->getMeshVertexByTag(data[j + k + 1]);
824  if(!vertices[k]) {
825  Msg::Error("Unknown node %lu in element %lu", data[j + k + 1],
826  data[j]);
827  delete[] elementCache;
828  return nullptr;
829  }
830  }
831 
834  elmType, vertices, data[j], 0, false, 0, nullptr, nullptr, nullptr);
835  if(!element) {
836  Msg::Error("Could not create element %lu of type %d", data[j],
837  elmType);
838  delete[] elementCache;
839  return nullptr;
840  }
841  if(entity->geomType() != GEntity::GhostCurve &&
842  entity->geomType() != GEntity::GhostSurface &&
843  entity->geomType() != GEntity::GhostVolume) {
844  entity->addElement(element->getType(), element);
845  }
846 
847  minElementNum = std::min(minElementNum, data[j]);
848  maxElementNum = std::max(maxElementNum, data[j]);
849 
850  elementCache[elementRead] =
851  std::make_pair(data[j], std::make_pair(element, entityTag));
852  elementRead++;
853 
854  if(totalNumElements > 100000)
855  Msg::ProgressMeter(elementRead, true, "Reading elements");
856  }
857  }
858  else {
859  for(std::size_t j = 0; j < numElements; j++) {
860  std::size_t elmTag = 0;
861  if(fscanf(fp, "%lu", &elmTag) != 1) {
862  delete[] elementCache;
863  return nullptr;
864  }
865  if(!fgets(str, sizeof(str), fp)) {
866  delete[] elementCache;
867  return nullptr;
868  }
869 
870  std::vector<MVertex *> vertices(numVertPerElm, (MVertex *)nullptr);
871 
872  for(int k = 0; k < numVertPerElm; k++) {
873  std::size_t vertexTag = 0;
874  if(k != numVertPerElm - 1) {
875  if(sscanf(str, "%lu %[0-9- ]", &vertexTag, str) != 2) {
876  delete[] elementCache;
877  return nullptr;
878  }
879  }
880  else {
881  if(sscanf(str, "%lu", &vertexTag) != 1) {
882  delete[] elementCache;
883  return nullptr;
884  }
885  }
886 
887  vertices[k] = model->getMeshVertexByTag(vertexTag);
888  if(!vertices[k]) {
889  Msg::Error("Unknown node %lu in element %lu", vertexTag, elmTag);
890  delete[] elementCache;
891  return nullptr;
892  }
893  }
894 
897  elmType, vertices, elmTag, 0, false, 0, nullptr, nullptr, nullptr);
898  if(!element) {
899  Msg::Error("Could not create element %lu of type %d", elmTag,
900  elmType);
901  delete[] elementCache;
902  return nullptr;
903  }
904  if(entity->geomType() != GEntity::GhostCurve &&
905  entity->geomType() != GEntity::GhostSurface &&
906  entity->geomType() != GEntity::GhostVolume) {
907  entity->addElement(element->getType(), element);
908  }
909 
910  minElementNum = std::min(minElementNum, elmTag);
911  maxElementNum = std::max(maxElementNum, elmTag);
912 
913  elementCache[elementRead] =
914  std::make_pair(elmTag, std::make_pair(element, entityTag));
915  elementRead++;
916 
917  if(totalNumElements > 100000)
918  Msg::ProgressMeter(elementRead, true, "Reading elements");
919  }
920  }
921  }
922  // if the vertex numbering is dense, we fill the vector cache, otherwise we
923  // fill the map cache
924  if(minElementNum == 1 && maxElementNum == totalNumElements) {
925  Msg::Debug("Element numbering is dense");
926  dense = true;
927  }
928  else if(maxElementNum < 10 * totalNumElements) {
929  Msg::Debug(
930  "Element numbering is fairly dense - still caching with a vector");
931  dense = true;
932  }
933  else {
934  Msg::Debug("Element numbering is not dense");
935  dense = false;
936  }
937 
938  return elementCache;
939 }
940 
941 static bool readMSH4PeriodicNodes(GModel *const model, FILE *fp, bool binary,
942  bool swap, double version)
943 {
944  std::size_t numPeriodicLinks = 0;
945  if(binary) {
946  if(fread(&numPeriodicLinks, sizeof(std::size_t), 1, fp) != 1) {
947  return false;
948  }
949  if(swap) SwapBytes((char *)&numPeriodicLinks, sizeof(std::size_t), 1);
950  }
951  else {
952  if(fscanf(fp, "%lu", &numPeriodicLinks) != 1) { return false; }
953  }
954 
955  for(std::size_t i = 0; i < numPeriodicLinks; i++) {
956  int slaveDim = 0, slaveTag = 0, masterTag = 0;
957 
958  if(binary) {
959  int data[3];
960  if(fread(data, sizeof(int), 3, fp) != 3) { return false; }
961  if(swap) SwapBytes((char *)data, sizeof(int), 3);
962  slaveDim = data[0];
963  slaveTag = data[1];
964  masterTag = data[2];
965  }
966  else {
967  if(fscanf(fp, "%d %d %d", &slaveDim, &slaveTag, &masterTag) != 3) {
968  return false;
969  }
970  }
971 
972  GEntity *slave = nullptr, *master = nullptr;
973  switch(slaveDim) {
974  case 0:
975  slave = model->getVertexByTag(slaveTag);
976  master = model->getVertexByTag(masterTag);
977  break;
978  case 1:
979  slave = model->getEdgeByTag(slaveTag);
980  master = model->getEdgeByTag(masterTag);
981  break;
982  case 2:
983  slave = model->getFaceByTag(slaveTag);
984  master = model->getFaceByTag(masterTag);
985  break;
986  }
987 
988  if(!slave) {
989  Msg::Info("Could not find periodic entity %d of dimension %d", slaveTag,
990  slaveDim);
991  continue;
992  }
993  if(!master) {
994  Msg::Info("Could not find periodic source entity %d of dimension %d",
995  masterTag, slaveDim);
996  continue;
997  }
998 
999  std::size_t correspondingVertexSize = 0;
1000  if(binary) {
1001  std::size_t numAffine;
1002  if(fread(&numAffine, sizeof(std::size_t), 1, fp) != 1) { return false; }
1003  if(swap) SwapBytes((char *)&numAffine, sizeof(std::size_t), 1);
1004  if(numAffine) {
1005  std::vector<double> tfo(numAffine);
1006  if(fread(&tfo[0], sizeof(double), numAffine, fp) != numAffine) {
1007  return false;
1008  }
1009  if(swap) SwapBytes((char *)&tfo[0], sizeof(double), numAffine);
1010  slave->setMeshMaster(master, tfo);
1011  }
1012  else {
1013  slave->setMeshMaster(master);
1014  }
1015  if(fread(&correspondingVertexSize, sizeof(std::size_t), 1, fp) != 1) {
1016  return false;
1017  }
1018  if(swap)
1019  SwapBytes((char *)&correspondingVertexSize, sizeof(std::size_t), 1);
1020  }
1021  else {
1022  if(version >= 4.1) {
1023  std::size_t numAffine;
1024  if(!fscanf(fp, "%lu", &numAffine)) { return false; }
1025  if(numAffine) {
1026  std::vector<double> tfo(numAffine);
1027  for(std::size_t i = 0; i < numAffine; i++) {
1028  if(fscanf(fp, "%lf", &tfo[i]) != 1) { return false; }
1029  }
1030  slave->setMeshMaster(master, tfo);
1031  }
1032  else {
1033  slave->setMeshMaster(master);
1034  }
1035  if(fscanf(fp, "%lu", &correspondingVertexSize) != 1) { return false; }
1036  }
1037  else {
1038  char affine[256];
1039  if(!fscanf(fp, "%s", affine)) { return false; }
1040  if(!strncmp(affine, "Affine", 6)) {
1041  if(!fgets(affine, sizeof(affine), fp)) { return false; }
1042  std::vector<double> tfo(16);
1043  if(sscanf(affine,
1044  "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf "
1045  "%lf %lf %lf %lf",
1046  &tfo[0], &tfo[1], &tfo[2], &tfo[3], &tfo[4], &tfo[5],
1047  &tfo[6], &tfo[7], &tfo[8], &tfo[9], &tfo[10], &tfo[11],
1048  &tfo[12], &tfo[13], &tfo[14], &tfo[15]) != 16) {
1049  return false;
1050  }
1051  slave->setMeshMaster(master, tfo);
1052  if(fscanf(fp, "%lu", &correspondingVertexSize) != 1) { return false; }
1053  }
1054  else {
1055  slave->setMeshMaster(master);
1056  if(sscanf(affine, "%lu", &correspondingVertexSize) != 1) {
1057  return false;
1058  }
1059  }
1060  }
1061  }
1062 
1063  for(std::size_t j = 0; j < correspondingVertexSize; j++) {
1064  std::size_t v1 = 0, v2 = 0;
1065  if(binary) {
1066  std::size_t data[2];
1067  if(fread(data, sizeof(std::size_t), 2, fp) != 2) { return false; }
1068  if(swap) SwapBytes((char *)data, sizeof(std::size_t), 2);
1069  v1 = data[0];
1070  v2 = data[1];
1071  }
1072  else {
1073  if(fscanf(fp, "%lu %lu", &v1, &v2) != 2) { return false; }
1074  }
1075  MVertex *mv1 = model->getMeshVertexByTag(v1);
1076  MVertex *mv2 = model->getMeshVertexByTag(v2);
1077 
1078  if(mv1 && mv2) { slave->correspondingVertices[mv1] = mv2; }
1079  else {
1080  if(!mv1) { Msg::Info("Could not find periodic node %d", v1); }
1081  else if(!mv2) {
1082  Msg::Info("Could not find periodic node %d", v2);
1083  }
1084  }
1085  }
1086  }
1087  return true;
1088 }
1089 
1090 static bool readMSH4GhostElements(GModel *const model, FILE *fp, bool binary,
1091  bool swap)
1092 {
1093  std::size_t numGhostCells = 0;
1094  if(binary) {
1095  if(fread(&numGhostCells, sizeof(std::size_t), 1, fp) != 1) { return false; }
1096  if(swap) SwapBytes((char *)&numGhostCells, sizeof(std::size_t), 1);
1097  }
1098  else {
1099  if(fscanf(fp, "%lu", &numGhostCells) != 1) { return false; }
1100  }
1101 
1102  std::multimap<std::pair<MElement *, int>, int> ghostCells;
1103  for(std::size_t i = 0; i < numGhostCells; i++) {
1104  std::size_t elmTag = 0;
1105  int partNum = 0;
1106  std::size_t numGhostPartitions = 0;
1107  char str[1024];
1108 
1109  if(binary) {
1110  if(fread(&elmTag, sizeof(std::size_t), 1, fp) != 1) { return false; }
1111  if(swap) SwapBytes((char *)&elmTag, sizeof(std::size_t), 1);
1112  if(fread(&partNum, sizeof(int), 1, fp) != 1) { return false; }
1113  if(swap) SwapBytes((char *)&partNum, sizeof(int), 1);
1114  if(fread(&numGhostPartitions, sizeof(std::size_t), 1, fp) != 1) {
1115  return false;
1116  }
1117  if(swap) SwapBytes((char *)&numGhostPartitions, sizeof(std::size_t), 1);
1118  }
1119  else {
1120  if(fscanf(fp, "%lu %d %lu", &elmTag, &partNum, &numGhostPartitions) !=
1121  3) {
1122  return false;
1123  }
1124  if(!fgets(str, sizeof(str), fp)) { return false; }
1125  }
1126 
1127  MElement *elm = model->getMeshElementByTag(elmTag);
1128  if(!elm) {
1129  Msg::Error("No element with tag %lu", elmTag);
1130  continue;
1131  }
1132 
1133  for(std::size_t j = 0; j < numGhostPartitions; j++) {
1134  int ghostPartition = 0;
1135 
1136  if(binary) {
1137  if(fread(&ghostPartition, sizeof(int), 1, fp) != 1) { return false; }
1138  if(swap) SwapBytes((char *)&ghostPartition, sizeof(int), 1);
1139  }
1140  else {
1141  if(j == numGhostPartitions - 1) {
1142  if(sscanf(str, "%d", &ghostPartition) != 1) { return false; }
1143  }
1144  else {
1145  if(sscanf(str, "%d %[0-9- ]", &ghostPartition, str) != 2) {
1146  return false;
1147  }
1148  }
1149  }
1150 
1151  ghostCells.insert(std::make_pair(std::make_pair(elm, partNum),
1152  ghostPartition));
1153  }
1154  }
1155 
1156  std::vector<GEntity *> ghostEntities(model->getNumPartitions() + 1, nullptr);
1157  std::vector<GEntity *> entities;
1158  model->getEntities(entities);
1159  for(std::size_t i = 0; i < entities.size(); i++) {
1160  GEntity *ge = entities[i];
1161  int partNum = -1;
1162  if(ge->geomType() == GEntity::GhostCurve)
1163  partNum = static_cast<ghostEdge *>(ge)->getPartition();
1164  else if(ge->geomType() == GEntity::GhostSurface)
1165  partNum = static_cast<ghostFace *>(ge)->getPartition();
1166  else if(ge->geomType() == GEntity::GhostVolume)
1167  partNum = static_cast<ghostRegion *>(ge)->getPartition();
1168  if(partNum >= 0 && partNum < (int)ghostEntities.size())
1169  ghostEntities[partNum] = ge;
1170  }
1171 
1172  for(auto it = ghostCells.begin(); it != ghostCells.end(); ++it) {
1173  if(it->second >= (int)ghostEntities.size()) {
1174  Msg::Error("Invalid partition %d in ghost elements", it->second);
1175  return false;
1176  }
1177  GEntity *ge = ghostEntities[it->second];
1178  if(!ge) {
1179  Msg::Warning("Missing ghost entity on partition %d", it->second);
1180  }
1181  else if(ge->geomType() == GEntity::GhostCurve) {
1182  static_cast<ghostEdge *>(ge)->addElement(
1183  it->first.first->getType(), it->first.first, it->first.second);
1184  }
1185  else if(ge->geomType() == GEntity::GhostSurface) {
1186  static_cast<ghostFace *>(ge)->addElement(
1187  it->first.first->getType(), it->first.first, it->first.second);
1188  }
1189  else if(ge->geomType() == GEntity::GhostVolume) {
1190  static_cast<ghostRegion *>(ge)->addElement(
1191  it->first.first->getType(), it->first.first, it->first.second);
1192  }
1193  }
1194  return true;
1195 }
1196 
1197 static bool readMSH4Parametrizations(GModel *const model, FILE *fp, bool binary)
1198 {
1199  if(CTX::instance()->mesh.ignoreParametrizationMsh4) return true;
1200 
1201  std::size_t nParamE, nParamF;
1202 
1203  if(binary) {
1204  if(fread(&nParamE, sizeof(std::size_t), 1, fp) != 1) { return false; }
1205  if(fread(&nParamF, sizeof(std::size_t), 1, fp) != 1) { return false; }
1206  }
1207  else {
1208  if(fscanf(fp, "%lu %lu", &nParamE, &nParamF) != 2) { return false; }
1209  }
1210 
1211  // only report surface parametrizations
1212  Msg::Info("%lu parametrizations", nParamF);
1213  Msg::StartProgressMeter(nParamF);
1214 
1215  for(std::size_t edge = 0; edge < nParamE; edge++) {
1216  int tag;
1217  if(binary) {
1218  if(fread(&tag, sizeof(int), 1, fp) != 1) { return false; }
1219  }
1220  else {
1221  if(fscanf(fp, "%d", &tag) != 1) { return false; }
1222  }
1223  GEdge *ge = model->getEdgeByTag(tag);
1224  if(ge) {
1225  discreteEdge *de = dynamic_cast<discreteEdge *>(ge);
1226  if(de) {
1227  if(!de->readParametrization(fp, binary)) return false;
1228  }
1229  }
1230  }
1231 
1232  for(std::size_t face = 0; face < nParamF; face++) {
1233  int tag;
1234  if(binary) {
1235  if(fread(&tag, sizeof(int), 1, fp) != 1) { return false; }
1236  }
1237  else {
1238  if(fscanf(fp, "%d", &tag) != 1) { return false; }
1239  }
1240  GFace *gf = model->getFaceByTag(tag);
1241  if(gf) {
1242  discreteFace *df = dynamic_cast<discreteFace *>(gf);
1243  if(df) {
1244  if(!df->readParametrization(fp, binary)) return false;
1245  }
1246  }
1247  Msg::ProgressMeter(face, true, "Processing parametrizations");
1248  }
1249 
1251 
1252  return true;
1253 }
1254 
1255 int GModel::_readMSH4(const std::string &name)
1256 {
1257  bool partitioned = false;
1258  FILE *fp = Fopen(name.c_str(), "rb");
1259  if(!fp) {
1260  Msg::Error("Unable to open file '%s'", name.c_str());
1261  return 0;
1262  }
1263 
1264  char str[1024] = "x";
1265  double version = 1.0;
1266  bool binary = false, swap = false, postpro = false;
1267 
1268  while(1) {
1269  while(str[0] != '$') {
1270  if(!fgets(str, sizeof(str), fp) || feof(fp)) break;
1271  }
1272 
1273  std::string sectionName(&str[1]);
1274  std::string endSectionName = "End" + sectionName;
1275 
1276  if(feof(fp)) break;
1277 
1278  if(!strncmp(&str[1], "MeshFormat", 10)) {
1279  if(!fgets(str, sizeof(str), fp) || feof(fp)) {
1280  fclose(fp);
1281  return 0;
1282  }
1283 
1284  int format;
1285  std::size_t size;
1286  if(sscanf(str, "%lf %d %lu", &version, &format, &size) != 3) {
1287  fclose(fp);
1288  return 0;
1289  }
1290  if(format) {
1291  binary = true;
1292  Msg::Debug("Mesh is in binary format");
1293  int one;
1294  if(fread(&one, sizeof(int), 1, fp) != 1) {
1295  fclose(fp);
1296  return 0;
1297  }
1298  if(one != 1) {
1299  swap = true;
1300  Msg::Debug("Swapping bytes from binary file");
1301  }
1302  }
1303 
1304  if(binary && size != sizeof(std::size_t)) {
1305  Msg::Error("Binary file has sizeof(size_t) = %d, not matching "
1306  "machine sizeof(size_t) = %d",
1307  size, sizeof(std::size_t));
1308  return false;
1309  }
1310  if(binary && version < 4.1) {
1311  Msg::Error("Can only read MSH 4.0 format in ASCII mode");
1312  return false;
1313  }
1314  }
1315  else if(!strncmp(&str[1], "PhysicalNames", 13)) {
1316  if(!fgets(str, sizeof(str), fp) || feof(fp)) {
1317  fclose(fp);
1318  return 0;
1319  }
1320  int numPhysicalNames = 0;
1321  if(sscanf(str, "%d", &numPhysicalNames) != 1) {
1322  fclose(fp);
1323  return 0;
1324  }
1325  std::vector<GModel::piter> iterators;
1326  getInnerPhysicalNamesIterators(iterators);
1327  for(int i = 0; i < numPhysicalNames; i++) {
1328  int dim = 0, tag = 0;
1329  if(fscanf(fp, "%d %d", &dim, &tag) != 2) {
1330  fclose(fp);
1331  return 0;
1332  }
1333  char name[256];
1334  if(!fgets(name, sizeof(name), fp)) {
1335  fclose(fp);
1336  return 0;
1337  }
1338  std::string physicalName = ExtractDoubleQuotedString(name, 256);
1339  if(physicalName.size())
1340  iterators[dim] =
1341  setPhysicalName(iterators[dim], physicalName, dim, tag);
1342  }
1343  }
1344  else if(!strncmp(&str[1], "Entities", 8)) {
1345  if(!readMSH4Entities(this, fp, false, binary, swap, version)) {
1346  Msg::Error("Could not read entities");
1347  fclose(fp);
1348  return 0;
1349  }
1350  }
1351  else if(!strncmp(&str[1], "PartitionedEntities", 19)) {
1352  if(!readMSH4Entities(this, fp, true, binary, swap, version)) {
1353  Msg::Error("Could not read partitioned entities");
1354  fclose(fp);
1355  return 0;
1356  }
1357  partitioned = true;
1358  }
1359  else if(!strncmp(&str[1], "Nodes", 5)) {
1360  _vertexVectorCache.clear();
1361  _vertexMapCache.clear();
1362  bool dense = false;
1363  std::size_t totalNumNodes = 0, maxNodeNum;
1364  std::pair<std::size_t, MVertex *> *vertexCache = readMSH4Nodes(
1365  this, fp, binary, dense, totalNumNodes, maxNodeNum, swap, version);
1367  if(!vertexCache) {
1368  Msg::Error("Could not read nodes");
1369  fclose(fp);
1370  return false;
1371  }
1372  if(dense) {
1373  _vertexVectorCache.resize(maxNodeNum + 1, nullptr);
1374  for(std::size_t i = 0; i < totalNumNodes; i++) {
1375  if(!_vertexVectorCache[vertexCache[i].first]) {
1376  _vertexVectorCache[vertexCache[i].first] = vertexCache[i].second;
1377  }
1378  else {
1379  Msg::Info("Skipping duplicate node %d", vertexCache[i].first);
1380  }
1381  }
1382  }
1383  else {
1384  for(std::size_t i = 0; i < totalNumNodes; i++) {
1385  if(_vertexMapCache.count(vertexCache[i].first) == 0) {
1386  _vertexMapCache[vertexCache[i].first] = vertexCache[i].second;
1387  }
1388  else {
1389  Msg::Info("Skipping duplicate node %d", vertexCache[i].first);
1390  }
1391  }
1392  }
1393  delete[] vertexCache;
1394  }
1395  else if(!strncmp(&str[1], "Elements", 8)) {
1396  bool dense = false;
1397  std::size_t totalNumElements = 0, maxElementNum = 0;
1398  std::pair<std::size_t, std::pair<MElement *, int> > *elementCache =
1399  readMSH4Elements(this, fp, binary, dense, totalNumElements,
1400  maxElementNum, swap, version);
1402  if(!elementCache) {
1403  Msg::Error("Could not read elements");
1404  fclose(fp);
1405  return 0;
1406  }
1407  if(dense) {
1408  _elementVectorCache.resize(maxElementNum + 1, std::make_pair(nullptr, 0));
1409  for(std::size_t i = 0; i < totalNumElements; i++) {
1410  if(!_elementVectorCache[elementCache[i].first].first) {
1411  _elementVectorCache[elementCache[i].first] = elementCache[i].second;
1412  }
1413  else {
1414  Msg::Info("Skipping duplicate element %d", elementCache[i].first);
1415  }
1416  }
1417  }
1418  else {
1419  for(std::size_t i = 0; i < totalNumElements; i++) {
1420  if(_elementMapCache.count(elementCache[i].first) == 0) {
1421  _elementMapCache[elementCache[i].first] = elementCache[i].second;
1422  }
1423  else {
1424  Msg::Info("Skipping duplicate element %d", elementCache[i].first);
1425  }
1426  }
1427  }
1428  delete[] elementCache;
1429  }
1430  else if(!strncmp(&str[1], "Periodic", 8)) {
1431  if(!readMSH4PeriodicNodes(this, fp, binary, swap, version)) {
1432  Msg::Error("Could not read periodic section");
1433  fclose(fp);
1434  return 0;
1435  }
1436  }
1437  else if(!strncmp(&str[1], "GhostElements", 13)) {
1438  if(!readMSH4GhostElements(this, fp, binary, swap)) {
1439  Msg::Error("Could not read ghost elements");
1440  fclose(fp);
1441  return 0;
1442  }
1443  }
1444  else if(!strncmp(&str[1], "Parametrizations", 16)) {
1445  if(!readMSH4Parametrizations(this, fp, binary)) {
1446  Msg::Error("Could not read parametrizations");
1447  fclose(fp);
1448  return 0;
1449  }
1450  }
1451  else if(!strncmp(&str[1], "NodeData", 8) ||
1452  !strncmp(&str[1], "ElementData", 11) ||
1453  !strncmp(&str[1], "ElementNodeData", 15)) {
1454  postpro = true;
1455  break;
1456  }
1457  else if(strlen(&str[1]) > 0){
1458  sectionName.pop_back();
1459  Msg::Info("Storing section $%s as model attribute", sectionName.c_str());
1460  std::vector<std::string> section;
1461  while(1) {
1462  if(!fgets(str, sizeof(str), fp) || feof(fp) ||
1463  !strncmp(&str[1], endSectionName.c_str(), endSectionName.size())) {
1464  break;
1465  }
1466  std::string s(str);
1467  if(s.back() == '\n') s.pop_back();
1468  if(s.back() == '\r') s.pop_back();
1469  section.push_back(s);
1470  }
1471  _attributes[sectionName] = section;
1472  }
1473 
1474  while(strncmp(&str[1], endSectionName.c_str(), endSectionName.size())) {
1475  if(!fgets(str, sizeof(str), fp) || feof(fp)) { break; }
1476  }
1477  str[0] = 'a';
1478  }
1479 
1480  fclose(fp);
1481 
1482  if(partitioned) {
1483  // This part is added to ensure the compatibility between the new
1484  // partitioning and the old one.
1485  std::vector<GEntity *> entities;
1486  getEntities(entities);
1487  for(std::size_t i = 0; i < entities.size(); i++) {
1488  if(entities[i]->geomType() == GEntity::PartitionPoint) {
1489  partitionVertex *pv = static_cast<partitionVertex *>(entities[i]);
1490  if(pv->numPartitions() == 1) {
1491  const int part = pv->getPartition(0);
1492  for(std::size_t j = 0; j < pv->getNumMeshElements(); j++) {
1493  pv->getMeshElement(j)->setPartition(part);
1494  }
1495  }
1496  }
1497  else if(entities[i]->geomType() == GEntity::PartitionCurve) {
1498  partitionEdge *pe = static_cast<partitionEdge *>(entities[i]);
1499  if(pe->numPartitions() == 1) {
1500  const int part = pe->getPartition(0);
1501  for(std::size_t j = 0; j < pe->getNumMeshElements(); j++) {
1502  pe->getMeshElement(j)->setPartition(part);
1503  }
1504  }
1505  }
1506  else if(entities[i]->geomType() == GEntity::PartitionSurface) {
1507  partitionFace *pf = static_cast<partitionFace *>(entities[i]);
1508  if(pf->numPartitions() == 1) {
1509  const int part = pf->getPartition(0);
1510  for(std::size_t j = 0; j < pf->getNumMeshElements(); j++) {
1511  pf->getMeshElement(j)->setPartition(part);
1512  }
1513  }
1514  }
1515  else if(entities[i]->geomType() == GEntity::PartitionVolume) {
1516  partitionRegion *pr = static_cast<partitionRegion *>(entities[i]);
1517  if(pr->numPartitions() == 1) {
1518  const int part = pr->getPartition(0);
1519  for(std::size_t j = 0; j < pr->getNumMeshElements(); j++) {
1520  pr->getMeshElement(j)->setPartition(part);
1521  }
1522  }
1523  }
1524  }
1525  }
1526 
1527  return postpro ? 2 : 1;
1528 }
1529 
1530 static void writeMSH4Physicals(FILE *fp, GEntity *const entity, bool binary)
1531 {
1532  if(binary) {
1533  std::vector<int> phys = entity->getPhysicalEntities();
1534  std::size_t phySize = phys.size();
1535  fwrite(&phySize, sizeof(std::size_t), 1, fp);
1536  for(std::size_t i = 0; i < phys.size(); i++) {
1537  int phy = phys[i];
1538  fwrite(&phy, sizeof(int), 1, fp);
1539  }
1540  }
1541  else {
1542  std::vector<int> phys = entity->getPhysicalEntities();
1543  fprintf(fp, "%lu", phys.size());
1544  for(std::size_t i = 0; i < phys.size(); i++) {
1545  fprintf(fp, " %d", phys[i]);
1546  }
1547  fprintf(fp, " ");
1548  }
1549 }
1550 
1551 static void writeMSH4BoundingBox(SBoundingBox3d boundBox, FILE *fp,
1552  double scalingFactor, bool binary, int dim,
1553  double version)
1554 {
1555  double bb[6] = {0., 0., 0., 0., 0., 0.};
1556  if(!boundBox.empty()) {
1557  boundBox *= scalingFactor;
1558  bb[0] = boundBox.min().x();
1559  bb[1] = boundBox.min().y();
1560  bb[2] = boundBox.min().z();
1561  bb[3] = boundBox.max().x();
1562  bb[4] = boundBox.max().y();
1563  bb[5] = boundBox.max().z();
1564  }
1565  if(binary) { fwrite(bb, sizeof(double), (dim > 0) ? 6 : 3, fp); }
1566  else {
1567  std::size_t n = (version < 4.1 || dim > 0) ? 6 : 3;
1568  for(std::size_t i = 0; i < n; i++) fprintf(fp, "%.16g ", bb[i]);
1569  }
1570 }
1571 
1572 static void writeMSH4Entities(GModel *const model, FILE *fp, bool partition,
1573  bool binary, double scalingFactor, double version,
1574  std::map<GEntity*, SBoundingBox3d> *entityBounds)
1575 {
1576  std::set<GEntity *, GEntityPtrFullLessThan> ghost;
1577  std::set<GRegion *, GEntityPtrLessThan> regions;
1578  std::set<GFace *, GEntityPtrLessThan> faces;
1579  std::set<GEdge *, GEntityPtrLessThan> edges;
1580  std::set<GVertex *, GEntityPtrLessThan> vertices;
1581 
1582  if(partition) {
1583  for(auto it = model->firstVertex(); it != model->lastVertex(); ++it) {
1584  if(CTX::instance()->mesh.saveWithoutOrphans && (*it)->isOrphan())
1585  continue;
1586  if((*it)->geomType() == GEntity::PartitionPoint) vertices.insert(*it);
1587  }
1588  for(auto it = model->firstEdge(); it != model->lastEdge(); ++it) {
1589  if(CTX::instance()->mesh.saveWithoutOrphans && (*it)->isOrphan())
1590  continue;
1591  if((*it)->geomType() == GEntity::PartitionCurve) edges.insert(*it);
1592  if((*it)->geomType() == GEntity::GhostCurve) ghost.insert(*it);
1593  }
1594  for(auto it = model->firstFace(); it != model->lastFace(); ++it) {
1595  if(CTX::instance()->mesh.saveWithoutOrphans && (*it)->isOrphan())
1596  continue;
1597  if((*it)->geomType() == GEntity::PartitionSurface) faces.insert(*it);
1598  if((*it)->geomType() == GEntity::GhostSurface) ghost.insert(*it);
1599  }
1600  for(auto it = model->firstRegion(); it != model->lastRegion(); ++it) {
1601  if((*it)->geomType() == GEntity::PartitionVolume) regions.insert(*it);
1602  if((*it)->geomType() == GEntity::GhostVolume) ghost.insert(*it);
1603  }
1604  }
1605  else {
1606  for(auto it = model->firstVertex(); it != model->lastVertex(); ++it) {
1607  if(CTX::instance()->mesh.saveWithoutOrphans && (*it)->isOrphan())
1608  continue;
1609  if((*it)->geomType() != GEntity::PartitionPoint) vertices.insert(*it);
1610  }
1611  for(auto it = model->firstEdge(); it != model->lastEdge(); ++it) {
1612  if(CTX::instance()->mesh.saveWithoutOrphans && (*it)->isOrphan())
1613  continue;
1614  if((*it)->geomType() != GEntity::PartitionCurve &&
1615  (*it)->geomType() != GEntity::GhostCurve)
1616  edges.insert(*it);
1617  }
1618  for(auto it = model->firstFace(); it != model->lastFace(); ++it) {
1619  if(CTX::instance()->mesh.saveWithoutOrphans && (*it)->isOrphan())
1620  continue;
1621  if((*it)->geomType() != GEntity::PartitionSurface &&
1622  (*it)->geomType() != GEntity::GhostSurface)
1623  faces.insert(*it);
1624  }
1625  for(auto it = model->firstRegion(); it != model->lastRegion(); ++it) {
1626  if((*it)->geomType() != GEntity::PartitionVolume &&
1627  (*it)->geomType() != GEntity::GhostVolume)
1628  regions.insert(*it);
1629  }
1630  }
1631 
1632  if(partition)
1633  fprintf(fp, "$PartitionedEntities\n");
1634  else
1635  fprintf(fp, "$Entities\n");
1636 
1637  if(binary) {
1638  if(partition) {
1639  std::size_t numPartitions = model->getNumPartitions();
1640  fwrite(&numPartitions, sizeof(std::size_t), 1, fp);
1641 
1642  // write the ghostentities' tag
1643  std::size_t ghostSize = ghost.size();
1644  std::vector<int> tags;
1645  if(ghostSize) {
1646  tags.resize(2 * ghostSize);
1647  int index = 0;
1648  for(auto it = ghost.begin(); it != ghost.end(); ++it) {
1649  if((*it)->geomType() == GEntity::GhostCurve) {
1650  tags[index] = (*it)->tag();
1651  tags[++index] = static_cast<ghostEdge *>(*it)->getPartition();
1652  }
1653  else if((*it)->geomType() == GEntity::GhostSurface) {
1654  tags[index] = (*it)->tag();
1655  tags[++index] = static_cast<ghostFace *>(*it)->getPartition();
1656  }
1657  else if((*it)->geomType() == GEntity::GhostVolume) {
1658  tags[index] = (*it)->tag();
1659  tags[++index] = static_cast<ghostRegion *>(*it)->getPartition();
1660  }
1661  index++;
1662  }
1663  }
1664  fwrite(&ghostSize, sizeof(std::size_t), 1, fp);
1665  if(ghostSize) { fwrite(&tags[0], sizeof(int), 2 * ghostSize, fp); }
1666  }
1667  std::size_t verticesSize = vertices.size();
1668  std::size_t edgesSize = edges.size();
1669  std::size_t facesSize = faces.size();
1670  std::size_t regionsSize = regions.size();
1671  fwrite(&verticesSize, sizeof(std::size_t), 1, fp);
1672  fwrite(&edgesSize, sizeof(std::size_t), 1, fp);
1673  fwrite(&facesSize, sizeof(std::size_t), 1, fp);
1674  fwrite(&regionsSize, sizeof(std::size_t), 1, fp);
1675 
1676  for(auto it = vertices.begin(); it != vertices.end(); ++it) {
1677  int entityTag = (*it)->tag();
1678  fwrite(&entityTag, sizeof(int), 1, fp);
1679  if(partition) {
1680  partitionVertex *pv = static_cast<partitionVertex *>(*it);
1681  int parentEntityDim = 0, parentEntityTag = 0;
1682  if(pv->getParentEntity()) {
1683  parentEntityDim = pv->getParentEntity()->dim();
1684  parentEntityTag = pv->getParentEntity()->tag();
1685  }
1686  fwrite(&parentEntityDim, sizeof(int), 1, fp);
1687  fwrite(&parentEntityTag, sizeof(int), 1, fp);
1688  std::vector<int> partitions(pv->getPartitions().begin(),
1689  pv->getPartitions().end()); // FIXME
1690  std::size_t numPart = partitions.size();
1691  fwrite(&numPart, sizeof(std::size_t), 1, fp);
1692  fwrite(&partitions[0], sizeof(int), partitions.size(), fp);
1693  }
1694  SBoundingBox3d bb = entityBounds ? (*entityBounds)[*it] : (*it)->bounds();
1695  writeMSH4BoundingBox(bb, fp, scalingFactor, binary, 0, version);
1696  writeMSH4Physicals(fp, *it, binary);
1697  }
1698 
1699  for(auto it = edges.begin(); it != edges.end(); ++it) {
1700  std::vector<GVertex *> vertices;
1701  std::vector<int> ori;
1702  if((*it)->getBeginVertex()) {
1703  vertices.push_back((*it)->getBeginVertex());
1704  ori.push_back(1);
1705  }
1706  if((*it)->getEndVertex()) { // convention that the end vertex is negative
1707  vertices.push_back((*it)->getEndVertex());
1708  ori.push_back(-1);
1709  }
1710  std::size_t verticesSize = vertices.size();
1711  int entityTag = (*it)->tag();
1712  fwrite(&entityTag, sizeof(int), 1, fp);
1713  if(partition) {
1714  partitionEdge *pe = static_cast<partitionEdge *>(*it);
1715  int parentEntityDim = 0, parentEntityTag = 0;
1716  if(pe->getParentEntity()) {
1717  parentEntityDim = pe->getParentEntity()->dim();
1718  parentEntityTag = pe->getParentEntity()->tag();
1719  }
1720  fwrite(&parentEntityDim, sizeof(int), 1, fp);
1721  fwrite(&parentEntityTag, sizeof(int), 1, fp);
1722  std::vector<int> partitions(pe->getPartitions().begin(),
1723  pe->getPartitions().end()); // FIXME
1724  std::size_t numPart = partitions.size();
1725  fwrite(&numPart, sizeof(std::size_t), 1, fp);
1726  fwrite(&partitions[0], sizeof(int), partitions.size(), fp);
1727  }
1728  SBoundingBox3d bb = entityBounds ? (*entityBounds)[*it] : (*it)->bounds();
1729  writeMSH4BoundingBox(bb, fp, scalingFactor, binary, 1, version);
1730  writeMSH4Physicals(fp, *it, binary);
1731  fwrite(&verticesSize, sizeof(std::size_t), 1, fp);
1732  int oriI = 0;
1733  for(auto itv = vertices.begin(); itv != vertices.end(); itv++) {
1734  int brepTag = ori[oriI] * (*itv)->tag();
1735  fwrite(&brepTag, sizeof(int), 1, fp);
1736  oriI++;
1737  }
1738  }
1739 
1740  for(auto it = faces.begin(); it != faces.end(); ++it) {
1741  std::vector<GEdge *> const &edges = (*it)->edges();
1742  std::vector<int> const &ori = (*it)->edgeOrientations();
1743  std::size_t edgesSize = edges.size();
1744  int entityTag = (*it)->tag();
1745  fwrite(&entityTag, sizeof(int), 1, fp);
1746  if(partition) {
1747  partitionFace *pf = static_cast<partitionFace *>(*it);
1748  int parentEntityDim = 0, parentEntityTag = 0;
1749  if(pf->getParentEntity()) {
1750  parentEntityDim = pf->getParentEntity()->dim();
1751  parentEntityTag = pf->getParentEntity()->tag();
1752  }
1753  fwrite(&parentEntityDim, sizeof(int), 1, fp);
1754  fwrite(&parentEntityTag, sizeof(int), 1, fp);
1755  std::vector<int> partitions(pf->getPartitions().begin(),
1756  pf->getPartitions().end()); // FIXME
1757  std::size_t numPart = partitions.size();
1758  fwrite(&numPart, sizeof(std::size_t), 1, fp);
1759  fwrite(&partitions[0], sizeof(int), partitions.size(), fp);
1760  }
1761  SBoundingBox3d bb = entityBounds ? (*entityBounds)[*it] : (*it)->bounds();
1762  writeMSH4BoundingBox(bb, fp, scalingFactor, binary, 2, version);
1763  writeMSH4Physicals(fp, *it, binary);
1764  fwrite(&edgesSize, sizeof(std::size_t), 1, fp);
1765  std::vector<int> tags, signs;
1766  for(auto ite = edges.begin(); ite != edges.end(); ite++)
1767  tags.push_back((*ite)->tag());
1768 
1769  signs.insert(signs.end(), ori.begin(), ori.end());
1770 
1771  if(tags.size() == signs.size()) {
1772  for(std::size_t i = 0; i < tags.size(); i++)
1773  tags[i] *= (signs[i] > 0 ? 1 : -1);
1774  }
1775  for(std::size_t i = 0; i < tags.size(); i++) {
1776  int brepTag = tags[i];
1777  fwrite(&brepTag, sizeof(int), 1, fp);
1778  }
1779  }
1780 
1781  for(auto it = regions.begin(); it != regions.end(); ++it) {
1782  std::vector<GFace *> faces = (*it)->faces();
1783  std::vector<int> const &ori = (*it)->faceOrientations();
1784  std::size_t facesSize = faces.size();
1785  int entityTag = (*it)->tag();
1786  fwrite(&entityTag, sizeof(int), 1, fp);
1787  if(partition) {
1788  partitionRegion *pr = static_cast<partitionRegion *>(*it);
1789  int parentEntityDim = 0, parentEntityTag = 0;
1790  if(pr->getParentEntity()) {
1791  parentEntityDim = pr->getParentEntity()->dim();
1792  parentEntityTag = pr->getParentEntity()->tag();
1793  }
1794  fwrite(&parentEntityDim, sizeof(int), 1, fp);
1795  fwrite(&parentEntityTag, sizeof(int), 1, fp);
1796  std::vector<int> partitions(pr->getPartitions().begin(),
1797  pr->getPartitions().end()); // FIXME
1798  std::size_t numPart = partitions.size();
1799  fwrite(&numPart, sizeof(std::size_t), 1, fp);
1800  fwrite(&partitions[0], sizeof(int), partitions.size(), fp);
1801  }
1802  SBoundingBox3d bb = entityBounds ? (*entityBounds)[*it] : (*it)->bounds();
1803  writeMSH4BoundingBox(bb, fp, scalingFactor, binary, 3, version);
1804  writeMSH4Physicals(fp, *it, binary);
1805  fwrite(&facesSize, sizeof(std::size_t), 1, fp);
1806  std::vector<int> tags, signs;
1807  for(auto itf = faces.begin(); itf != faces.end(); itf++)
1808  tags.push_back((*itf)->tag());
1809  for(auto itf = ori.begin(); itf != ori.end(); itf++)
1810  signs.push_back(*itf);
1811  if(tags.size() == signs.size()) {
1812  for(std::size_t i = 0; i < tags.size(); i++)
1813  tags[i] *= (signs[i] > 0 ? 1 : -1);
1814  }
1815  for(std::size_t i = 0; i < tags.size(); i++) {
1816  int brepTag = tags[i];
1817  fwrite(&brepTag, sizeof(int), 1, fp);
1818  }
1819  }
1820  fprintf(fp, "\n");
1821  }
1822  else {
1823  if(partition) {
1824  fprintf(fp, "%lu\n", model->getNumPartitions());
1825 
1826  // write the ghostentities' tag
1827  std::size_t ghostSize = ghost.size();
1828  std::vector<int> tags;
1829  if(ghostSize) {
1830  tags.resize(2 * ghostSize);
1831  int index = 0;
1832  for(auto it = ghost.begin(); it != ghost.end(); ++it) {
1833  if((*it)->geomType() == GEntity::GhostCurve) {
1834  tags[index] = (*it)->tag();
1835  tags[++index] = static_cast<ghostEdge *>(*it)->getPartition();
1836  }
1837  else if((*it)->geomType() == GEntity::GhostSurface) {
1838  tags[index] = (*it)->tag();
1839  tags[++index] = static_cast<ghostFace *>(*it)->getPartition();
1840  }
1841  else if((*it)->geomType() == GEntity::GhostVolume) {
1842  tags[index] = (*it)->tag();
1843  tags[++index] = static_cast<ghostRegion *>(*it)->getPartition();
1844  }
1845  index++;
1846  }
1847  }
1848  fprintf(fp, "%lu\n", ghostSize);
1849  if(ghostSize) {
1850  for(std::size_t i = 0; i < 2 * ghostSize; i += 2) {
1851  fprintf(fp, "%d %d\n", tags[i], tags[i + 1]);
1852  }
1853  }
1854  }
1855  fprintf(fp, "%lu %lu %lu %lu\n", vertices.size(), edges.size(),
1856  faces.size(), regions.size());
1857 
1858  for(auto it = vertices.begin(); it != vertices.end(); ++it) {
1859  fprintf(fp, "%d ", (*it)->tag());
1860  if(partition) {
1861  partitionVertex *pv = static_cast<partitionVertex *>(*it);
1862  int parentEntityDim = 0, parentEntityTag = 0;
1863  if(pv->getParentEntity()) {
1864  parentEntityDim = pv->getParentEntity()->dim();
1865  parentEntityTag = pv->getParentEntity()->tag();
1866  }
1867  fprintf(fp, "%d %d ", parentEntityDim, parentEntityTag);
1868  std::vector<int> partitions(pv->getPartitions().begin(),
1869  pv->getPartitions().end()); // FIXME
1870  fprintf(fp, "%lu ", partitions.size());
1871  for(std::size_t i = 0; i < partitions.size(); i++)
1872  fprintf(fp, "%d ", partitions[i]);
1873  }
1874  SBoundingBox3d bb = entityBounds ? (*entityBounds)[*it] : (*it)->bounds();
1875  writeMSH4BoundingBox(bb, fp, scalingFactor, binary, 0, version);
1876  writeMSH4Physicals(fp, *it, binary);
1877  fprintf(fp, "\n");
1878  }
1879 
1880  for(auto it = edges.begin(); it != edges.end(); ++it) {
1881  std::vector<GVertex *> vertices;
1882  std::vector<int> ori;
1883  if((*it)->getBeginVertex()) {
1884  vertices.push_back((*it)->getBeginVertex());
1885  ori.push_back(1);
1886  }
1887  if((*it)->getEndVertex()) { // I use the convention that the end vertex is
1888  // negative
1889  vertices.push_back((*it)->getEndVertex());
1890  ori.push_back(-1);
1891  }
1892  fprintf(fp, "%d ", (*it)->tag());
1893  if(partition) {
1894  partitionEdge *pe = static_cast<partitionEdge *>(*it);
1895  int parentEntityDim = 0, parentEntityTag = 0;
1896  if(pe->getParentEntity()) {
1897  parentEntityDim = pe->getParentEntity()->dim();
1898  parentEntityTag = pe->getParentEntity()->tag();
1899  }
1900  fprintf(fp, "%d %d ", parentEntityDim, parentEntityTag);
1901  std::vector<int> partitions(pe->getPartitions().begin(),
1902  pe->getPartitions().end()); // FIXME
1903  fprintf(fp, "%lu ", partitions.size());
1904  for(std::size_t i = 0; i < partitions.size(); i++)
1905  fprintf(fp, "%d ", partitions[i]);
1906  }
1907  SBoundingBox3d bb = entityBounds ? (*entityBounds)[*it] : (*it)->bounds();
1908  writeMSH4BoundingBox(bb, fp, scalingFactor, binary, 1, version);
1909  writeMSH4Physicals(fp, *it, binary);
1910  fprintf(fp, "%lu ", vertices.size());
1911  int oriI = 0;
1912  for(auto itv = vertices.begin(); itv != vertices.end(); itv++) {
1913  fprintf(fp, "%d ", ori[oriI] * (*itv)->tag());
1914  oriI++;
1915  }
1916  fprintf(fp, "\n");
1917  }
1918 
1919  for(auto it = faces.begin(); it != faces.end(); ++it) {
1920  std::vector<GEdge *> const &edges = (*it)->edges();
1921  std::vector<int> const &ori = (*it)->edgeOrientations();
1922  fprintf(fp, "%d ", (*it)->tag());
1923  if(partition) {
1924  partitionFace *pf = static_cast<partitionFace *>(*it);
1925  int parentEntityDim = 0, parentEntityTag = 0;
1926  if(pf->getParentEntity()) {
1927  parentEntityDim = pf->getParentEntity()->dim();
1928  parentEntityTag = pf->getParentEntity()->tag();
1929  }
1930  fprintf(fp, "%d %d ", parentEntityDim, parentEntityTag);
1931  std::vector<int> partitions(pf->getPartitions().begin(),
1932  pf->getPartitions().end()); // FIXME
1933  fprintf(fp, "%lu ", partitions.size());
1934  for(std::size_t i = 0; i < partitions.size(); i++)
1935  fprintf(fp, "%d ", partitions[i]);
1936  }
1937  SBoundingBox3d bb = entityBounds ? (*entityBounds)[*it] : (*it)->bounds();
1938  writeMSH4BoundingBox(bb, fp, scalingFactor, binary, 2, version);
1939  writeMSH4Physicals(fp, *it, binary);
1940  fprintf(fp, "%lu ", edges.size());
1941  std::vector<int> tags, signs;
1942  for(auto ite = edges.begin(); ite != edges.end(); ite++)
1943  tags.push_back((*ite)->tag());
1944  for(auto ite = ori.begin(); ite != ori.end(); ite++)
1945  signs.push_back(*ite);
1946  if(tags.size() == signs.size()) {
1947  for(std::size_t i = 0; i < tags.size(); i++)
1948  tags[i] *= (signs[i] > 0 ? 1 : -1);
1949  }
1950  for(std::size_t i = 0; i < tags.size(); i++) fprintf(fp, "%d ", tags[i]);
1951  fprintf(fp, "\n");
1952  }
1953 
1954  for(auto it = regions.begin(); it != regions.end(); ++it) {
1955  std::vector<GFace *> const &faces = (*it)->faces();
1956  std::vector<int> const &ori = (*it)->faceOrientations();
1957  fprintf(fp, "%d ", (*it)->tag());
1958  if(partition) {
1959  partitionRegion *pr = static_cast<partitionRegion *>(*it);
1960  int parentEntityDim = 0, parentEntityTag = 0;
1961  if(pr->getParentEntity()) {
1962  parentEntityDim = pr->getParentEntity()->dim();
1963  parentEntityTag = pr->getParentEntity()->tag();
1964  }
1965  fprintf(fp, "%d %d ", parentEntityDim, parentEntityTag);
1966 
1967  fprintf(fp, "%lu ", pr->getPartitions().size());
1968 
1969  for(auto const partition : pr->getPartitions()) {
1970  fprintf(fp, "%d ", partition);
1971  }
1972  }
1973  SBoundingBox3d bb = entityBounds ? (*entityBounds)[*it] : (*it)->bounds();
1974  writeMSH4BoundingBox(bb, fp, scalingFactor, binary, 3, version);
1975  writeMSH4Physicals(fp, *it, binary);
1976  fprintf(fp, "%lu ", faces.size());
1977 
1978  std::vector<int> tags(faces.size());
1979  std::transform(begin(faces), end(faces), begin(tags),
1980  [](const GFace *const face) { return face->tag(); });
1981 
1982  std::vector<int> signs(ori.begin(), ori.end());
1983 
1984  if(tags.size() == signs.size()) {
1985  for(std::size_t i = 0; i < tags.size(); i++)
1986  tags[i] *= (signs[i] > 0 ? 1 : -1);
1987  }
1988 
1989  for(auto const tag : tags) { fprintf(fp, "%d ", tag); }
1990  fprintf(fp, "\n");
1991  }
1992  }
1993 
1994  if(partition)
1995  fprintf(fp, "$EndPartitionedEntities\n");
1996  else
1997  fprintf(fp, "$EndEntities\n");
1998 }
1999 
2000 static void writeMSH4EntityNodes(GEntity *ge, FILE *fp, bool binary,
2001  int saveParametric, double scalingFactor,
2002  double version)
2003 {
2004  int parametric = saveParametric;
2005  if(ge->dim() != 1 && ge->dim() != 2)
2006  parametric = 0; // Gmsh only stores parametric coordinates for dim 1 and 2
2007 
2008  if(binary) {
2009  int entityDim = ge->dim();
2010  int entityTag = ge->tag();
2011  std::size_t numVerts = ge->getNumMeshVertices();
2012  fwrite(&entityDim, sizeof(int), 1, fp);
2013  fwrite(&entityTag, sizeof(int), 1, fp);
2014  fwrite(&parametric, sizeof(int), 1, fp);
2015  fwrite(&numVerts, sizeof(std::size_t), 1, fp);
2016  }
2017  else {
2018  fprintf(fp, "%d %d %d %lu\n", (version >= 4.1) ? ge->dim() : ge->tag(),
2019  (version >= 4.1) ? ge->tag() : ge->dim(), parametric,
2020  ge->getNumMeshVertices());
2021  }
2022 
2023  std::size_t N = ge->getNumMeshVertices();
2024  std::size_t n = 3;
2025  if(parametric) n += ge->dim();
2026 
2027  if(binary) {
2028  std::vector<size_t> tags(N);
2029  for(std::size_t i = 0; i < N; i++) tags[i] = ge->getMeshVertex(i)->getNum();
2030  fwrite(&tags[0], sizeof(std::size_t), N, fp);
2031  std::vector<double> coord(n * N);
2032  std::size_t j = 0;
2033  for(std::size_t i = 0; i < N; i++) {
2034  MVertex *mv = ge->getMeshVertex(i);
2035  coord[j++] = mv->x() * scalingFactor;
2036  coord[j++] = mv->y() * scalingFactor;
2037  coord[j++] = mv->z() * scalingFactor;
2038  if(n >= 4) mv->getParameter(0, coord[j++]);
2039  if(n == 5) mv->getParameter(1, coord[j++]);
2040  }
2041  fwrite(&coord[0], sizeof(double), n * N, fp);
2042  }
2043  else {
2044  if(version >= 4.1) {
2045  for(std::size_t i = 0; i < N; i++)
2046  fprintf(fp, "%lu\n", ge->getMeshVertex(i)->getNum());
2047  }
2048  for(std::size_t i = 0; i < N; i++) {
2049  MVertex *mv = ge->getMeshVertex(i);
2050  double x = mv->x() * scalingFactor;
2051  double y = mv->y() * scalingFactor;
2052  double z = mv->z() * scalingFactor;
2053  if(version < 4.1) fprintf(fp, "%lu ", mv->getNum());
2054  if(n == 5) {
2055  double u, v;
2056  mv->getParameter(0, u);
2057  mv->getParameter(1, v);
2058  fprintf(fp, "%.16g %.16g %.16g %.16g %.16g\n", x, y, z, u, v);
2059  }
2060  else if(n == 4) {
2061  double u;
2062  mv->getParameter(0, u);
2063  fprintf(fp, "%.16g %.16g %.16g %.16g\n", x, y, z, u);
2064  }
2065  else {
2066  fprintf(fp, "%.16g %.16g %.16g\n", x, y, z);
2067  }
2068  }
2069  }
2070 }
2071 
2072 static std::size_t
2073 getAdditionalEntities(std::set<GRegion *, GEntityPtrLessThan> &regions,
2074  std::set<GFace *, GEntityPtrLessThan> &faces,
2075  std::set<GEdge *, GEntityPtrLessThan> &edges,
2076  std::set<GVertex *, GEntityPtrLessThan> &vertices)
2077 {
2078  std::size_t numVertices = 0;
2079 
2080  for(auto it = vertices.begin(); it != vertices.end(); ++it) {
2081  numVertices += (*it)->getNumMeshVertices();
2082  }
2083 
2084  for(auto it = edges.begin(); it != edges.end(); ++it) {
2085  numVertices += (*it)->getNumMeshVertices();
2086  for(std::size_t i = 0; i < (*it)->getNumMeshElements(); i++) {
2087  for(std::size_t j = 0; j < (*it)->getMeshElement(i)->getNumVertices();
2088  j++) {
2089  if((*it)->getMeshElement(i)->getVertex(j)->onWhat() != (*it)) {
2090  GEntity *entity = (*it)->getMeshElement(i)->getVertex(j)->onWhat();
2091 
2092  switch(entity->dim()) {
2093  case 0:
2094  if(vertices.find(static_cast<GVertex *>(entity)) ==
2095  vertices.end()) {
2096  vertices.insert(static_cast<GVertex *>(entity));
2097  numVertices += entity->getNumMeshVertices();
2098  }
2099  break;
2100  case 1:
2101  if(edges.find(static_cast<GEdge *>(entity)) == edges.end()) {
2102  edges.insert(static_cast<GEdge *>(entity));
2103  numVertices += entity->getNumMeshVertices();
2104  }
2105  break;
2106  case 2:
2107  if(faces.find(static_cast<GFace *>(entity)) == faces.end()) {
2108  faces.insert(static_cast<GFace *>(entity));
2109  numVertices += entity->getNumMeshVertices();
2110  }
2111  break;
2112  case 3:
2113  if(regions.find(static_cast<GRegion *>(entity)) == regions.end()) {
2114  regions.insert(static_cast<GRegion *>(entity));
2115  numVertices += entity->getNumMeshVertices();
2116  }
2117  break;
2118  default: break;
2119  }
2120  }
2121  }
2122  }
2123  }
2124 
2125  for(auto it = faces.begin(); it != faces.end(); ++it) {
2126  numVertices += (*it)->getNumMeshVertices();
2127  for(std::size_t i = 0; i < (*it)->getNumMeshElements(); i++) {
2128  for(std::size_t j = 0; j < (*it)->getMeshElement(i)->getNumVertices();
2129  j++) {
2130  if((*it)->getMeshElement(i)->getVertex(j)->onWhat() != (*it)) {
2131  GEntity *entity = (*it)->getMeshElement(i)->getVertex(j)->onWhat();
2132 
2133  switch(entity->dim()) {
2134  case 0:
2135  if(vertices.find(static_cast<GVertex *>(entity)) ==
2136  vertices.end()) {
2137  vertices.insert(static_cast<GVertex *>(entity));
2138  numVertices += entity->getNumMeshVertices();
2139  }
2140  break;
2141  case 1:
2142  if(edges.find(static_cast<GEdge *>(entity)) == edges.end()) {
2143  edges.insert(static_cast<GEdge *>(entity));
2144  numVertices += entity->getNumMeshVertices();
2145  }
2146  break;
2147  case 2:
2148  if(faces.find(static_cast<GFace *>(entity)) == faces.end()) {
2149  faces.insert(static_cast<GFace *>(entity));
2150  numVertices += entity->getNumMeshVertices();
2151  }
2152  break;
2153  case 3:
2154  if(regions.find(static_cast<GRegion *>(entity)) == regions.end()) {
2155  regions.insert(static_cast<GRegion *>(entity));
2156  numVertices += entity->getNumMeshVertices();
2157  }
2158  break;
2159  default: break;
2160  }
2161  }
2162  }
2163  }
2164  }
2165 
2166  for(auto it = regions.begin(); it != regions.end(); ++it) {
2167  numVertices += (*it)->getNumMeshVertices();
2168  for(std::size_t i = 0; i < (*it)->getNumMeshElements(); i++) {
2169  for(std::size_t j = 0; j < (*it)->getMeshElement(i)->getNumVertices();
2170  j++) {
2171  if((*it)->getMeshElement(i)->getVertex(j)->onWhat() != (*it)) {
2172  GEntity *entity = (*it)->getMeshElement(i)->getVertex(j)->onWhat();
2173 
2174  switch(entity->dim()) {
2175  case 0:
2176  if(vertices.find(static_cast<GVertex *>(entity)) ==
2177  vertices.end()) {
2178  vertices.insert(static_cast<GVertex *>(entity));
2179  numVertices += entity->getNumMeshVertices();
2180  }
2181  break;
2182  case 1:
2183  if(edges.find(static_cast<GEdge *>(entity)) == edges.end()) {
2184  edges.insert(static_cast<GEdge *>(entity));
2185  numVertices += entity->getNumMeshVertices();
2186  }
2187  break;
2188  case 2:
2189  if(faces.find(static_cast<GFace *>(entity)) == faces.end()) {
2190  faces.insert(static_cast<GFace *>(entity));
2191  numVertices += entity->getNumMeshVertices();
2192  }
2193  break;
2194  case 3:
2195  if(regions.find(static_cast<GRegion *>(entity)) == regions.end()) {
2196  regions.insert(static_cast<GRegion *>(entity));
2197  numVertices += entity->getNumMeshVertices();
2198  }
2199  break;
2200  default: break;
2201  }
2202  }
2203  }
2204  }
2205  }
2206 
2207  return numVertices;
2208 }
2209 
2210 static void
2211 getEntitiesToSave(GModel *const model, bool partitioned,
2212  int partitionToSave, bool saveAll,
2213  std::set<GRegion *, GEntityPtrLessThan> &regions,
2214  std::set<GFace *, GEntityPtrLessThan> &faces,
2215  std::set<GEdge *, GEntityPtrLessThan> &edges,
2216  std::set<GVertex *, GEntityPtrLessThan> &vertices)
2217 {
2218  if(partitioned) {
2219  for(auto it = model->firstVertex(); it != model->lastVertex(); ++it) {
2220  if(CTX::instance()->mesh.saveWithoutOrphans && (*it)->isOrphan())
2221  continue;
2222  if((*it)->geomType() == GEntity::PartitionPoint) {
2223  partitionVertex *pv = static_cast<partitionVertex *>(*it);
2224  if(!partitionToSave ||
2225  std::find(pv->getPartitions().begin(), pv->getPartitions().end(),
2226  partitionToSave) != pv->getPartitions().end())
2227  vertices.insert(pv);
2228  }
2229  }
2230  for(auto it = model->firstEdge(); it != model->lastEdge(); ++it) {
2231  if(CTX::instance()->mesh.saveWithoutOrphans && (*it)->isOrphan())
2232  continue;
2233  if((*it)->geomType() == GEntity::PartitionCurve) {
2234  partitionEdge *pe = static_cast<partitionEdge *>(*it);
2235  if(!partitionToSave ||
2236  std::find(pe->getPartitions().begin(), pe->getPartitions().end(),
2237  partitionToSave) != pe->getPartitions().end())
2238  edges.insert(pe);
2239  }
2240  else if((*it)->geomType() == GEntity::GhostCurve) {
2241  ghostEdge *ge = static_cast<ghostEdge *>(*it);
2242  if(ge->getPartition() == partitionToSave)
2243  edges.insert(ge);
2244  }
2245  }
2246  for(auto it = model->firstFace(); it != model->lastFace(); ++it) {
2247  if(CTX::instance()->mesh.saveWithoutOrphans && (*it)->isOrphan())
2248  continue;
2249  if((*it)->geomType() == GEntity::PartitionSurface) {
2250  partitionFace *pf = static_cast<partitionFace *>(*it);
2251  if(!partitionToSave ||
2252  std::find(pf->getPartitions().begin(), pf->getPartitions().end(),
2253  partitionToSave) != pf->getPartitions().end())
2254  faces.insert(pf);
2255  }
2256  else if((*it)->geomType() == GEntity::GhostSurface) {
2257  ghostFace *gf = static_cast<ghostFace *>(*it);
2258  if(gf->getPartition() == partitionToSave)
2259  faces.insert(gf);
2260  }
2261  }
2262  for(auto it = model->firstRegion(); it != model->lastRegion(); ++it) {
2263  if((*it)->geomType() == GEntity::PartitionVolume) {
2264  partitionRegion *pr = static_cast<partitionRegion *>(*it);
2265  if(!partitionToSave ||
2266  std::find(pr->getPartitions().begin(), pr->getPartitions().end(),
2267  partitionToSave) != pr->getPartitions().end())
2268  regions.insert(pr);
2269  }
2270  else if((*it)->geomType() == GEntity::GhostVolume) {
2271  ghostRegion *gr = static_cast<ghostRegion *>(*it);
2272  if(gr->getPartition() == partitionToSave)
2273  regions.insert(gr);
2274  }
2275  }
2276  }
2277  else {
2278  for(auto it = model->firstVertex(); it != model->lastVertex(); ++it) {
2279  if(CTX::instance()->mesh.saveWithoutOrphans && (*it)->isOrphan())
2280  continue;
2281  if((*it)->geomType() != GEntity::PartitionPoint &&
2282  (saveAll || (!saveAll && (*it)->getPhysicalEntities().size() != 0)))
2283  vertices.insert(*it);
2284  }
2285  for(auto it = model->firstEdge(); it != model->lastEdge(); ++it) {
2286  if(CTX::instance()->mesh.saveWithoutOrphans && (*it)->isOrphan())
2287  continue;
2288  if((*it)->geomType() != GEntity::PartitionCurve &&
2289  (saveAll || (!saveAll && (*it)->getPhysicalEntities().size() != 0) ||
2290  (*it)->geomType() == GEntity::GhostCurve))
2291  edges.insert(*it);
2292  }
2293  for(auto it = model->firstFace(); it != model->lastFace(); ++it) {
2294  if(CTX::instance()->mesh.saveWithoutOrphans && (*it)->isOrphan())
2295  continue;
2296  if((*it)->geomType() != GEntity::PartitionSurface &&
2297  (saveAll || (!saveAll && (*it)->getPhysicalEntities().size() != 0) ||
2298  (*it)->geomType() == GEntity::GhostSurface))
2299  faces.insert(*it);
2300  }
2301  for(auto it = model->firstRegion(); it != model->lastRegion(); ++it) {
2302  if((*it)->geomType() != GEntity::PartitionVolume &&
2303  (saveAll || (!saveAll && (*it)->getPhysicalEntities().size() != 0) ||
2304  (*it)->geomType() == GEntity::GhostVolume))
2305  regions.insert(*it);
2306  }
2307  }
2308 }
2309 
2310 static void writeMSH4Nodes(GModel *const model, FILE *fp, bool partitioned,
2311  int partitionToSave, bool binary, int saveParametric,
2312  double scalingFactor, bool saveAll, double version)
2313 {
2314  std::set<GRegion *, GEntityPtrLessThan> regions;
2315  std::set<GFace *, GEntityPtrLessThan> faces;
2316  std::set<GEdge *, GEntityPtrLessThan> edges;
2317  std::set<GVertex *, GEntityPtrLessThan> vertices;
2318  getEntitiesToSave(model, partitioned, partitionToSave, saveAll, regions,
2319  faces, edges, vertices);
2320 
2321  std::size_t numNodes = (saveAll && !partitioned &&
2323  model->getNumMeshVertices() :
2324  getAdditionalEntities(regions, faces, edges, vertices);
2325 
2326  if(!numNodes) return;
2327 
2328  fprintf(fp, "$Nodes\n");
2329 
2330  std::size_t minTag = std::numeric_limits<std::size_t>::max(), maxTag = 0;
2331  for(auto it = vertices.begin(); it != vertices.end(); ++it) {
2332  for(std::size_t i = 0; i < (*it)->getNumMeshVertices(); i++) {
2333  minTag = std::min(minTag, (*it)->getMeshVertex(i)->getNum());
2334  maxTag = std::max(maxTag, (*it)->getMeshVertex(i)->getNum());
2335  }
2336  }
2337  for(auto it = edges.begin(); it != edges.end(); ++it) {
2338  for(std::size_t i = 0; i < (*it)->getNumMeshVertices(); i++) {
2339  minTag = std::min(minTag, (*it)->getMeshVertex(i)->getNum());
2340  maxTag = std::max(maxTag, (*it)->getMeshVertex(i)->getNum());
2341  }
2342  }
2343  for(auto it = faces.begin(); it != faces.end(); ++it) {
2344  for(std::size_t i = 0; i < (*it)->getNumMeshVertices(); i++) {
2345  minTag = std::min(minTag, (*it)->getMeshVertex(i)->getNum());
2346  maxTag = std::max(maxTag, (*it)->getMeshVertex(i)->getNum());
2347  }
2348  }
2349  for(auto it = regions.begin(); it != regions.end(); ++it) {
2350  for(std::size_t i = 0; i < (*it)->getNumMeshVertices(); i++) {
2351  minTag = std::min(minTag, (*it)->getMeshVertex(i)->getNum());
2352  maxTag = std::max(maxTag, (*it)->getMeshVertex(i)->getNum());
2353  }
2354  }
2355 
2356  if(binary) {
2357  std::size_t numSection =
2358  vertices.size() + edges.size() + faces.size() + regions.size();
2359  fwrite(&numSection, sizeof(std::size_t), 1, fp);
2360  fwrite(&numNodes, sizeof(std::size_t), 1, fp);
2361  fwrite(&minTag, sizeof(std::size_t), 1, fp);
2362  fwrite(&maxTag, sizeof(std::size_t), 1, fp);
2363  }
2364  else {
2365  if(version >= 4.1) {
2366  fprintf(fp, "%lu %lu %lu %lu\n",
2367  vertices.size() + edges.size() + faces.size() + regions.size(),
2368  numNodes, minTag, maxTag);
2369  }
2370  else {
2371  fprintf(fp, "%lu %lu\n",
2372  vertices.size() + edges.size() + faces.size() + regions.size(),
2373  numNodes);
2374  }
2375  }
2376 
2377  for(auto it = vertices.begin(); it != vertices.end(); ++it) {
2378  writeMSH4EntityNodes(*it, fp, binary, saveParametric, scalingFactor,
2379  version);
2380  }
2381  for(auto it = edges.begin(); it != edges.end(); ++it) {
2382  writeMSH4EntityNodes(*it, fp, binary, saveParametric, scalingFactor,
2383  version);
2384  }
2385  for(auto it = faces.begin(); it != faces.end(); ++it) {
2386  writeMSH4EntityNodes(*it, fp, binary, saveParametric, scalingFactor,
2387  version);
2388  }
2389  for(auto it = regions.begin(); it != regions.end(); ++it) {
2390  writeMSH4EntityNodes(*it, fp, binary, saveParametric, scalingFactor,
2391  version);
2392  }
2393 
2394  if(binary) fprintf(fp, "\n");
2395 
2396  fprintf(fp, "$EndNodes\n");
2397 }
2398 
2399 static void writeMSH4Elements(GModel *const model, FILE *fp, bool partitioned,
2400  int partitionToSave, bool binary, bool saveAll,
2401  double version)
2402 {
2403  std::set<GRegion *, GEntityPtrLessThan> regions;
2404  std::set<GFace *, GEntityPtrLessThan> faces;
2405  std::set<GEdge *, GEntityPtrLessThan> edges;
2406  std::set<GVertex *, GEntityPtrLessThan> vertices;
2407  getEntitiesToSave(model, partitioned, partitionToSave, saveAll, regions,
2408  faces, edges, vertices);
2409 
2410  std::map<std::pair<int, int>, std::vector<MElement *> > elementsByType[4];
2411  std::size_t numElements = 0;
2412 
2413  for(auto it = vertices.begin(); it != vertices.end(); ++it) {
2414  if(!saveAll && (*it)->physicals.size() == 0) continue;
2415 
2416  numElements += (*it)->points.size();
2417  for(std::size_t i = 0; i < (*it)->points.size(); i++) {
2418  std::pair<int, int> p((*it)->tag(), (*it)->points[i]->getTypeForMSH());
2419  elementsByType[0][p].push_back((*it)->points[i]);
2420  }
2421  }
2422 
2423  for(auto it = edges.begin(); it != edges.end(); ++it) {
2424  if(!saveAll && (*it)->physicals.size() == 0 &&
2425  (*it)->geomType() != GEntity::GhostCurve)
2426  continue;
2427 
2428  numElements += (*it)->lines.size();
2429  for(std::size_t i = 0; i < (*it)->lines.size(); i++) {
2430  std::pair<int, int> p((*it)->tag(), (*it)->lines[i]->getTypeForMSH());
2431  elementsByType[1][p].push_back((*it)->lines[i]);
2432  }
2433  }
2434 
2435  for(auto it = faces.begin(); it != faces.end(); ++it) {
2436  if(!saveAll && (*it)->physicals.size() == 0 &&
2437  (*it)->geomType() != GEntity::GhostSurface)
2438  continue;
2439 
2440  numElements += (*it)->triangles.size();
2441  for(std::size_t i = 0; i < (*it)->triangles.size(); i++) {
2442  std::pair<int, int> p((*it)->tag(), (*it)->triangles[i]->getTypeForMSH());
2443  elementsByType[2][p].push_back((*it)->triangles[i]);
2444  }
2445  numElements += (*it)->quadrangles.size();
2446  for(std::size_t i = 0; i < (*it)->quadrangles.size(); i++) {
2447  std::pair<int, int> p((*it)->tag(),
2448  (*it)->quadrangles[i]->getTypeForMSH());
2449  elementsByType[2][p].push_back((*it)->quadrangles[i]);
2450  }
2451  }
2452 
2453  for(auto it = regions.begin(); it != regions.end(); ++it) {
2454  if(!saveAll && (*it)->physicals.size() == 0 &&
2455  (*it)->geomType() != GEntity::GhostVolume)
2456  continue;
2457 
2458  numElements += (*it)->tetrahedra.size();
2459  for(std::size_t i = 0; i < (*it)->tetrahedra.size(); i++) {
2460  std::pair<int, int> p((*it)->tag(),
2461  (*it)->tetrahedra[i]->getTypeForMSH());
2462  elementsByType[3][p].push_back((*it)->tetrahedra[i]);
2463  }
2464  numElements += (*it)->hexahedra.size();
2465  for(std::size_t i = 0; i < (*it)->hexahedra.size(); i++) {
2466  std::pair<int, int> p((*it)->tag(), (*it)->hexahedra[i]->getTypeForMSH());
2467  elementsByType[3][p].push_back((*it)->hexahedra[i]);
2468  }
2469  numElements += (*it)->prisms.size();
2470  for(std::size_t i = 0; i < (*it)->prisms.size(); i++) {
2471  std::pair<int, int> p((*it)->tag(), (*it)->prisms[i]->getTypeForMSH());
2472  elementsByType[3][p].push_back((*it)->prisms[i]);
2473  }
2474  numElements += (*it)->pyramids.size();
2475  for(std::size_t i = 0; i < (*it)->pyramids.size(); i++) {
2476  std::pair<int, int> p((*it)->tag(), (*it)->pyramids[i]->getTypeForMSH());
2477  elementsByType[3][p].push_back((*it)->pyramids[i]);
2478  }
2479  numElements += (*it)->trihedra.size();
2480  for(std::size_t i = 0; i < (*it)->trihedra.size(); i++) {
2481  std::pair<int, int> p((*it)->tag(), (*it)->trihedra[i]->getTypeForMSH());
2482  elementsByType[3][p].push_back((*it)->trihedra[i]);
2483  }
2484  }
2485 
2486  if(!numElements) return;
2487 
2488  fprintf(fp, "$Elements\n");
2489 
2490  std::size_t numSection = 0;
2491  for(int dim = 0; dim <= 3; dim++) numSection += elementsByType[dim].size();
2492 
2493  std::size_t minTag = std::numeric_limits<std::size_t>::max(), maxTag = 0;
2494  for(int dim = 0; dim <= 3; dim++) {
2495  for(auto it = elementsByType[dim].begin(); it != elementsByType[dim].end();
2496  ++it) {
2497  for(std::size_t i = 0; i < it->second.size(); i++) {
2498  minTag = std::min(minTag, it->second[i]->getNum());
2499  maxTag = std::max(maxTag, it->second[i]->getNum());
2500  }
2501  }
2502  }
2503 
2504  if(binary) {
2505  fwrite(&numSection, sizeof(std::size_t), 1, fp);
2506  fwrite(&numElements, sizeof(std::size_t), 1, fp);
2507  fwrite(&minTag, sizeof(std::size_t), 1, fp);
2508  fwrite(&maxTag, sizeof(std::size_t), 1, fp);
2509  }
2510  else {
2511  if(version >= 4.1)
2512  fprintf(fp, "%lu %lu %lu %lu\n", numSection, numElements, minTag, maxTag);
2513  else
2514  fprintf(fp, "%lu %lu\n", numSection, numElements);
2515  }
2516 
2517  for(int dim = 0; dim <= 3; dim++) {
2518  for(auto it = elementsByType[dim].begin(); it != elementsByType[dim].end();
2519  ++it) {
2520  int entityTag = it->first.first;
2521  int elmType = it->first.second;
2522  std::size_t numElm = it->second.size();
2523  if(binary) {
2524  fwrite(&dim, sizeof(int), 1, fp);
2525  fwrite(&entityTag, sizeof(int), 1, fp);
2526  fwrite(&elmType, sizeof(int), 1, fp);
2527  fwrite(&numElm, sizeof(std::size_t), 1, fp);
2528  }
2529  else {
2530  fprintf(fp, "%d %d %d %lu\n", (version >= 4.1) ? dim : entityTag,
2531  (version >= 4.1) ? entityTag : dim, elmType, numElm);
2532  }
2533 
2534  std::size_t N = it->second.size();
2535  if(binary) {
2536  const int numVertPerElm = MElement::getInfoMSH(elmType);
2537  std::size_t n = 1 + numVertPerElm;
2538  std::vector<std::size_t> tags(N * n);
2539  std::size_t k = 0;
2540  for(std::size_t i = 0; i < N; i++) {
2541  MElement *e = it->second[i];
2542  tags[k] = e->getNum();
2543  for(int j = 0; j < numVertPerElm; j++) {
2544  tags[k + 1 + j] = e->getVertex(j)->getNum();
2545  }
2546  k += n;
2547  }
2548  fwrite(&tags[0], sizeof(std::size_t), N * n, fp);
2549  }
2550  else {
2551  for(std::size_t i = 0; i < N; i++) {
2552  MElement *e = it->second[i];
2553  fprintf(fp, "%lu ", e->getNum());
2554  for(std::size_t i = 0; i < e->getNumVertices(); i++) {
2555  fprintf(fp, "%lu ", e->getVertex(i)->getNum());
2556  }
2557  fprintf(fp, "\n");
2558  }
2559  }
2560  }
2561  }
2562 
2563  if(binary) fprintf(fp, "\n");
2564 
2565  fprintf(fp, "$EndElements\n");
2566 }
2567 
2568 static void writeMSH4PeriodicNodes(GModel *const model, FILE *fp,
2569  bool binary, double version)
2570 {
2571  // To avoid saving correspondences bwteen nodes that are not saved (either in
2572  // the same file or not at all, e.g. in the partitioned case, or simply if
2573  // some physical entities are not defined), we could only apply the code below
2574  // to the entities returned by getEntitiesForNodes().
2575 
2576  // The current choice is to save everything, and not complain if a node is not
2577  // found when reading the file. This should be reevaluated at some point.
2578 
2579  std::size_t count = 0;
2580  std::vector<GEntity *> entities;
2581  model->getEntities(entities);
2582  for(std::size_t i = 0; i < entities.size(); i++)
2583  if(entities[i]->getMeshMaster() != entities[i]) count++;
2584 
2585  if(!count) return;
2586 
2587  fprintf(fp, "$Periodic\n");
2588 
2589  if(binary) { fwrite(&count, sizeof(std::size_t), 1, fp); }
2590  else {
2591  fprintf(fp, "%lu\n", count);
2592  }
2593 
2594  for(std::size_t i = 0; i < entities.size(); i++) {
2595  GEntity *g_slave = entities[i];
2596  GEntity *g_master = g_slave->getMeshMaster();
2597 
2598  if(g_slave != g_master) {
2599  std::map<MVertex *, MVertex *, MVertexPtrLessThan> corrVert;
2600  corrVert.insert(g_slave->correspondingVertices.begin(),
2601  g_slave->correspondingVertices.end());
2602  if(CTX::instance()->mesh.hoSavePeriodic)
2603  corrVert.insert(g_slave->correspondingHighOrderVertices.begin(),
2604  g_slave->correspondingHighOrderVertices.end());
2605 
2606  if(binary) {
2607  int gSlaveDim = g_slave->dim();
2608  int gSlaveTag = g_slave->tag();
2609  int gMasterTag = g_master->tag();
2610  fwrite(&gSlaveDim, sizeof(int), 1, fp);
2611  fwrite(&gSlaveTag, sizeof(int), 1, fp);
2612  fwrite(&gMasterTag, sizeof(int), 1, fp);
2613 
2614  if(g_slave->affineTransform.size() == 16) {
2615  std::size_t numAffine = 16;
2616  fwrite(&numAffine, sizeof(std::size_t), 1, fp);
2617  for(int j = 0; j < 16; j++) {
2618  double value = g_slave->affineTransform[j];
2619  fwrite(&value, sizeof(double), 1, fp);
2620  }
2621  }
2622  else {
2623  std::size_t numAffine = 0;
2624  fwrite(&numAffine, sizeof(std::size_t), 1, fp);
2625  }
2626 
2627  std::size_t corrVertSize = corrVert.size();
2628  fwrite(&corrVertSize, sizeof(std::size_t), 1, fp);
2629 
2630  for(auto it = corrVert.begin(); it != corrVert.end(); ++it) {
2631  std::size_t numFirst = it->first->getNum();
2632  std::size_t numSecond = it->second->getNum();
2633  fwrite(&numFirst, sizeof(std::size_t), 1, fp);
2634  fwrite(&numSecond, sizeof(std::size_t), 1, fp);
2635  }
2636  }
2637  else {
2638  fprintf(fp, "%d %d %d\n", g_slave->dim(), g_slave->tag(),
2639  g_master->tag());
2640 
2641  if(version >= 4.1) {
2642  if(g_slave->affineTransform.size() == 16) {
2643  fprintf(fp, "16");
2644  for(int j = 0; j < 16; j++)
2645  fprintf(fp, " %.16g", g_slave->affineTransform[j]);
2646  fprintf(fp, "\n");
2647  }
2648  else {
2649  fprintf(fp, "0\n");
2650  }
2651  }
2652  else {
2653  if(g_slave->affineTransform.size() == 16) {
2654  fprintf(fp, "Affine");
2655  for(int j = 0; j < 16; j++)
2656  fprintf(fp, " %.16g", g_slave->affineTransform[j]);
2657  fprintf(fp, "\n");
2658  }
2659  }
2660 
2661  fprintf(fp, "%lu\n", corrVert.size());
2662 
2663  for(auto it = corrVert.begin(); it != corrVert.end(); ++it) {
2664  fprintf(fp, "%lu %lu\n", it->first->getNum(), it->second->getNum());
2665  }
2666  }
2667  }
2668  }
2669 
2670  if(binary) fprintf(fp, "\n");
2671  fprintf(fp, "$EndPeriodic\n");
2672 }
2673 
2674 static void writeMSH4GhostCells(GModel *const model, FILE *fp,
2675  int partitionToSave, bool binary)
2676 {
2677  std::vector<GEntity *> entities;
2678  model->getEntities(entities);
2679  std::map<MElement *, std::vector<int> > ghostCells;
2680 
2681  for(std::size_t i = 0; i < entities.size(); i++) {
2682  std::map<MElement *, int> ghostElements;
2683  int partition;
2684 
2685  if(entities[i]->geomType() == GEntity::GhostCurve) {
2686  ghostElements = static_cast<ghostEdge *>(entities[i])->getGhostCells();
2687  partition = static_cast<ghostEdge *>(entities[i])->getPartition();
2688  }
2689  else if(entities[i]->geomType() == GEntity::GhostSurface) {
2690  ghostElements = static_cast<ghostFace *>(entities[i])->getGhostCells();
2691  partition = static_cast<ghostFace *>(entities[i])->getPartition();
2692  }
2693  else if(entities[i]->geomType() == GEntity::GhostVolume) {
2694  ghostElements = static_cast<ghostRegion *>(entities[i])->getGhostCells();
2695  partition = static_cast<ghostRegion *>(entities[i])->getPartition();
2696  }
2697 
2698  if(!partitionToSave || partitionToSave == partition) {
2699  for(auto it = ghostElements.begin(); it != ghostElements.end(); ++it) {
2700  if(ghostCells[it->first].size() == 0)
2701  ghostCells[it->first].push_back(it->second);
2702  ghostCells[it->first].push_back(partition);
2703  }
2704  }
2705  }
2706 
2707  if(ghostCells.size() != 0) {
2708  fprintf(fp, "$GhostElements\n");
2709  if(binary) {
2710  std::size_t ghostCellsSize = ghostCells.size();
2711  fwrite(&ghostCellsSize, sizeof(std::size_t), 1, fp);
2712 
2713  for(auto it = ghostCells.begin(); it != ghostCells.end(); ++it) {
2714  std::size_t elmTag = it->first->getNum();
2715  int partNum = it->second[0];
2716  std::size_t numGhostPartitions = it->second.size() - 1;
2717  fwrite(&elmTag, sizeof(std::size_t), 1, fp);
2718  fwrite(&partNum, sizeof(int), 1, fp);
2719  fwrite(&numGhostPartitions, sizeof(std::size_t), 1, fp);
2720  for(std::size_t i = 1; i < it->second.size(); i++) {
2721  fwrite(&it->second[i], sizeof(int), 1, fp);
2722  }
2723  }
2724  fprintf(fp, "\n");
2725  }
2726  else {
2727  fprintf(fp, "%ld\n", ghostCells.size());
2728 
2729  for(auto it = ghostCells.begin(); it != ghostCells.end(); ++it) {
2730  fprintf(fp, "%lu %d %ld", it->first->getNum(), it->second[0],
2731  it->second.size() - 1);
2732  for(std::size_t i = 1; i < it->second.size(); i++) {
2733  fprintf(fp, " %d", it->second[i]);
2734  }
2735  fprintf(fp, "\n");
2736  }
2737  }
2738  fprintf(fp, "$EndGhostElements\n");
2739  }
2740 }
2741 
2742 static void writeMSH4Parametrizations(GModel *const model, FILE *fp,
2743  bool binary)
2744 {
2745  std::size_t nParamE = 0, nParamF = 0;
2746 
2747  for(auto it = model->firstEdge(); it != model->lastEdge(); ++it) {
2748  discreteEdge *de = dynamic_cast<discreteEdge *>(*it);
2749  if(de && de->haveParametrization()) { nParamE++; }
2750  }
2751  for(auto it = model->firstFace(); it != model->lastFace(); ++it) {
2752  discreteFace *df = dynamic_cast<discreteFace *>(*it);
2753  if(df && df->haveParametrization()) { nParamF++; }
2754  }
2755 
2756  if(!nParamE && !nParamF) return;
2757 
2758  fprintf(fp, "$Parametrizations\n");
2759 
2760  if(binary) {
2761  fwrite(&nParamE, sizeof(std::size_t), 1, fp);
2762  fwrite(&nParamF, sizeof(std::size_t), 1, fp);
2763  }
2764  else {
2765  fprintf(fp, "%lu %lu\n", nParamE, nParamF);
2766  }
2767 
2768  for(auto it = model->firstEdge(); it != model->lastEdge(); ++it) {
2769  discreteEdge *de = dynamic_cast<discreteEdge *>(*it);
2770  if(de && de->haveParametrization()) {
2771  int t = de->tag();
2772  if(binary)
2773  fwrite(&t, sizeof(int), 1, fp);
2774  else
2775  fprintf(fp, "%d\n", t);
2776  de->writeParametrization(fp, binary);
2777  }
2778  }
2779  for(auto it = model->firstFace(); it != model->lastFace(); ++it) {
2780  discreteFace *df = dynamic_cast<discreteFace *>(*it);
2781  if(df && df->haveParametrization()) {
2782  int t = df->tag();
2783  if(binary)
2784  fwrite(&t, sizeof(int), 1, fp);
2785  else
2786  fprintf(fp, "%d\n", t);
2787  df->writeParametrization(fp, binary);
2788  }
2789  }
2790 
2791  if(binary) fprintf(fp, "\n");
2792 
2793  fprintf(fp, "$EndParametrizations\n");
2794 }
2795 
2796 int GModel::_writeMSH4(const std::string &name, double version, bool binary,
2797  bool saveAll, bool saveParametric, double scalingFactor,
2798  bool append, int partitionToSave,
2799  std::map<GEntity*, SBoundingBox3d> *entityBounds)
2800 {
2801  FILE *fp = nullptr;
2802  if(append)
2803  fp = Fopen(name.c_str(), binary ? "ab" : "a");
2804  else
2805  fp = Fopen(name.c_str(), binary ? "wb" : "w");
2806 
2807  if(!fp) {
2808  Msg::Error("Unable to open file '%s'", name.c_str());
2809  return 0;
2810  }
2811 
2812  if(version < 4.1 && binary) {
2813  Msg::Error("Can only write MSH 4.0 format in ASCII mode");
2814  return 0;
2815  }
2816 
2817  // if there are no physicals we save all the elements
2818  if(noPhysicalGroups()) saveAll = true;
2819 
2820  // header
2821  fprintf(fp, "$MeshFormat\n");
2822  fprintf(fp, "%g %d %lu\n", version, (binary ? 1 : 0), sizeof(std::size_t));
2823  if(binary) {
2824  int one = 1;
2825  fwrite(&one, sizeof(int), 1, fp); // swapping byte
2826  fprintf(fp, "\n");
2827  }
2828  fprintf(fp, "$EndMeshFormat\n");
2829 
2830  // physicals
2831  if(numPhysicalNames() > 0) {
2832  fprintf(fp, "$PhysicalNames\n");
2833  fprintf(fp, "%d\n", numPhysicalNames());
2834  for(auto it = firstPhysicalName(); it != lastPhysicalName(); ++it) {
2835  std::string name = it->second;
2836  if(name.size() > 128) name.resize(128);
2837  fprintf(fp, "%d %d \"%s\"\n", it->first.first, it->first.second,
2838  name.c_str());
2839  }
2840  fprintf(fp, "$EndPhysicalNames\n");
2841  }
2842 
2843  // entities
2844  writeMSH4Entities(this, fp, false, binary, scalingFactor, version,
2845  entityBounds);
2846 
2847  // check if the mesh is partitioned... and if we actually have elements in the
2848  // partitioned entities
2849  bool partitioned = getNumPartitions() > 0;
2850  if(partitioned) {
2851  std::vector<GEntity *> entities;
2852  getEntities(entities);
2853  std::size_t partEnt = 0;
2854  for(auto &ge : entities) {
2855  if(ge->geomType() == GEntity::PartitionPoint ||
2856  ge->geomType() == GEntity::PartitionCurve ||
2857  ge->geomType() == GEntity::PartitionSurface ||
2858  ge->geomType() == GEntity::PartitionVolume ||
2859  ge->geomType() == GEntity::GhostCurve ||
2860  ge->geomType() == GEntity::GhostSurface ||
2861  ge->geomType() == GEntity::GhostVolume)
2862  partEnt++;
2863  }
2864  if(!partEnt) {
2865  // this can happen when e.g. loading an old MSH2 files with partition tags
2866  // stored in elements
2867  Msg::Warning("No partition entities found, saving mesh as unpartitioned");
2868  partitioned = false;
2869  }
2870  }
2871 
2872  // partitioned entities
2873  if(partitioned)
2874  writeMSH4Entities(this, fp, true, binary, scalingFactor, version,
2875  entityBounds);
2876 
2877  // nodes
2878  writeMSH4Nodes(this, fp, partitioned, partitionToSave, binary,
2879  saveParametric ? 1 : 0, scalingFactor, saveAll, version);
2880 
2881  // elements
2882  writeMSH4Elements(this, fp, partitioned, partitionToSave, binary, saveAll,
2883  version);
2884 
2885  // periodic
2886  writeMSH4PeriodicNodes(this, fp, binary, version);
2887 
2888  // ghostCells
2889  writeMSH4GhostCells(this, fp, partitionToSave, binary);
2890 
2891  // parametrizations
2892  writeMSH4Parametrizations(this, fp, binary);
2893 
2894  // attributes
2895  for(auto &a : _attributes) {
2896  fprintf(fp, "$%s\n", a.first.c_str());
2897  for(auto &s : a.second) fprintf(fp, "%s\n", s.c_str());
2898  fprintf(fp, "$End%s\n", a.first.c_str());
2899  }
2900 
2901  fclose(fp);
2902 
2903  return 1;
2904 }
2905 
2906 int GModel::_writePartitionedMSH4(const std::string &baseName, double version,
2907  bool binary, bool saveAll,
2908  bool saveParametric, double scalingFactor)
2909 {
2910  int nthreads = CTX::instance()->numThreads;
2911  if(!nthreads) nthreads = Msg::GetMaxThreads();
2912 
2913  // precompute entity bounding boxes (we write the full brep in each file, so
2914  // otherwise we would compute the bounding boxes as many times as we have
2915  // partitions)
2916  std::vector<GEntity*> entities;
2917  getEntities(entities);
2918  std::vector<SBoundingBox3d> bounds(entities.size());
2919 #pragma omp parallel for num_threads(nthreads)
2920  for(std::size_t i = 0; i < entities.size(); i++) {
2921  bounds[i] = entities[i]->bounds();
2922  }
2923  std::map<GEntity*, SBoundingBox3d> entityBounds;
2924  for(std::size_t i = 0; i < entities.size(); i++) {
2925  entityBounds[entities[i]] = bounds[i];
2926  }
2927 
2928  bool exceptions = false;
2929 #pragma omp parallel for num_threads(nthreads)
2930  for(std::size_t part = 1; part <= getNumPartitions(); part++) {
2931  if(exceptions) continue;
2932  std::ostringstream sstream;
2933  sstream << baseName << "_" << part << ".msh";
2934  if(getNumPartitions() > 100) {
2935  if(part % 100 == 1) {
2936  Msg::Info("Writing partition %d/%d in file '%s'", part, getNumPartitions(),
2937  sstream.str().c_str());
2938  }
2939  }
2940  else {
2941  Msg::Info("Writing partition %d in file '%s'", part, sstream.str().c_str());
2942  }
2943  try { // OpenMP forbids leaving block via exception
2944  _writeMSH4(sstream.str(), version, binary, saveAll, saveParametric,
2945  scalingFactor, false, part, &entityBounds);
2946  }
2947  catch(...) {
2948  exceptions = true;
2949  }
2950  }
2951 
2952  if(exceptions) throw std::runtime_error(Msg::GetLastError());
2953 
2954  return 1;
2955 }
2956 
2957 static bool getPhyscialNameInfo(const std::string &name, int &parentPhysicalTag,
2958  std::vector<int> &partitions)
2959 {
2960  if(name[0] != '_') return false;
2961 
2962  const std::string part = "_part{";
2963  const std::string physical = "_physical{";
2964 
2965  size_t firstPart = name.find(part) + part.size();
2966  size_t lastPart = name.find_first_of('}', firstPart);
2967  const std::string partString = name.substr(firstPart, lastPart - firstPart);
2968 
2969  size_t firstPhysical = name.find(physical) + physical.size();
2970  size_t lastPhysical = name.find_first_of('}', firstPhysical);
2971  const std::string physicalString =
2972  name.substr(firstPhysical, lastPhysical - firstPhysical);
2973 
2974  std::string number;
2975  for(size_t i = 0; i < partString.size(); ++i) {
2976  if(partString[i] == ',') {
2977  partitions.push_back(atoi(number.c_str()));
2978  number.clear();
2979  }
2980  else {
2981  number += partString[i];
2982  }
2983  }
2984  partitions.push_back(atoi(number.c_str()));
2985 
2986  parentPhysicalTag = atoi(physicalString.c_str());
2987 
2988  return true;
2989 }
2990 
2991 int GModel::writePartitionedTopology(std::string &name)
2992 {
2993  Msg::Info("Writing '%s'", name.c_str());
2994 
2995  std::vector<std::map<int, std::pair<int, std::vector<int> > > > allParts(4);
2996  std::vector<GEntity *> entities;
2997  getEntities(entities);
2998  for(size_t i = 0; i < entities.size(); i++) {
2999  std::vector<int> physicals = entities[i]->getPhysicalEntities();
3000  for(size_t j = 0; j < physicals.size(); ++j) {
3001  const std::string phyName =
3002  this->getPhysicalName(entities[i]->dim(), physicals[j]);
3003  int parentPhysicalTag;
3004  std::vector<int> partitions;
3005  if(getPhyscialNameInfo(phyName, parentPhysicalTag, partitions)) {
3006  allParts[entities[i]->dim()].insert
3007  (std::make_pair(physicals[j],
3008  std::make_pair(parentPhysicalTag, partitions)));
3009  }
3010  }
3011  }
3012 
3013  FILE *fp = Fopen(name.c_str(), "w");
3014  if(!fp) {
3015  Msg::Error("Could not open file '%s'", name.c_str());
3016  return 0;
3017  }
3018 
3019  fprintf(fp, "Group{\n");
3020  fprintf(fp, " // Part~{dim}~{parentPhysicalTag}~{part1}~{part2}~...\n\n");
3021  std::vector<std::map<int, std::string> > tagToString(4);
3022  for(size_t i = 4; i > 0; --i) {
3023  fprintf(fp, " // Dim %lu\n", i - 1);
3024  for(auto it = allParts[i - 1].begin(); it != allParts[i - 1].end(); ++it) {
3025  std::string partName = "Part~{" + std::to_string(i - 1) + "}~{" +
3026  std::to_string(it->second.first) + "}";
3027  fprintf(fp, " Part~{%lu}~{%d}", i - 1, it->second.first);
3028  for(size_t j = 0; j < it->second.second.size(); ++j) {
3029  partName += "~{" + std::to_string(it->second.second[j]) + "}";
3030  fprintf(fp, "~{%d}", it->second.second[j]);
3031  }
3032  tagToString[i - 1].insert(std::make_pair(it->first, partName));
3033  fprintf(fp, " = Region[{%d}];\n", it->first);
3034  }
3035  fprintf(fp, "\n");
3036  }
3037 
3038  fprintf(fp, " // Global names\n\n");
3039  std::map<int, std::vector<int> > omegas;
3040  std::map<std::pair<int, int>, std::vector<int> > sigmasij;
3041  std::map<int, std::vector<int> > sigmas;
3042  std::map<int, std::set<int> > neighbors;
3043  std::size_t omegaDim = 0;
3044  for(size_t i = 4; i > 0; --i) {
3045  if(allParts[i - 1].size() != 0) {
3046  omegaDim = i - 1;
3047  break;
3048  }
3049  }
3050 
3051  // omega
3052  for(auto it = allParts[omegaDim].begin(); it != allParts[omegaDim].end();
3053  ++it) {
3054  if(it->second.second.size() == 1) {
3055  omegas[it->second.second[0]].push_back(it->first);
3056  }
3057  }
3058  fprintf(fp, " // Omega\n");
3059  for(auto it = omegas.begin(); it != omegas.end(); ++it) {
3060  fprintf(fp, " Omega~{%d} = Region[{", it->first);
3061  for(size_t j = 0; j < it->second.size(); ++j) {
3062  if(j == 0)
3063  fprintf(fp, "%s", tagToString[omegaDim][it->second[j]].c_str());
3064  else
3065  fprintf(fp, ", %s", tagToString[omegaDim][it->second[j]].c_str());
3066  }
3067  fprintf(fp, "}];\n");
3068  }
3069  fprintf(fp, "\n");
3070 
3071  if(omegaDim > 0) {
3072  // sigma
3073  for(auto it = allParts[omegaDim - 1].begin();
3074  it != allParts[omegaDim - 1].end(); ++it) {
3075  if(it->second.second.size() == 2) {
3076  sigmasij[std::make_pair(it->second.second[0],
3077  it->second.second[1])]
3078  .push_back(it->first);
3079  sigmasij[std::make_pair(it->second.second[1],
3080  it->second.second[0])]
3081  .push_back(it->first);
3082  sigmas[it->second.second[0]].push_back(it->first);
3083  sigmas[it->second.second[1]].push_back(it->first);
3084  }
3085  }
3086  fprintf(fp, " // Sigma\n");
3087  for(auto it = sigmasij.begin(); it != sigmasij.end(); ++it) {
3088  fprintf(fp, " Sigma~{%d}~{%d} = Region[{", it->first.first,
3089  it->first.second);
3090  for(size_t j = 0; j < it->second.size(); ++j) {
3091  if(j == 0)
3092  fprintf(fp, "%s", tagToString[omegaDim - 1][it->second[j]].c_str());
3093  else
3094  fprintf(fp, ", %s", tagToString[omegaDim - 1][it->second[j]].c_str());
3095  }
3096  fprintf(fp, "}];\n");
3097  }
3098  fprintf(fp, "\n");
3099 
3100  for(auto it = sigmas.begin(); it != sigmas.end(); ++it) {
3101  fprintf(fp, " Sigma~{%d} = Region[{", it->first);
3102  for(size_t j = 0; j < it->second.size(); ++j) {
3103  if(j == 0)
3104  fprintf(fp, "%s", tagToString[omegaDim - 1][it->second[j]].c_str());
3105  else
3106  fprintf(fp, ", %s", tagToString[omegaDim - 1][it->second[j]].c_str());
3107  }
3108  fprintf(fp, "}];\n");
3109  }
3110  fprintf(fp, "\n");
3111  }
3112 
3113  // D
3114  fprintf(fp, " D() = {");
3115  for(size_t i = 1; i <= getNumPartitions(); ++i) {
3116  if(i != 1) fprintf(fp, ", ");
3117  fprintf(fp, "%lu", i);
3118  }
3119  fprintf(fp, "};\n");
3120 
3121  if(omegaDim > 0) {
3122  // D~{i}
3123  for(auto it = allParts[omegaDim - 1].begin();
3124  it != allParts[omegaDim - 1].end(); ++it) {
3125  if(it->second.second.size() == 2) {
3126  neighbors[it->second.second[0]].insert(it->second.second[1]);
3127  neighbors[it->second.second[1]].insert(it->second.second[0]);
3128  }
3129  }
3130  for(size_t i = 1; i <= getNumPartitions(); ++i) {
3131  fprintf(fp, " D~{%lu}() = {", i);
3132  for(auto it = neighbors[i].begin(); it != neighbors[i].end(); ++it) {
3133  if(it != neighbors[i].begin()) fprintf(fp, ", ");
3134  fprintf(fp, "%d", *it);
3135  }
3136  fprintf(fp, "};\n");
3137  }
3138  }
3139 
3140  fprintf(fp, "}\n\n");
3141 
3142  fclose(fp);
3143 
3144  Msg::Info("Done writing '%s'", name.c_str());
3145 
3146  return 1;
3147 }
MElement::getNum
virtual std::size_t getNum() const
Definition: MElement.h:68
MTriangle.h
readMSH4Entities
static bool readMSH4Entities(GModel *const model, FILE *fp, bool partition, bool binary, bool swap, double version)
Definition: GModelIO_MSH4.cpp:269
ghostEdge::getPartition
virtual int getPartition() const
Definition: ghostEdge.h:37
GModel::_attributes
std::map< std::string, std::vector< std::string > > _attributes
Definition: GModel.h:156
tags
static std::map< SPoint2, unsigned int > tags
Definition: drawGraph2d.cpp:400
MTrihedron.h
GEntity::affineTransform
std::vector< double > affineTransform
Definition: GEntity.h:403
GModel::firstEdge
eiter firstEdge()
Definition: GModel.h:356
discreteEdge::readParametrization
bool readParametrization(FILE *fp, bool binary)
Definition: discreteEdge.cpp:251
partitionEdge
Definition: partitionEdge.h:12
GEntity::GhostCurve
@ GhostCurve
Definition: GEntity.h:125
readMSH4BoundingEntities
static bool readMSH4BoundingEntities(GModel *const model, FILE *fp, GEntity *const entity, bool binary, char *str, bool swap)
Definition: GModelIO_MSH4.cpp:79
GModel::writePartitionedTopology
int writePartitionedTopology(std::string &name)
Definition: GModelIO_MSH4.cpp:2991
GEdge::getMeshElement
MElement * getMeshElement(std::size_t index) const
Definition: GEdge.cpp:173
writeMSH4PeriodicNodes
static void writeMSH4PeriodicNodes(GModel *const model, FILE *fp, bool binary, double version)
Definition: GModelIO_MSH4.cpp:2568
GEntity::correspondingHighOrderVertices
std::map< MVertex *, MVertex * > correspondingHighOrderVertices
Definition: GEntity.h:409
partitionEdge::getPartition
virtual int getPartition(std::size_t index) const
Definition: partitionEdge.h:42
ghostRegion
Definition: ghostRegion.h:18
GModel::getNumMeshVertices
std::size_t getNumMeshVertices(int dim=-1) const
Definition: GModel.cpp:1529
ghostFace
Definition: ghostFace.h:17
GEntity::getMeshVertex
MVertex * getMeshVertex(std::size_t index)
Definition: GEntity.h:379
GFace
Definition: GFace.h:33
Msg::Info
static void Info(const char *fmt,...)
Definition: GmshMessage.cpp:587
MElementFactory
Definition: MElement.h:517
ghostFace.h
OS.h
MElement::setPartition
virtual void setPartition(int num)
Definition: MElement.h:93
GEntity.h
physicalName
static std::string physicalName(GModel *m, int dim, int num)
Definition: GModelIO_INP.cpp:35
Msg::Debug
static void Debug(const char *fmt,...)
Definition: GmshMessage.cpp:752
discreteEdge
Definition: discreteEdge.h:12
MVertex
Definition: MVertex.h:24
CTX::numThreads
int numThreads
Definition: Context.h:169
partitionRegion::getPartition
virtual int getPartition(std::size_t index) const
Definition: partitionRegion.h:40
GModel::numPhysicalNames
int numPhysicalNames() const
Definition: GModel.h:464
Msg::Warning
static void Warning(const char *fmt,...)
Definition: GmshMessage.cpp:543
Msg::Error
static void Error(const char *fmt,...)
Definition: GmshMessage.cpp:482
MVertex::z
double z() const
Definition: MVertex.h:62
transform
static SPoint3 transform(MVertex *vsource, const std::vector< double > &tfo)
Definition: Generator.cpp:1347
MVertex::getNum
std::size_t getNum() const
Definition: MVertex.h:86
GModel::getFaceByTag
GFace * getFaceByTag(int n) const
Definition: GModel.cpp:326
SBoundingBox3d::min
SPoint3 min() const
Definition: SBoundingBox3d.h:90
GModel::getMeshVertexByTag
MVertex * getMeshVertexByTag(int n)
Definition: GModel.cpp:1953
partitionEdge::getParentEntity
virtual GEntity * getParentEntity()
Definition: partitionEdge.h:36
GModel::getInnerPhysicalNamesIterators
void getInnerPhysicalNamesIterators(std::vector< piter > &iterators)
Definition: GModel.cpp:929
GRegion::getNumMeshElements
std::size_t getNumMeshElements() const
Definition: GRegion.cpp:60
partitionFace
Definition: partitionFace.h:12
MVertex::onWhat
GEntity * onWhat() const
Definition: MVertex.h:82
MPoint.h
GModel::firstVertex
viter firstVertex()
Definition: GModel.h:357
partitionRegion::getPartitions
virtual const std::vector< int > & getPartitions() const
Definition: partitionRegion.h:39
GEntity::addPhysicalEntity
virtual void addPhysicalEntity(int physicalTag)
Definition: GEntity.h:284
discreteEdge::haveParametrization
virtual bool haveParametrization()
Definition: discreteEdge.h:27
writeMSH4Entities
static void writeMSH4Entities(GModel *const model, FILE *fp, bool partition, bool binary, double scalingFactor, double version, std::map< GEntity *, SBoundingBox3d > *entityBounds)
Definition: GModelIO_MSH4.cpp:1572
GModel::getEdgeByTag
GEdge * getEdgeByTag(int n) const
Definition: GModel.cpp:336
GModel::_writePartitionedMSH4
int _writePartitionedMSH4(const std::string &baseName, double version, bool binary, bool saveAll, bool saveParametric, double scalingFactor)
Definition: GModelIO_MSH4.cpp:2906
discreteEdge::writeParametrization
bool writeParametrization(FILE *fp, bool binary)
Definition: discreteEdge.cpp:223
MLine.h
edges
static int edges[6][2]
Definition: meshGRegionLocalMeshMod.cpp:23
partitionFace::getPartitions
virtual const std::vector< int > & getPartitions() const
Definition: partitionFace.h:39
readMSH4Nodes
static std::pair< std::size_t, MVertex * > * readMSH4Nodes(GModel *const model, FILE *fp, bool binary, bool &dense, std::size_t &totalNumNodes, std::size_t &maxNodeNum, bool swap, double version)
Definition: GModelIO_MSH4.cpp:463
partitionFace::getPartition
virtual int getPartition(std::size_t index) const
Definition: partitionFace.h:40
GEntity
Definition: GEntity.h:31
GEntity::getNumMeshVertices
std::size_t getNumMeshVertices()
Definition: GEntity.h:376
ghostRegion::getPartition
virtual int getPartition() const
Definition: ghostRegion.h:45
GModel::firstPhysicalName
piter firstPhysicalName()
Definition: GModel.h:458
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
GModel::getNumPartitions
std::size_t getNumPartitions() const
Definition: GModel.h:602
MElement::getNumVertices
virtual std::size_t getNumVertices() const =0
GModel::setNumPartitions
void setNumPartitions(std::size_t npart)
Definition: GModel.h:603
GEntity::GhostSurface
@ GhostSurface
Definition: GEntity.h:126
discreteRegion
Definition: discreteRegion.h:13
Fopen
FILE * Fopen(const char *f, const char *mode)
Definition: OS.cpp:273
readMSH4Parametrizations
static bool readMSH4Parametrizations(GModel *const model, FILE *fp, bool binary)
Definition: GModelIO_MSH4.cpp:1197
GEntity::PartitionCurve
@ PartitionCurve
Definition: GEntity.h:122
elementFactory
Definition: shapeFunctions.h:1402
CTX::instance
static CTX * instance()
Definition: Context.cpp:122
MElement::getVertex
virtual const MVertex * getVertex(int num) const =0
SPoint3::x
double x(void) const
Definition: SPoint3.h:125
GModel::lastFace
fiter lastFace()
Definition: GModel.h:359
SwapBytes
void SwapBytes(char *array, int size, int n)
Definition: StringUtils.cpp:16
discreteVertex
Definition: discreteVertex.h:15
GModel::getPhysicalName
std::string getPhysicalName(int dim, int num) const
Definition: GModel.cpp:961
GModel::bounds
SBoundingBox3d bounds(bool aroundVisible=false)
Definition: GModel.cpp:1043
writeMSH4Elements
static void writeMSH4Elements(GModel *const model, FILE *fp, bool partitioned, int partitionToSave, bool binary, bool saveAll, double version)
Definition: GModelIO_MSH4.cpp:2399
partitionRegion::numPartitions
virtual std::size_t numPartitions() const
Definition: partitionRegion.h:44
GVertex::getMeshElement
MElement * getMeshElement(std::size_t index) const
Definition: GVertex.cpp:124
readMSH4Elements
static std::pair< std::size_t, std::pair< MElement *, int > > * readMSH4Elements(GModel *const model, FILE *fp, bool binary, bool &dense, std::size_t &totalNumElements, std::size_t &maxElementNum, bool swap, double version)
Definition: GModelIO_MSH4.cpp:714
writeMSH4Parametrizations
static void writeMSH4Parametrizations(GModel *const model, FILE *fp, bool binary)
Definition: GModelIO_MSH4.cpp:2742
readMSH4GhostElements
static bool readMSH4GhostElements(GModel *const model, FILE *fp, bool binary, bool swap)
Definition: GModelIO_MSH4.cpp:1090
MHexahedron.h
MEdgeVertex
Definition: MVertex.h:137
GModel::lastVertex
viter lastVertex()
Definition: GModel.h:361
writeMSH4Nodes
static void writeMSH4Nodes(GModel *const model, FILE *fp, bool partitioned, int partitionToSave, bool binary, int saveParametric, double scalingFactor, bool saveAll, double version)
Definition: GModelIO_MSH4.cpp:2310
readMSH4Physicals
static bool readMSH4Physicals(GModel *const model, FILE *fp, GEntity *const entity, bool binary, char *str, bool swap)
Definition: GModelIO_MSH4.cpp:44
GVertex
Definition: GVertex.h:23
SBoundingBox3d::empty
bool empty()
Definition: SBoundingBox3d.h:36
swap
void swap(double &a, double &b)
Definition: meshTriangulation.cpp:27
writeMSH4EntityNodes
static void writeMSH4EntityNodes(GEntity *ge, FILE *fp, bool binary, int saveParametric, double scalingFactor, double version)
Definition: GModelIO_MSH4.cpp:2000
partitionRegion.h
GModel::getDim
int getDim() const
Definition: GModel.cpp:989
contextMeshOptions::saveWithoutOrphans
int saveWithoutOrphans
Definition: Context.h:66
GModel
Definition: GModel.h:44
Msg::StopProgressMeter
static void StopProgressMeter()
Definition: GmshMessage.cpp:318
GVertex::getNumMeshElements
std::size_t getNumMeshElements() const
Definition: GVertex.h:104
Msg::GetMaxThreads
static int GetMaxThreads()
Definition: GmshMessage.cpp:1637
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
ghostFace::getPartition
virtual int getPartition() const
Definition: ghostFace.h:41
writeMSH4GhostCells
static void writeMSH4GhostCells(GModel *const model, FILE *fp, int partitionToSave, bool binary)
Definition: GModelIO_MSH4.cpp:2674
MPyramid.h
writeMSH4BoundingBox
static void writeMSH4BoundingBox(SBoundingBox3d boundBox, FILE *fp, double scalingFactor, bool binary, int dim, double version)
Definition: GModelIO_MSH4.cpp:1551
GEntity::geomType
virtual GeomType geomType() const
Definition: GEntity.h:238
GModel::firstFace
fiter firstFace()
Definition: GModel.h:355
GmshDefines.h
SPoint3::y
double y(void) const
Definition: SPoint3.h:127
getAdditionalEntities
static std::size_t getAdditionalEntities(std::set< GRegion *, GEntityPtrLessThan > &regions, std::set< GFace *, GEntityPtrLessThan > &faces, std::set< GEdge *, GEntityPtrLessThan > &edges, std::set< GVertex *, GEntityPtrLessThan > &vertices)
Definition: GModelIO_MSH4.cpp:2073
writeMSH4Physicals
static void writeMSH4Physicals(FILE *fp, GEntity *const entity, bool binary)
Definition: GModelIO_MSH4.cpp:1530
partitionRegion::getParentEntity
virtual GEntity * getParentEntity()
Definition: partitionRegion.h:34
GModel::add
bool add(GRegion *r)
Definition: GModel.h:394
GModel::_elementVectorCache
std::vector< std::pair< MElement *, int > > _elementVectorCache
Definition: GModel.h:103
CTX::mesh
contextMeshOptions mesh
Definition: Context.h:313
GModel::_writeMSH4
int _writeMSH4(const std::string &name, double version, bool binary, bool saveAll, bool saveParametric, double scalingFactor, bool append, int partitionToSave=0, std::map< GEntity *, SBoundingBox3d > *entityBounds=nullptr)
Definition: GModelIO_MSH4.cpp:2796
MElement
Definition: MElement.h:30
GModel::getMeshElementByTag
MElement * getMeshElementByTag(int n)
Definition: GModel.h:538
ExtractDoubleQuotedString
std::string ExtractDoubleQuotedString(const char *str, int len)
Definition: StringUtils.cpp:27
readMSH4EntityInfo
static bool readMSH4EntityInfo(FILE *fp, bool binary, char *str, int sizeofstr, bool swap, double version, bool partition, int dim, int &tag, int &parentDim, int &parentTag, std::vector< int > &partitions, double &minX, double &minY, double &minZ, double &maxX, double &maxY, double &maxZ)
Definition: GModelIO_MSH4.cpp:171
GEntity::GhostVolume
@ GhostVolume
Definition: GEntity.h:127
GModel::_vertexMapCache
std::map< int, MVertex * > _vertexMapCache
Definition: GModel.h:102
GEntity::tag
int tag() const
Definition: GEntity.h:280
MFaceVertex
Definition: MVertex.h:168
partitionFace.h
elementFactory::create
element * create(int numNodes, int dimension, double *x, double *y, double *z, bool copy=false)
Definition: shapeFunctions.h:1404
partitionEdge.h
partitionEdge::getPartitions
virtual const std::vector< int > & getPartitions() const
Definition: partitionEdge.h:41
GModel::_vertexVectorCache
std::vector< MVertex * > _vertexVectorCache
Definition: GModel.h:101
GModel::getEntities
void getEntities(std::vector< GEntity * > &entities, int dim=-1) const
Definition: GModel.cpp:651
element
Definition: shapeFunctions.h:12
GRegion
Definition: GRegion.h:28
GFace::getMeshElement
MElement * getMeshElement(std::size_t index) const
Definition: GFace.cpp:234
readMSH4PeriodicNodes
static bool readMSH4PeriodicNodes(GModel *const model, FILE *fp, bool binary, bool swap, double version)
Definition: GModelIO_MSH4.cpp:941
StringUtils.h
LegendrePolynomials::df
void df(int n, double u, double *val)
Definition: orthogonalBasis.cpp:103
Msg::GetLastError
static std::string GetLastError()
Definition: GmshMessage.cpp:362
GEntity::addElement
virtual void addElement(int type, MElement *e)
Definition: GEntity.h:387
GModel::firstRegion
riter firstRegion()
Definition: GModel.h:354
GEntity::PartitionSurface
@ PartitionSurface
Definition: GEntity.h:123
partitionEdge::numPartitions
virtual std::size_t numPartitions() const
Definition: partitionEdge.h:46
GModel::lastRegion
riter lastRegion()
Definition: GModel.h:358
MVertex::getParameter
virtual bool getParameter(int i, double &par) const
Definition: MVertex.h:97
discreteEdge.h
Context.h
GEntity::getMeshElement
virtual MElement * getMeshElement(std::size_t index) const
Definition: GEntity.h:363
MTetrahedron.h
partitionVertex::getParentEntity
virtual GEntity * getParentEntity()
Definition: partitionVertex.h:34
z
const double z
Definition: GaussQuadratureQuad.cpp:56
GModel::lastPhysicalName
piter lastPhysicalName()
Definition: GModel.h:459
MQuadrangle.h
MElement::getInfoMSH
static unsigned int getInfoMSH(const int typeMSH, const char **const name=nullptr)
Definition: MElement.cpp:2057
getPhyscialNameInfo
static bool getPhyscialNameInfo(const std::string &name, int &parentPhysicalTag, std::vector< int > &partitions)
Definition: GModelIO_MSH4.cpp:2957
GModel::noPhysicalGroups
bool noPhysicalGroups()
Definition: GModel.cpp:828
Msg::StartProgressMeter
static void StartProgressMeter(int ntotal)
Definition: GmshMessage.cpp:312
GEdge
Definition: GEdge.h:26
GEntity::setMeshMaster
void setMeshMaster(GEntity *)
Definition: GEntity.cpp:128
GModel::_elementMapCache
std::map< int, std::pair< MElement *, int > > _elementMapCache
Definition: GModel.h:104
MPrism.h
GEntity::getPhysicalEntities
virtual std::vector< int > getPhysicalEntities()
Definition: GEntity.h:288
GModel::_readMSH4
int _readMSH4(const std::string &name)
Definition: GModelIO_MSH4.cpp:1255
GModel::setPhysicalName
int setPhysicalName(const std::string &name, int dim, int num=0)
Definition: GModel.cpp:937
GModel::getEntityByTag
GEntity * getEntityByTag(int dim, int n) const
Definition: GModel.cpp:356
SPoint3::z
double z(void) const
Definition: SPoint3.h:129
partitionVertex
Definition: partitionVertex.h:12
GEntity::PartitionPoint
@ PartitionPoint
Definition: GEntity.h:121
GModel::lastEdge
eiter lastEdge()
Definition: GModel.h:360
GModel.h
ghostEdge.h
GEdge::getNumMeshElements
std::size_t getNumMeshElements() const
Definition: GEdge.h:201
GModel::getRegionByTag
GRegion * getRegionByTag(int n) const
Definition: GModel.cpp:316
MVertex::y
double y() const
Definition: MVertex.h:61
partitionVertex::getPartition
virtual int getPartition(std::size_t index) const
Definition: partitionVertex.h:40
ElementType::getNumVertices
int getNumVertices(int type)
Definition: ElementType.cpp:456
partitionFace::getParentEntity
virtual GEntity * getParentEntity()
Definition: partitionFace.h:34
partitionVertex::numPartitions
virtual std::size_t numPartitions() const
Definition: partitionVertex.h:44
GFace::getNumMeshElements
std::size_t getNumMeshElements() const
Definition: GFace.cpp:181
SBoundingBox3d::max
SPoint3 max() const
Definition: SBoundingBox3d.h:91
GEntity::dim
virtual int dim() const
Definition: GEntity.h:196
Msg::ProgressMeter
static void ProgressMeter(int n, bool log, const char *fmt,...)
Definition: GmshMessage.cpp:783
GModel::getVertexByTag
GVertex * getVertexByTag(int n) const
Definition: GModel.cpp:346
partitionVertex.h
ghostEdge
Definition: ghostEdge.h:15
ghostRegion.h
MVertex::setEntity
void setEntity(GEntity *ge)
Definition: MVertex.h:83
GEntity::correspondingVertices
std::map< MVertex *, MVertex * > correspondingVertices
Definition: GEntity.h:406
partitionFace::numPartitions
virtual std::size_t numPartitions() const
Definition: partitionFace.h:44
SBoundingBox3d
Definition: SBoundingBox3d.h:21
GRegion::getMeshElement
MElement * getMeshElement(std::size_t index) const
Definition: GRegion.cpp:127
GModel::current
static GModel * current(int index=-1)
Definition: GModel.cpp:136
MVertex::x
double x() const
Definition: MVertex.h:60
GEntity::addMeshVertex
void addMeshVertex(MVertex *v)
Definition: GEntity.h:382
discreteFace
Definition: discreteFace.h:18
faces
static int faces[4][3]
Definition: meshGRegionDelaunayInsertion.cpp:165