gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
GModelIO_MSH3.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 #include <sstream>
7 #include <iomanip>
8 #include <ctime>
9 #include "GModel.h"
10 #include "OS.h"
11 #include "Context.h"
12 #include "GmshMessage.h"
13 #include "MElement.h"
14 #include "MPoint.h"
15 #include "MLine.h"
16 #include "MTriangle.h"
17 #include "MQuadrangle.h"
18 #include "MTetrahedron.h"
19 #include "MHexahedron.h"
20 #include "MPrism.h"
21 #include "MPyramid.h"
22 #include "MTrihedron.h"
23 #include "StringUtils.h"
24 #include "discreteVertex.h"
25 #include "discreteEdge.h"
26 #include "discreteFace.h"
27 #include "discreteRegion.h"
28 
29 static int readMSHPhysicals(FILE *fp, GEntity *ge)
30 {
31  int nump;
32  if(fscanf(fp, "%d", &nump) != 1) return 0;
33  for(int i = 0; i < nump; i++) {
34  int tag;
35  if(fscanf(fp, "%d", &tag) != 1) return 0;
36  ge->physicals.push_back(tag);
37  }
38  return 1;
39 }
40 
41 static void readMSHEntities(FILE *fp, GModel *gm)
42 {
43  int nv, ne, nf, nr;
44  int tag;
45  if(fscanf(fp, "%d %d %d %d", &nv, &ne, &nf, &nr) != 4) return;
46  for(int i = 0; i < nv; i++) {
47  if(fscanf(fp, "%d", &tag) != 1) return;
48  GVertex *gv = gm->getVertexByTag(tag);
49  if(!gv) {
50  gv = new discreteVertex(gm, tag);
51  gm->add(gv);
52  }
53  if(!readMSHPhysicals(fp, gv)) return;
54  }
55  for(int i = 0; i < ne; i++) {
56  int n;
57  if(fscanf(fp, "%d %d", &tag, &n) != 2) return;
58  GEdge *ge = gm->getEdgeByTag(tag);
59  if(!ge) {
60  GVertex *v1 = nullptr, *v2 = nullptr;
61  for(int j = 0; j < n; j++) {
62  int tagv;
63  if(fscanf(fp, "%d", &tagv) != 1) {
64  delete ge;
65  return;
66  }
67  GVertex *v = gm->getVertexByTag(tagv);
68  if(!v) Msg::Error("Unknown GVertex %d", tagv);
69  if(j == 0) v1 = v;
70  if(j == 1) v2 = v;
71  }
72  ge = new discreteEdge(gm, tag, v1, v2);
73  gm->add(ge);
74  }
75  if(!readMSHPhysicals(fp, ge)) return;
76  }
77  for(int i = 0; i < nf; i++) {
78  int n;
79  if(fscanf(fp, "%d %d", &tag, &n) != 2) return;
80  GFace *gf = gm->getFaceByTag(tag);
81  if(!gf) {
82  discreteFace *df = new discreteFace(gm, tag);
83  std::vector<int> edges, signs;
84  for(int j = 0; j < n; j++) {
85  int tage;
86  if(fscanf(fp, "%d", &tage) != 1) {
87  delete df;
88  return;
89  }
90  edges.push_back(std::abs(tage));
91  int sign = tage > 0 ? 1 : -1;
92  signs.push_back(sign);
93  }
94  df->setBoundEdges(edges, signs);
95  gm->add(df);
96  gf = df;
97  }
98  if(!readMSHPhysicals(fp, gf)) return;
99  }
100  for(int i = 0; i < nr; i++) {
101  int n;
102  if(fscanf(fp, "%d %d", &tag, &n) != 2) return;
103  GRegion *gr = gm->getRegionByTag(tag);
104  if(!gr) {
105  discreteRegion *dr = new discreteRegion(gm, tag);
106  std::vector<int> faces, signs;
107  for(int j = 0; j < n; j++) {
108  int tagf;
109  if(fscanf(fp, "%d", &tagf) != 1) {
110  delete dr;
111  return;
112  }
113  faces.push_back(std::abs(tagf));
114  int sign = tagf > 0 ? 1 : -1;
115  signs.push_back(sign);
116  }
117  dr->setBoundFaces(faces, signs);
118  gm->add(dr);
119  gr = dr;
120  }
121  if(!readMSHPhysicals(fp, gr)) return;
122  }
123 }
124 
125 void readMSHPeriodicNodes(FILE *fp, GModel *gm) // also used in MSH2
126 {
127  int count;
128  if(fscanf(fp, "%d", &count) != 1) return;
129  for(int i = 0; i < count; i++) {
130  int dim, slave, master;
131 
132  if(fscanf(fp, "%d %d %d", &dim, &slave, &master) != 3) continue;
133 
134  GEntity *s = nullptr, *m = nullptr;
135  switch(dim) {
136  case 0:
137  s = gm->getVertexByTag(slave);
138  m = gm->getVertexByTag(master);
139  break;
140  case 1:
141  s = gm->getEdgeByTag(slave);
142  m = gm->getEdgeByTag(master);
143  break;
144  case 2:
145  s = gm->getFaceByTag(slave);
146  m = gm->getFaceByTag(master);
147  break;
148  }
149 
150  // we need to continue parsing, otherwise we end up reading on the wrong
151  // position
152 
153  bool completePer = s && m;
154 
155  char token[7];
156  fpos_t pos;
157  fgetpos(fp, &pos);
158  if(fscanf(fp, "%s", token) != 1) return;
159  if(strcmp(token, "Affine") == 0) {
160  std::vector<double> tfo(16);
161  for(int i = 0; i < 16; i++) {
162  if(fscanf(fp, "%lf", &tfo[i]) != 1) return;
163  }
164  if(completePer) s->setMeshMaster(m, tfo);
165  }
166  else {
167  fsetpos(fp, &pos);
168  if(completePer) s->setMeshMaster(m);
169  }
170  int numv;
171  if(fscanf(fp, "%d", &numv) != 1) numv = 0;
172  for(int j = 0; j < numv; j++) {
173  int v1, v2;
174  if(fscanf(fp, "%d %d", &v1, &v2) != 2) continue;
175  MVertex *mv1 = gm->getMeshVertexByTag(v1);
176  MVertex *mv2 = gm->getMeshVertexByTag(v2);
177  if(completePer) s->correspondingVertices[mv1] = mv2;
178  }
179  if(!completePer) {
180  if(!s)
181  Msg::Info("Could not find periodic slave entity %d of dimension %d",
182  slave, dim);
183  if(!m)
184  Msg::Info("Could not find periodic master entity %d of dimension %d",
185  master, dim);
186  }
187  }
188 }
189 
190 int GModel::_readMSH3(const std::string &name)
191 {
192  FILE *fp = Fopen(name.c_str(), "rb");
193  if(!fp) {
194  Msg::Error("Unable to open file '%s'", name.c_str());
195  return 0;
196  }
197 
198  char str[256] = "";
199  double version = 0.;
200  bool binary = false, swap = false, postpro = false;
201  int minVertex = 0;
202  std::map<int, std::vector<MElement *> > elements[11];
203  std::size_t oldNumPartitions = getNumPartitions();
204 
205  while(1) {
206  while(str[0] != '$') {
207  if(!fgets(str, sizeof(str), fp) || feof(fp)) break;
208  }
209 
210  if(feof(fp)) break;
211 
212  // $MeshFormat section
213  if(!strncmp(&str[1], "MeshFormat", 10)) {
214  if(!fgets(str, sizeof(str), fp)) {
215  fclose(fp);
216  return 0;
217  }
218  int format, size;
219  if(sscanf(str, "%lf %d %d", &version, &format, &size) != 3) {
220  fclose(fp);
221  return 0;
222  }
223  if(version < 3. || version >= 4.) {
224  Msg::Error("Wrong MSH file version %g for MSH3 reader", version);
225  fclose(fp);
226  return 0;
227  }
228  if(format) {
229  binary = true;
230  Msg::Debug("Mesh is in binary format");
231  int one;
232  if(fread(&one, sizeof(int), 1, fp) != 1) {
233  fclose(fp);
234  return 0;
235  }
236  if(one != 1) {
237  swap = true;
238  Msg::Debug("Swapping bytes from binary file");
239  }
240  }
241  }
242 
243  // $PhysicalNames section
244  else if(!strncmp(&str[1], "PhysicalNames", 13)) {
245  if(!fgets(str, sizeof(str), fp)) {
246  fclose(fp);
247  return 0;
248  }
249  int numNames;
250  if(sscanf(str, "%d", &numNames) != 1) {
251  fclose(fp);
252  return 0;
253  }
254  for(int i = 0; i < numNames; i++) {
255  int dim, num;
256  if(fscanf(fp, "%d", &dim) != 1) {
257  fclose(fp);
258  return 0;
259  }
260  if(fscanf(fp, "%d", &num) != 1) {
261  fclose(fp);
262  return 0;
263  }
264  if(!fgets(str, sizeof(str), fp)) {
265  fclose(fp);
266  return 0;
267  }
268  std::string name = ExtractDoubleQuotedString(str, 256);
269  if(name.size()) setPhysicalName(name, dim, num);
270  }
271  }
272 
273  // $Entities section
274  else if(!strncmp(&str[1], "Entities", 8)) {
275  readMSHEntities(fp, this);
276  }
277 
278  // $Nodes section
279  else if(!strncmp(&str[1], "Nodes", 5)) {
280  if(!fgets(str, sizeof(str), fp)) {
281  fclose(fp);
282  return 0;
283  }
284  int numVertices;
285  if(sscanf(str, "%d", &numVertices) != 1) {
286  fclose(fp);
287  return 0;
288  }
289  Msg::Info("%d nodes", numVertices);
290  Msg::StartProgressMeter(numVertices);
291  _vertexMapCache.clear();
292  _vertexVectorCache.clear();
293  int maxVertex = -1;
294  minVertex = numVertices + 1;
295  for(int i = 0; i < numVertices; i++) {
296  int num, entity, dim;
297  double xyz[3];
298  MVertex *vertex = nullptr;
299  if(!binary) {
300  if(fscanf(fp, "%d %lf %lf %lf %d", &num, &xyz[0], &xyz[1], &xyz[2],
301  &entity) != 5) {
302  fclose(fp);
303  return 0;
304  }
305  }
306  else {
307  if(fread(&num, sizeof(int), 1, fp) != 1) {
308  fclose(fp);
309  return 0;
310  }
311  if(swap) SwapBytes((char *)&num, sizeof(int), 1);
312  if(fread(xyz, sizeof(double), 3, fp) != 3) {
313  fclose(fp);
314  return 0;
315  }
316  if(swap) SwapBytes((char *)xyz, sizeof(double), 3);
317  if(fread(&entity, sizeof(int), 1, fp) != 1) {
318  fclose(fp);
319  return 0;
320  }
321  if(swap) SwapBytes((char *)&entity, sizeof(int), 1);
322  }
323  if(!entity) {
324  vertex = new MVertex(xyz[0], xyz[1], xyz[2], nullptr, num);
325  }
326  else {
327  if(!binary) {
328  if(fscanf(fp, "%d", &dim) != 1) {
329  fclose(fp);
330  return 0;
331  }
332  }
333  else {
334  if(fread(&dim, sizeof(int), 1, fp) != 1) {
335  fclose(fp);
336  return 0;
337  }
338  if(swap) SwapBytes((char *)&dim, sizeof(int), 1);
339  }
340  switch(dim) {
341  case 0: {
342  GVertex *gv = getVertexByTag(entity);
343  // FIXME -- cannot call this: it destroys _vertexMapCache
344  // if(gv) gv->deleteMesh();
345  vertex = new MVertex(xyz[0], xyz[1], xyz[2], gv, num);
346  } break;
347  case 1: {
348  GEdge *ge = getEdgeByTag(entity);
349  double u;
350  if(!binary) {
351  if(fscanf(fp, "%lf", &u) != 1) {
352  fclose(fp);
353  return 0;
354  }
355  }
356  else {
357  if(fread(&u, sizeof(double), 1, fp) != 1) {
358  fclose(fp);
359  return 0;
360  }
361  if(swap) SwapBytes((char *)&u, sizeof(double), 1);
362  }
363  vertex = new MEdgeVertex(xyz[0], xyz[1], xyz[2], ge, u, num);
364  } break;
365  case 2: {
366  GFace *gf = getFaceByTag(entity);
367  double uv[2];
368  if(!binary) {
369  if(fscanf(fp, "%lf %lf", &uv[0], &uv[1]) != 2) {
370  fclose(fp);
371  return 0;
372  }
373  }
374  else {
375  if(fread(uv, sizeof(double), 2, fp) != 2) {
376  fclose(fp);
377  return 0;
378  }
379  if(swap) SwapBytes((char *)uv, sizeof(double), 2);
380  }
381  vertex =
382  new MFaceVertex(xyz[0], xyz[1], xyz[2], gf, uv[0], uv[1], num);
383  } break;
384  case 3: {
385  GRegion *gr = getRegionByTag(entity);
386  double uvw[3];
387  if(!binary) {
388  if(fscanf(fp, "%lf %lf %lf", &uvw[0], &uvw[1], &uvw[2]) != 3) {
389  fclose(fp);
390  return 0;
391  }
392  }
393  else {
394  if(fread(uvw, sizeof(double), 3, fp) != 3) {
395  fclose(fp);
396  return 0;
397  }
398  if(swap) SwapBytes((char *)uvw, sizeof(double), 3);
399  }
400  vertex = new MVertex(xyz[0], xyz[1], xyz[2], gr, num);
401  } break;
402  default:
403  Msg::Error("Wrong entity dimension for node %d", num);
404  fclose(fp);
405  return 0;
406  }
407  }
408  minVertex = std::min(minVertex, num);
409  maxVertex = std::max(maxVertex, num);
410  if(_vertexMapCache.count(num))
411  Msg::Warning("Skipping duplicate node %d", num);
412  _vertexMapCache[num] = vertex;
413  if(numVertices > 100000)
414  Msg::ProgressMeter(i + 1, true, "Reading nodes");
415  }
417  // if the vertex numbering is dense, transfer the map into a vector to
418  // speed up element creation
419  if((int)_vertexMapCache.size() == numVertices &&
420  ((minVertex == 1 && maxVertex == numVertices) ||
421  (minVertex == 0 && maxVertex == numVertices - 1))) {
422  Msg::Debug("Vertex numbering is dense");
423  _vertexVectorCache.resize(_vertexMapCache.size() + 1);
424  if(minVertex == 1)
425  _vertexVectorCache[0] = nullptr;
426  else
427  _vertexVectorCache[numVertices] = nullptr;
428  for(auto it = _vertexMapCache.begin(); it != _vertexMapCache.end(); ++it)
429  _vertexVectorCache[it->first] = it->second;
430  _vertexMapCache.clear();
431  }
432  }
433 
434  // $Elements section
435  else if(!strncmp(&str[1], "Elements", 8)) {
436  if(!fgets(str, sizeof(str), fp)) {
437  fclose(fp);
438  return 0;
439  }
440  int numElements;
441  if(sscanf(str, "%d", &numElements) != 1) {
442  fclose(fp);
443  return 0;
444  }
445  Msg::Info("%d elements", numElements);
446  Msg::StartProgressMeter(numElements);
447  for(int i = 0; i < numElements; i++) {
448  int num, type, entity, numData;
449  if(!binary) {
450  if(fscanf(fp, "%d %d %d %d", &num, &type, &entity, &numData) != 4) {
451  fclose(fp);
452  return 0;
453  }
454  }
455  else {
456  if(fread(&num, sizeof(int), 1, fp) != 1) {
457  fclose(fp);
458  return 0;
459  }
460  if(swap) SwapBytes((char *)&num, sizeof(int), 1);
461  if(fread(&type, sizeof(int), 1, fp) != 1) {
462  fclose(fp);
463  return 0;
464  }
465  if(swap) SwapBytes((char *)&type, sizeof(int), 1);
466  if(fread(&entity, sizeof(int), 1, fp) != 1) {
467  fclose(fp);
468  return 0;
469  }
470  if(swap) SwapBytes((char *)&entity, sizeof(int), 1);
471  if(fread(&numData, sizeof(int), 1, fp) != 1) {
472  fclose(fp);
473  return 0;
474  }
475  if(swap) SwapBytes((char *)&numData, sizeof(int), 1);
476  }
477  std::vector<int> data;
478  if(numData > 0) {
479  data.resize(numData);
480  if(!binary) {
481  for(int j = 0; j < numData; j++) {
482  if(fscanf(fp, "%d", &data[j]) != 1) {
483  fclose(fp);
484  return 0;
485  }
486  }
487  }
488  else {
489  if((int)fread(&data[0], sizeof(int), numData, fp) != numData) {
490  fclose(fp);
491  return 0;
492  }
493  if(swap) SwapBytes((char *)&data[0], sizeof(int), numData);
494  }
495  }
497  MElement *element = f.create(num, type, data, this);
498  if(!element) {
499  fclose(fp);
500  return 0;
501  }
502  switch(element->getType()) {
503  case TYPE_PNT: elements[0][entity].push_back(element); break;
504  case TYPE_LIN: elements[1][entity].push_back(element); break;
505  case TYPE_TRI: elements[2][entity].push_back(element); break;
506  case TYPE_QUA: elements[3][entity].push_back(element); break;
507  case TYPE_TET: elements[4][entity].push_back(element); break;
508  case TYPE_HEX: elements[5][entity].push_back(element); break;
509  case TYPE_PRI: elements[6][entity].push_back(element); break;
510  case TYPE_PYR: elements[7][entity].push_back(element); break;
511  case TYPE_TRIH: elements[8][entity].push_back(element); break;
512  case TYPE_POLYG: elements[9][entity].push_back(element); break;
513  case TYPE_POLYH: elements[10][entity].push_back(element); break;
514  }
515  if(numElements > 100000)
516  Msg::ProgressMeter(i + 1, true, "Reading elements");
517  }
519  }
520 
521  // $Periodical section
522  else if(!strncmp(&str[1], "Periodic", 8)) {
523  readMSHPeriodicNodes(fp, this);
524  }
525 
526  // Post-processing sections
527  else if(!strncmp(&str[1], "NodeData", 8) ||
528  !strncmp(&str[1], "ElementData", 11) ||
529  !strncmp(&str[1], "ElementNodeData", 15)) {
530  postpro = true;
531  break;
532  }
533 
534  do {
535  if(!fgets(str, sizeof(str), fp) || feof(fp)) break;
536  } while(str[0] != '$');
537  }
538 
539  // store the elements in their associated elementary entity. If the
540  // entity does not exist, create a new (discrete) one.
541  for(int i = 0; i < (int)(sizeof(elements) / sizeof(elements[0])); i++)
542  _storeElementsInEntities(elements[i]);
543 
544  // associate the correct geometrical entity with each mesh vertex
546 
547  // store the vertices in their associated geometrical entity
548  if(_vertexVectorCache.size())
550  else
552 
553  for(int i = 0; i < (int)(sizeof(elements) / sizeof(elements[0])); i++)
554  _storeParentsInSubElements(elements[i]);
555 
556  fclose(fp);
557 
558  // create new partition entities if the mesh is partitioned
559  if(CTX::instance()->mesh.partitionConvertMsh2 &&
560  getNumPartitions() > oldNumPartitions)
562 
563  return postpro ? 2 : 1;
564 }
565 
566 static void writeMSHPhysicals(FILE *fp, GEntity *ge)
567 {
568  std::vector<int> phys = ge->physicals;
569  fprintf(fp, "%d ", (int)phys.size());
570  for(auto itp = phys.begin(); itp != phys.end(); itp++)
571  fprintf(fp, "%d ", *itp);
572 }
573 
574 void writeMSHEntities(FILE *fp, GModel *gm) // also used in MSH2
575 {
576  fprintf(fp, "$Entities\n");
577  fprintf(fp, "%lu %lu %lu %lu\n", gm->getNumVertices(), gm->getNumEdges(),
578  gm->getNumFaces(), gm->getNumRegions());
579  for(auto it = gm->firstVertex(); it != gm->lastVertex(); ++it) {
580  fprintf(fp, "%d ", (*it)->tag());
581  writeMSHPhysicals(fp, *it);
582  fprintf(fp, "\n");
583  }
584  for(auto it = gm->firstEdge(); it != gm->lastEdge(); ++it) {
585  std::list<GVertex *> vertices;
586  if((*it)->getBeginVertex()) vertices.push_back((*it)->getBeginVertex());
587  if((*it)->getEndVertex()) vertices.push_back((*it)->getEndVertex());
588  fprintf(fp, "%d %d ", (*it)->tag(), (int)vertices.size());
589  for(auto itv = vertices.begin(); itv != vertices.end(); itv++) {
590  fprintf(fp, "%d ", (*itv)->tag());
591  }
592  writeMSHPhysicals(fp, *it);
593  fprintf(fp, "\n");
594  }
595  for(auto it = gm->firstFace(); it != gm->lastFace(); ++it) {
596  std::vector<GEdge *> const &edges = (*it)->edges();
597  std::vector<int> const &ori = (*it)->edgeOrientations();
598  fprintf(fp, "%d %d ", (*it)->tag(), (int)edges.size());
599  std::vector<int> tags;
600  for(auto ite = edges.begin(); ite != edges.end(); ite++)
601  tags.push_back((*ite)->tag());
602 
603  std::vector<int> signs(ori.begin(), ori.end());
604 
605  if(tags.size() == signs.size()) {
606  for(std::size_t i = 0; i < tags.size(); i++)
607  tags[i] *= (signs[i] > 0 ? 1 : -1);
608  }
609  for(std::size_t i = 0; i < tags.size(); i++) fprintf(fp, "%d ", tags[i]);
610  writeMSHPhysicals(fp, *it);
611  fprintf(fp, "\n");
612  }
613  for(auto it = gm->firstRegion(); it != gm->lastRegion(); ++it) {
614  std::vector<GFace *> faces = (*it)->faces();
615  std::vector<int> ori = (*it)->faceOrientations();
616  fprintf(fp, "%d %d ", (*it)->tag(), (int)faces.size());
617  std::vector<int> tags, signs;
618  for(auto itf = faces.begin(); itf != faces.end(); itf++)
619  tags.push_back((*itf)->tag());
620  for(auto itf = ori.begin(); itf != ori.end(); itf++)
621  signs.push_back(*itf);
622  if(tags.size() == signs.size()) {
623  for(std::size_t i = 0; i < tags.size(); i++)
624  tags[i] *= (signs[i] > 0 ? 1 : -1);
625  }
626  for(std::size_t i = 0; i < tags.size(); i++) fprintf(fp, "%d ", tags[i]);
627  writeMSHPhysicals(fp, *it);
628  fprintf(fp, "\n");
629  }
630  fprintf(fp, "$EndEntities\n");
631 }
632 
633 static int getNumElementsMSH(GEntity *ge, bool saveAll, int saveSinglePartition)
634 {
635  int n = 0;
636  if(saveAll || ge->physicals.size()) {
637  if(saveSinglePartition <= 0)
638  n = ge->getNumMeshElements();
639  else
640  for(std::size_t i = 0; i < ge->getNumMeshElements(); i++)
641  if(ge->getMeshElement(i)->getPartition() == saveSinglePartition) n++;
642  }
643  return n;
644 }
645 
646 static void writeElementMSH(FILE *fp, GModel *model, MElement *ele, bool binary,
647  int elementary)
648 {
649  if(model->getGhostCells().size()) {
650  std::vector<short> ghosts;
651  auto itp = model->getGhostCells().equal_range(ele);
652  for(auto it = itp.first; it != itp.second; it++)
653  ghosts.push_back(it->second);
654  ele->writeMSH3(fp, binary, elementary, &ghosts);
655  }
656  else
657  ele->writeMSH3(fp, binary, elementary);
658 }
659 
660 template <class T>
661 static void writeElementsMSH(FILE *fp, GModel *model, GEntity *ge,
662  std::vector<T *> &ele, bool saveAll,
663  int saveSinglePartition, bool binary)
664 {
665  if(saveAll || ge->physicals.size()) {
666  for(std::size_t i = 0; i < ele.size(); i++) {
667  if(saveSinglePartition && ele[i]->getPartition() != saveSinglePartition)
668  continue;
669  writeElementMSH(fp, model, ele[i], binary, ge->tag());
670  }
671  }
672 }
673 
674 void writeMSHPeriodicNodes(FILE *fp, std::vector<GEntity *> &entities,
675  bool renumber, bool saveAll) // also used in MSH2
676 {
677  int count = 0;
678  for(std::size_t i = 0; i < entities.size(); i++) {
679  if(entities[i]->getMeshMaster() != entities[i] &&
680  (saveAll || (entities[i]->physicals.size() &&
681  entities[i]->getMeshMaster()->physicals.size()))) {
682  count++;
683  }
684  }
685  if(!count) return;
686  fprintf(fp, "$Periodic\n");
687  fprintf(fp, "%d\n", count);
688  for(std::size_t i = 0; i < entities.size(); i++) {
689  GEntity *g_slave = entities[i];
690  GEntity *g_master = g_slave->getMeshMaster();
691  if(g_slave != g_master &&
692  (saveAll || (entities[i]->physicals.size() &&
693  entities[i]->getMeshMaster()->physicals.size()))) {
694  fprintf(fp, "%d %d %d\n", g_slave->dim(), g_slave->tag(),
695  g_master->tag());
696 
697  if(g_slave->affineTransform.size() == 16) {
698  fprintf(fp, "Affine");
699  for(int i = 0; i < 16; i++)
700  fprintf(fp, " %.16g", g_slave->affineTransform[i]);
701  fprintf(fp, "\n");
702  }
703 
704  std::map<MVertex *, MVertex *, MVertexPtrLessThan> corrVert;
705  corrVert.insert(g_slave->correspondingVertices.begin(),
706  g_slave->correspondingVertices.end());
707  if(CTX::instance()->mesh.hoSavePeriodic)
708  corrVert.insert(g_slave->correspondingHighOrderVertices.begin(),
709  g_slave->correspondingHighOrderVertices.end());
710 
711  fprintf(fp, "%d\n", (int)corrVert.size());
712  for(auto it = corrVert.begin(); it != corrVert.end(); it++) {
713  MVertex *v1 = it->first;
714  MVertex *v2 = it->second;
715  if(renumber)
716  fprintf(fp, "%ld %ld\n", v1->getIndex(), v2->getIndex());
717  else
718  fprintf(fp, "%lu %lu\n", v1->getNum(), v2->getNum());
719  }
720  }
721  }
722  fprintf(fp, "$EndPeriodic\n");
723 }
724 
725 int GModel::_writeMSH3(const std::string &name, double version, bool binary,
726  bool saveAll, bool saveParametric, double scalingFactor,
727  int elementStartNum, int saveSinglePartition,
728  bool append)
729 {
730  if(version < 3. || version >= 4.) {
731  Msg::Error("Wrong MSH file version %g for MSH3 writer", version);
732  return 0;
733  }
734 
735  FILE *fp;
736  if(append)
737  fp = Fopen(name.c_str(), binary ? "ab" : "a");
738  else
739  fp = Fopen(name.c_str(), binary ? "wb" : "w");
740  if(!fp) {
741  Msg::Error("Unable to open file '%s'", name.c_str());
742  return 0;
743  }
744 
745  // should make this available to users, and should allow to renumber elements,
746  // too. Renumbering should be disabled by default.
747  bool renumber = false;
748 
749  // if there are no physicals we save all the elements
750  if(noPhysicalGroups()) saveAll = true;
751 
752  // get the number of vertices and index the vertices in a continuous
753  // sequence
754  int numVertices = indexMeshVertices(saveAll, saveSinglePartition, renumber);
755 
756  // get the number of elements we need to save
757  std::vector<GEntity *> entities;
758  getEntities(entities);
759  int numElements = 0;
760  for(std::size_t i = 0; i < entities.size(); i++)
761  numElements += getNumElementsMSH(entities[i], saveAll, saveSinglePartition);
762 
763  fprintf(fp, "$MeshFormat\n");
764  fprintf(fp, "%g %d %d\n", version, binary ? 1 : 0, (int)sizeof(double));
765  if(binary) {
766  int one = 1;
767  fwrite(&one, sizeof(int), 1, fp);
768  fprintf(fp, "\n");
769  }
770  fprintf(fp, "$EndMeshFormat\n");
771 
772  if(numPhysicalNames()) {
773  fprintf(fp, "$PhysicalNames\n");
774  fprintf(fp, "%d\n", numPhysicalNames());
775  for(auto it = firstPhysicalName(); it != lastPhysicalName(); it++) {
776  std::string name = it->second;
777  if(name.size() > 254) name.resize(254);
778  fprintf(fp, "%d %d \"%s\"\n", it->first.first, it->first.second,
779  name.c_str());
780  }
781  fprintf(fp, "$EndPhysicalNames\n");
782  }
783 
784  writeMSHEntities(fp, this);
785 
786  fprintf(fp, "$Nodes\n");
787  fprintf(fp, "%d\n", numVertices);
788  for(std::size_t i = 0; i < entities.size(); i++)
789  for(std::size_t j = 0; j < entities[i]->mesh_vertices.size(); j++)
790  entities[i]->mesh_vertices[j]->writeMSH(fp, binary, saveParametric,
791  scalingFactor);
792 
793  if(binary) fprintf(fp, "\n");
794  fprintf(fp, "$EndNodes\n");
795 
796  fprintf(fp, "$Elements\n");
797  fprintf(fp, "%d\n", numElements);
798 
799  _elementIndexCache.clear();
800 
801  for(auto it = firstRegion(); it != lastRegion(); ++it)
802  writeElementsMSH(fp, this, *it, (*it)->tetrahedra, saveAll,
803  saveSinglePartition, binary);
804  for(auto it = firstRegion(); it != lastRegion(); ++it)
805  writeElementsMSH(fp, this, *it, (*it)->hexahedra, saveAll,
806  saveSinglePartition, binary);
807  for(auto it = firstRegion(); it != lastRegion(); ++it)
808  writeElementsMSH(fp, this, *it, (*it)->prisms, saveAll, saveSinglePartition,
809  binary);
810  for(auto it = firstRegion(); it != lastRegion(); ++it)
811  writeElementsMSH(fp, this, *it, (*it)->pyramids, saveAll,
812  saveSinglePartition, binary);
813  for(auto it = firstRegion(); it != lastRegion(); ++it)
814  writeElementsMSH(fp, this, *it, (*it)->trihedra, saveAll,
815  saveSinglePartition, binary);
816  for(auto it = firstFace(); it != lastFace(); ++it)
817  writeElementsMSH(fp, this, *it, (*it)->triangles, saveAll,
818  saveSinglePartition, binary);
819  for(auto it = firstFace(); it != lastFace(); ++it)
820  writeElementsMSH(fp, this, *it, (*it)->quadrangles, saveAll,
821  saveSinglePartition, binary);
822  for(auto it = firstEdge(); it != lastEdge(); ++it)
823  writeElementsMSH(fp, this, *it, (*it)->lines, saveAll, saveSinglePartition,
824  binary);
825  for(auto it = firstVertex(); it != lastVertex(); ++it)
826  writeElementsMSH(fp, this, *it, (*it)->points, saveAll, saveSinglePartition,
827  binary);
828 
829  if(binary) fprintf(fp, "\n");
830 
831  fprintf(fp, "$EndElements\n");
832 
833  // save periodic nodes
834  writeMSHPeriodicNodes(fp, entities, renumber, saveAll);
835 
836  fclose(fp);
837 
838  return 1;
839 }
840 
841 int GModel::_writePartitionedMSH3(const std::string &baseName, double version,
842  bool binary, bool saveAll,
843  bool saveParametric, double scalingFactor)
844 {
845  if(version < 3. || version >= 4.) {
846  Msg::Error("Wrong MSH file version %g for MSH3 writer", version);
847  return 0;
848  }
849 
850  for(std::size_t partition = 0; partition < getNumPartitions(); partition++) {
851  std::ostringstream sstream;
852  sstream << baseName << "_" << std::setw(6) << std::setfill('0')
853  << partition;
854  Msg::Info("Writing partition %d in file '%s'", partition,
855  sstream.str().c_str());
856  _writeMSH3(sstream.str(), version, binary, saveAll, saveParametric,
857  scalingFactor, 0, partition, false);
858  }
859  return 1;
860 }
MTriangle.h
GModel::getGhostCells
std::multimap< MElement *, short > & getGhostCells()
Definition: GModel.h:618
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
GEntity::correspondingHighOrderVertices
std::map< MVertex *, MVertex * > correspondingHighOrderVertices
Definition: GEntity.h:409
GModel::_readMSH3
int _readMSH3(const std::string &name)
Definition: GModelIO_MSH3.cpp:190
GModel::convertOldPartitioningToNewOne
int convertOldPartitioningToNewOne()
Definition: GModel.cpp:2236
GModel::_writePartitionedMSH3
int _writePartitionedMSH3(const std::string &baseName, double version, bool binary, bool saveAll, bool saveParametric, double scalingFactor)
Definition: GModelIO_MSH3.cpp:841
TYPE_LIN
#define TYPE_LIN
Definition: GmshDefines.h:65
GFace
Definition: GFace.h:33
Msg::Info
static void Info(const char *fmt,...)
Definition: GmshMessage.cpp:587
discreteRegion.h
MElementFactory
Definition: MElement.h:517
OS.h
Msg::Debug
static void Debug(const char *fmt,...)
Definition: GmshMessage.cpp:752
discreteEdge
Definition: discreteEdge.h:12
MVertex
Definition: MVertex.h:24
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
GEntity::physicals
std::vector< int > physicals
Definition: GEntity.h:65
LegendrePolynomials::f
void f(int n, double u, double *val)
Definition: orthogonalBasis.cpp:77
MElement::writeMSH3
virtual void writeMSH3(FILE *fp, bool binary=false, int elementary=1, std::vector< short > *ghosts=nullptr)
Definition: MElement.cpp:1473
MVertex::getNum
std::size_t getNum() const
Definition: MVertex.h:86
GModel::getFaceByTag
GFace * getFaceByTag(int n) const
Definition: GModel.cpp:326
TYPE_PNT
#define TYPE_PNT
Definition: GmshDefines.h:64
GModel::_storeElementsInEntities
void _storeElementsInEntities(std::map< int, std::vector< MElement * > > &map)
Definition: GModel.cpp:2273
GModel::getMeshVertexByTag
MVertex * getMeshVertexByTag(int n)
Definition: GModel.cpp:1953
TYPE_TRI
#define TYPE_TRI
Definition: GmshDefines.h:66
MPoint.h
GModel::firstVertex
viter firstVertex()
Definition: GModel.h:357
GModel::getEdgeByTag
GEdge * getEdgeByTag(int n) const
Definition: GModel.cpp:336
GmshMessage.h
MLine.h
edges
static int edges[6][2]
Definition: meshGRegionLocalMeshMod.cpp:23
writeElementsMSH
static void writeElementsMSH(FILE *fp, GModel *model, GEntity *ge, std::vector< T * > &ele, bool saveAll, int saveSinglePartition, bool binary)
Definition: GModelIO_MSH3.cpp:661
GEntity
Definition: GEntity.h:31
GModel::firstPhysicalName
piter firstPhysicalName()
Definition: GModel.h:458
TYPE_PRI
#define TYPE_PRI
Definition: GmshDefines.h:70
GEntity::getMeshMaster
GEntity * getMeshMaster() const
Definition: GEntity.h:291
GModel::getNumPartitions
std::size_t getNumPartitions() const
Definition: GModel.h:602
readMSHPhysicals
static int readMSHPhysicals(FILE *fp, GEntity *ge)
Definition: GModelIO_MSH3.cpp:29
readMSHPeriodicNodes
void readMSHPeriodicNodes(FILE *fp, GModel *gm)
Definition: GModelIO_MSH3.cpp:125
discreteRegion
Definition: discreteRegion.h:13
Fopen
FILE * Fopen(const char *f, const char *mode)
Definition: OS.cpp:273
GModel::_elementIndexCache
std::map< int, int > _elementIndexCache
Definition: GModel.h:105
discreteVertex.h
CTX::instance
static CTX * instance()
Definition: Context.cpp:122
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
MHexahedron.h
MEdgeVertex
Definition: MVertex.h:137
GModel::lastVertex
viter lastVertex()
Definition: GModel.h:361
GEntity::getNumMeshElements
virtual std::size_t getNumMeshElements() const
Definition: GEntity.h:348
GVertex
Definition: GVertex.h:23
swap
void swap(double &a, double &b)
Definition: meshTriangulation.cpp:27
GModel::getNumVertices
std::size_t getNumVertices() const
Definition: GModel.h:347
GModel
Definition: GModel.h:44
Msg::StopProgressMeter
static void StopProgressMeter()
Definition: GmshMessage.cpp:318
MPyramid.h
getNumElementsMSH
static int getNumElementsMSH(GEntity *ge, bool saveAll, int saveSinglePartition)
Definition: GModelIO_MSH3.cpp:633
GModel::firstFace
fiter firstFace()
Definition: GModel.h:355
GModel::add
bool add(GRegion *r)
Definition: GModel.h:394
GModel::getNumRegions
std::size_t getNumRegions() const
Definition: GModel.h:344
MElement
Definition: MElement.h:30
ExtractDoubleQuotedString
std::string ExtractDoubleQuotedString(const char *str, int len)
Definition: StringUtils.cpp:27
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
GModel::getNumFaces
std::size_t getNumFaces() const
Definition: GModel.h:345
discreteFace.h
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
GModel::_writeMSH3
int _writeMSH3(const std::string &name, double version, bool binary, bool saveAll, bool saveParametric, double scalingFactor, int elementStartNum, int saveSinglePartition, bool append)
Definition: GModelIO_MSH3.cpp:725
GRegion
Definition: GRegion.h:28
GModel::getNumEdges
std::size_t getNumEdges() const
Definition: GModel.h:346
TYPE_PYR
#define TYPE_PYR
Definition: GmshDefines.h:69
StringUtils.h
GModel::writeMSH
int writeMSH(const std::string &name, double version=2.2, bool binary=false, bool saveAll=false, bool saveParametric=false, double scalingFactor=1.0, int elementStartNum=0, int saveSinglePartition=0, bool append=false)
Definition: GModelIO_MSH.cpp:76
LegendrePolynomials::df
void df(int n, double u, double *val)
Definition: orthogonalBasis.cpp:103
GModel::firstRegion
riter firstRegion()
Definition: GModel.h:354
writeMSHPhysicals
static void writeMSHPhysicals(FILE *fp, GEntity *ge)
Definition: GModelIO_MSH3.cpp:566
TYPE_QUA
#define TYPE_QUA
Definition: GmshDefines.h:67
GModel::lastRegion
riter lastRegion()
Definition: GModel.h:358
TYPE_POLYG
#define TYPE_POLYG
Definition: GmshDefines.h:72
GModel::_storeParentsInSubElements
void _storeParentsInSubElements(std::map< int, std::vector< MElement * > > &map)
Definition: GModel.cpp:2347
discreteEdge.h
MVertex::getIndex
long int getIndex() const
Definition: MVertex.h:93
Context.h
GEntity::getMeshElement
virtual MElement * getMeshElement(std::size_t index) const
Definition: GEntity.h:363
MTetrahedron.h
GModel::lastPhysicalName
piter lastPhysicalName()
Definition: GModel.h:459
MQuadrangle.h
writeMSHPeriodicNodes
void writeMSHPeriodicNodes(FILE *fp, std::vector< GEntity * > &entities, bool renumber, bool saveAll)
Definition: GModelIO_MSH3.cpp:674
MElement.h
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
TYPE_HEX
#define TYPE_HEX
Definition: GmshDefines.h:71
writeMSHEntities
void writeMSHEntities(FILE *fp, GModel *gm)
Definition: GModelIO_MSH3.cpp:574
MPrism.h
TYPE_TET
#define TYPE_TET
Definition: GmshDefines.h:68
GModel::setPhysicalName
int setPhysicalName(const std::string &name, int dim, int num=0)
Definition: GModel.cpp:937
GModel::mesh
int mesh(int dimension)
Definition: GModel.cpp:1066
TYPE_TRIH
#define TYPE_TRIH
Definition: GmshDefines.h:76
writeElementMSH
static void writeElementMSH(FILE *fp, GModel *model, MElement *ele, bool binary, int elementary)
Definition: GModelIO_MSH3.cpp:646
GModel::lastEdge
eiter lastEdge()
Definition: GModel.h:360
GModel.h
GModel::getRegionByTag
GRegion * getRegionByTag(int n) const
Definition: GModel.cpp:316
GModel::_storeVerticesInEntities
void _storeVerticesInEntities(std::map< int, MVertex * > &vertices)
Definition: GModel.cpp:2496
MElement::getPartition
virtual int getPartition() const
Definition: MElement.h:92
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
GRegion::setBoundFaces
void setBoundFaces(const std::set< int > &tagFaces)
Definition: GRegion.cpp:294
GEntity::correspondingVertices
std::map< MVertex *, MVertex * > correspondingVertices
Definition: GEntity.h:406
GModel::_associateEntityWithMeshVertices
void _associateEntityWithMeshVertices()
Definition: GModel.cpp:2470
TYPE_POLYH
#define TYPE_POLYH
Definition: GmshDefines.h:73
GModel::indexMeshVertices
std::size_t indexMeshVertices(bool all, int singlePartition=0, bool renumber=true)
Definition: GModel.cpp:2135
discreteFace
Definition: discreteFace.h:18
faces
static int faces[4][3]
Definition: meshGRegionDelaunayInsertion.cpp:165
readMSHEntities
static void readMSHEntities(FILE *fp, GModel *gm)
Definition: GModelIO_MSH3.cpp:41