gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
GModelIO_MED.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 <string>
7 #include "GmshConfig.h"
8 #include "GmshMessage.h"
9 #include "GModel.h"
10 
11 #if defined(HAVE_MED)
12 
13 #include <string.h>
14 #include <map>
15 #include <sstream>
16 #include <vector>
17 #include "MVertex.h"
18 #include "MPoint.h"
19 #include "MLine.h"
20 #include "MTriangle.h"
21 #include "MQuadrangle.h"
22 #include "MTetrahedron.h"
23 #include "MHexahedron.h"
24 #include "MPrism.h"
25 #include "MPyramid.h"
26 #include "discreteVertex.h"
27 #include "Context.h"
28 
29 #include <med.h>
30 
31 #if(MED_MAJOR_NUM >= 3)
32 // To avoid too many ifdefs below we use defines for the bits of the
33 // API that did not change too much between MED2 and MED3. If we remove
34 // MED2 support at some point, please remove these defines and replace
35 // the symbols accordingly.
36 #define med_geometrie_element med_geometry_type
37 #define med_maillage med_mesh_type
38 #define MED_TAILLE_NOM MED_NAME_SIZE
39 #define MED_TAILLE_LNOM MED_LNAME_SIZE
40 #define MED_TAILLE_DESC MED_COMMENT_SIZE
41 #define MED_NON_STRUCTURE MED_UNSTRUCTURED_MESH
42 #define MED_LECTURE MED_ACC_RDONLY
43 #define MED_CREATION MED_ACC_CREAT
44 #define MEDouvrir MEDfileOpen
45 #define MEDversionDonner MEDlibraryNumVersion
46 #define MEDversionLire MEDfileNumVersionRd
47 #define MEDnMaa MEDnMesh
48 #define MEDfermer MEDfileClose
49 #define MEDnFam MEDnFamily
50 #define MEDfichDesEcr MEDfileCommentWr
51 #endif
52 
53 med_geometrie_element msh2medElementType(int msh)
54 {
55  switch(msh) {
56  case MSH_LIN_2: return MED_SEG2;
57  case MSH_TRI_3: return MED_TRIA3;
58  case MSH_QUA_4: return MED_QUAD4;
59  case MSH_TET_4: return MED_TETRA4;
60  case MSH_HEX_8: return MED_HEXA8;
61  case MSH_PRI_6: return MED_PENTA6;
62  case MSH_PYR_5: return MED_PYRA5;
63  case MSH_LIN_3: return MED_SEG3;
64  case MSH_TRI_6: return MED_TRIA6;
65  case MSH_TET_10: return MED_TETRA10;
66  case MSH_PNT: return MED_POINT1;
67  case MSH_QUA_8: return MED_QUAD8;
68  case MSH_HEX_20: return MED_HEXA20;
69  case MSH_PRI_15: return MED_PENTA15;
70 #if(MED_MAJOR_NUM >= 4)
71  case MSH_PRI_18: return MED_PENTA18;
72 #endif
73  case MSH_PYR_13: return MED_PYRA13;
74 #if(MED_MAJOR_NUM >= 3)
75  case MSH_QUA_9: return MED_QUAD9;
76  case MSH_HEX_27: return MED_HEXA27;
77 #endif
78  default: return MED_NONE;
79  }
80 }
81 
82 int med2mshElementType(med_geometrie_element med)
83 {
84  switch(med) {
85  case MED_SEG2: return MSH_LIN_2;
86  case MED_TRIA3: return MSH_TRI_3;
87  case MED_QUAD4: return MSH_QUA_4;
88  case MED_TETRA4: return MSH_TET_4;
89  case MED_HEXA8: return MSH_HEX_8;
90  case MED_PENTA6: return MSH_PRI_6;
91  case MED_PYRA5: return MSH_PYR_5;
92  case MED_SEG3: return MSH_LIN_3;
93  case MED_TRIA6: return MSH_TRI_6;
94  case MED_TETRA10: return MSH_TET_10;
95  case MED_POINT1: return MSH_PNT;
96  case MED_QUAD8: return MSH_QUA_8;
97  case MED_HEXA20: return MSH_HEX_20;
98  case MED_PENTA15: return MSH_PRI_15;
99 #if(MED_MAJOR_NUM >= 4)
100  case MED_PENTA18: return MSH_PRI_18;
101 #endif
102  case MED_PYRA13: return MSH_PYR_13;
103 #if(MED_MAJOR_NUM >= 3)
104  case MED_QUAD9: return MSH_QUA_9;
105  case MED_HEXA27: return MSH_HEX_27;
106 #endif
107  default: return 0;
108  }
109 }
110 
111 int msh2medNodeIndex(int msh, int k)
112 {
113  med_geometrie_element med = msh2medElementType(msh);
114  switch(med) {
115  case MED_POINT1:
116  case MED_SEG2:
117  case MED_SEG3:
118  case MED_TRIA3:
119  case MED_TRIA6:
120  case MED_QUAD4:
121  case MED_QUAD8:
122 #if(MED_MAJOR_NUM >= 3)
123  case MED_QUAD9:
124 #endif
125  return k; // same node numbering as in Gmsh
126  case MED_TETRA4: {
127  static const int map[4] = {0, 2, 1, 3};
128  return map[k];
129  }
130  case MED_TETRA10: {
131  static const int map[10] = {0, 2, 1, 3, 6, 5, 4, 7, 8, 9};
132  return map[k];
133  }
134  case MED_HEXA8: {
135  static const int map[8] = {0, 3, 2, 1, 4, 7, 6, 5};
136  return map[k];
137  }
138  case MED_HEXA20: {
139  static const int map[20] = {0, 3, 2, 1, 4, 7, 6, 5, 9, 13,
140  11, 8, 17, 19, 18, 16, 10, 15, 14, 12};
141 
142  return map[k];
143  }
144 #if(MED_MAJOR_NUM >= 3)
145  case MED_HEXA27: {
146  static const int map[27] = {0, 3, 2, 1, 4, 7, 6, 5, 9,
147  13, 11, 8, 17, 19, 18, 16, 10, 15,
148  14, 12, 20, 22, 24, 23, 21, 25, 26};
149  return map[k];
150  }
151 #endif
152  case MED_PENTA6: {
153  static const int map[6] = {0, 2, 1, 3, 5, 4};
154  return map[k];
155  }
156  case MED_PENTA15: {
157  static const int map[15] = {0, 2, 1, 3, 5, 4, 7, 9,
158  6, 13, 14, 12, 8, 11, 10};
159  return map[k];
160  }
161 #if(MED_MAJOR_NUM >= 4)
162  case MED_PENTA18: {
163  static const int map[18] = {0, 2, 1, 3, 5, 4, 7, 9, 6,
164  13, 14, 12, 8, 11, 10, 16, 17, 15};
165  return map[k];
166  }
167 #endif
168  case MED_PYRA5: {
169  static const int map[5] = {0, 3, 2, 1, 4};
170  return map[k];
171  }
172  case MED_PYRA13: {
173  static const int map[13] = {0, 3, 2, 1, 4, 6, 10, 8, 5, 7, 12, 11, 9};
174  return map[k];
175  }
176  default: Msg::Error("Unknown MED element type"); return k;
177  }
178 }
179 
180 int med2mshNodeIndex(med_geometrie_element med, int k)
181 {
182  switch(med) {
183  case MED_POINT1:
184  case MED_SEG2:
185  case MED_SEG3:
186  case MED_TRIA3:
187  case MED_TRIA6:
188  case MED_QUAD4:
189  case MED_QUAD8:
190 #if(MED_MAJOR_NUM >= 3)
191  case MED_QUAD9:
192 #endif
193  return k; // same node numbering as in Gmsh
194  case MED_TETRA4:
195  case MED_TETRA10:
196  case MED_HEXA8:
197  case MED_PENTA6:
198  case MED_PYRA5:
199  return msh2medNodeIndex(med2mshElementType(med), k); // symmetric
200  case MED_HEXA20: {
201  static const int map[20] = {0, 3, 2, 1, 4, 7, 6, 5, 11, 8,
202  16, 10, 19, 9, 18, 17, 15, 12, 14, 13};
203  return map[k];
204  }
205 #if(MED_MAJOR_NUM >= 3)
206  case MED_HEXA27: {
207  static const int map[27] = {0, 3, 2, 1, 4, 7, 6, 5, 11,
208  8, 16, 10, 19, 9, 18, 17, 15, 12,
209  14, 13, 20, 24, 21, 23, 22, 25, 26};
210  return map[k];
211  }
212 #endif
213  case MED_PENTA15: {
214  static const int map[15] = {0, 2, 1, 3, 5, 4, 8, 6,
215  12, 7, 14, 13, 11, 9, 10};
216  return map[k];
217  }
218 #if(MED_MAJOR_NUM >= 4)
219  case MED_PENTA18: {
220  static const int map[18] = {0, 2, 1, 3, 5, 4, 8, 6, 12,
221  7, 14, 13, 11, 9, 10, 17, 15, 16};
222  return map[k];
223  }
224 #endif
225  case MED_PYRA13: {
226  static const int map[13] = {0, 3, 2, 1, 4, 8, 5, 9, 7, 12, 6, 11, 10};
227  return map[k];
228  }
229  default: Msg::Error("Unknown MED element type"); return k;
230  }
231 }
232 
233 int GModel::readMED(const std::string &name)
234 {
235  med_idt fid = MEDouvrir((char *)name.c_str(), MED_LECTURE);
236  if(fid < 0) {
237  Msg::Error("Unable to open file '%s'", name.c_str());
238  return 0;
239  }
240 
241  med_int v[3], vf[3];
242  MEDversionDonner(&v[0], &v[1], &v[2]);
243  MEDversionLire(fid, &vf[0], &vf[1], &vf[2]);
244  Msg::Info("Reading MED file V%d.%d.%d using MED library V%d.%d.%d", vf[0],
245  vf[1], vf[2], v[0], v[1], v[2]);
246  if(vf[0] < 2 || (vf[0] == 2 && vf[1] < 2)) {
247  Msg::Error("Cannot read MED file older than V2.2");
248  return 0;
249  }
250 
251  std::vector<std::string> meshNames;
252  for(int i = 0; i < MEDnMaa(fid); i++) {
253  char meshName[MED_TAILLE_NOM + 1], meshDesc[MED_TAILLE_DESC + 1];
254  med_int spaceDim;
255  med_maillage meshType;
256 #if(MED_MAJOR_NUM >= 3)
257  med_int meshDim, nStep;
258  char dtUnit[MED_SNAME_SIZE + 1];
259  char axisName[3 * MED_SNAME_SIZE + 1], axisUnit[3 * MED_SNAME_SIZE + 1];
260  med_sorting_type sortingType;
261  med_axis_type axisType;
262  if(MEDmeshInfo(fid, i + 1, meshName, &spaceDim, &meshDim, &meshType,
263  meshDesc, dtUnit, &sortingType, &nStep, &axisType, axisName,
264  axisUnit) < 0) {
265 #else
266  if(MEDmaaInfo(fid, i + 1, meshName, &spaceDim, &meshType, meshDesc) < 0) {
267 #endif
268  Msg::Error("Unable to read mesh information");
269  return 0;
270  }
271  meshNames.push_back(meshName);
272  }
273 
274  if(MEDfermer(fid) < 0) {
275  Msg::Error("Unable to close file '%s'", name.c_str());
276  return 0;
277  }
278 
279  int ret = 1;
280  for(std::size_t i = 0; i < meshNames.size(); i++) {
281  // we use the filename as a kind of "partition" indicator, allowing to
282  // complete a model part by part (used e.g. in DDM, since MED does not store
283  // a partition index)
284  GModel *m = findByName(meshNames[i], name);
285  if(!m) m = new GModel(meshNames[i]);
286  ret = m->readMED(name, i);
287  if(!ret) return 0;
288  }
289  return ret;
290 }
291 
292 int GModel::readMED(const std::string &name, int meshIndex)
293 {
294  med_idt fid = MEDouvrir((char *)name.c_str(), MED_LECTURE);
295  if(fid < 0) {
296  Msg::Error("Unable to open file '%s'", name.c_str());
297  return 0;
298  }
299 
300  int numMeshes = MEDnMaa(fid);
301  if(meshIndex >= numMeshes) {
302  Msg::Info("Could not find mesh %d in MED file", meshIndex);
303  return 0;
304  }
305 
307  GModel::setCurrent(this); // make sure we increment max nums in this model
308 
309  // read mesh info
310  char meshName[MED_TAILLE_NOM + 1], meshDesc[MED_TAILLE_DESC + 1];
311  med_int spaceDim, nStep = 1;
312  med_maillage meshType;
313 #if(MED_MAJOR_NUM >= 3)
314  med_int meshDim;
315  char dtUnit[MED_SNAME_SIZE + 1];
316  char axisName[3 * MED_SNAME_SIZE + 1], axisUnit[3 * MED_SNAME_SIZE + 1];
317  med_sorting_type sortingType;
318  med_axis_type axisType;
319  if(MEDmeshInfo(fid, meshIndex + 1, meshName, &spaceDim, &meshDim, &meshType,
320  meshDesc, dtUnit, &sortingType, &nStep, &axisType, axisName,
321  axisUnit) < 0) {
322 #else
323  if(MEDmaaInfo(fid, meshIndex + 1, meshName, &spaceDim, &meshType, meshDesc) <
324  0) {
325 #endif
326  Msg::Error("Unable to read mesh information");
327  return 0;
328  }
329 
330  // FIXME: we should support multi-step MED3 meshes (probably by
331  // storing each mesh as a separate model, with a naming convention
332  // e.g. meshName_step%d). This way we could also handle multi-mesh
333  // time sequences in MED3.
334  if(nStep > 1)
335  Msg::Warning("Discarding %d last meshes in multi-step MED mesh", nStep - 1);
336 
337  setName(meshName);
338  setFileName(name);
339  if(meshType == MED_NON_STRUCTURE) {
340  Msg::Info("Reading %d-D unstructured mesh '%s'", spaceDim, meshName);
341  }
342  else {
343  Msg::Error("Reading structured MED meshes is not supported");
344  return 0;
345  }
346  med_int vf[3];
347  MEDversionLire(fid, &vf[0], &vf[1], &vf[2]);
348 
349  // read nodes
350 #if(MED_MAJOR_NUM >= 3)
351  med_bool changeOfCoord, geoTransform;
352  med_int numNodes = MEDmeshnEntity(
353  fid, meshName, MED_NO_DT, MED_NO_IT, MED_NODE, MED_NO_GEOTYPE,
354  MED_COORDINATE, MED_NO_CMODE, &changeOfCoord, &geoTransform);
355 #else
356  med_int numNodes =
357  MEDnEntMaa(fid, meshName, MED_COOR, MED_NOEUD, MED_NONE, MED_NOD);
358 #endif
359  if(numNodes < 0) {
360  Msg::Error("Could not read number of MED nodes");
361  return 0;
362  }
363  if(numNodes == 0) {
364  Msg::Error("No nodes in MED mesh");
365  return 0;
366  }
367  std::vector<MVertex *> verts(numNodes);
368  std::vector<med_float> coord(spaceDim * numNodes);
369 #if(MED_MAJOR_NUM >= 3)
370  if(MEDmeshNodeCoordinateRd(fid, meshName, MED_NO_DT, MED_NO_IT,
371  MED_FULL_INTERLACE, &coord[0]) < 0) {
372 #else
373  std::vector<char> coordName(spaceDim * MED_TAILLE_PNOM + 1);
374  std::vector<char> coordUnit(spaceDim * MED_TAILLE_PNOM + 1);
375  med_repere rep;
376  if(MEDcoordLire(fid, meshName, spaceDim, &coord[0], MED_FULL_INTERLACE,
377  MED_ALL, 0, 0, &rep, &coordName[0], &coordUnit[0]) < 0) {
378 #endif
379  Msg::Error("Could not read MED node coordinates");
380  return 0;
381  }
382 
383  std::vector<med_int> nodeTags(numNodes);
384 #if(MED_MAJOR_NUM >= 3)
385  if(MEDmeshEntityNumberRd(fid, meshName, MED_NO_DT, MED_NO_IT, MED_NODE,
386  MED_NO_GEOTYPE, &nodeTags[0]) < 0)
387 #else
388  if(MEDnumLire(fid, meshName, &nodeTags[0], numNodes, MED_NOEUD, MED_NONE) < 0)
389 #endif
390  nodeTags.clear();
391 
392  for(int i = 0; i < numNodes; i++)
393  verts[i] = new MVertex(coord[spaceDim * i],
394  (spaceDim > 1) ? coord[spaceDim * i + 1] : 0.,
395  (spaceDim > 2) ? coord[spaceDim * i + 2] : 0.,
396  nullptr, nodeTags.empty() ? 0 : nodeTags[i]);
397 
398  std::vector<med_int> nodeFamily(numNodes, 0);
399 #if(MED_MAJOR_NUM >= 3)
400  MEDmeshEntityFamilyNumberRd(fid, meshName, MED_NO_DT, MED_NO_IT, MED_NODE,
401  MED_NONE, &nodeFamily[0]);
402 #else
403  MEDfamLire(fid, meshName, &nodeFamily[0], numEle, MED_NOEUD, MED_NONE);
404 #endif
405 
406  // read elements (loop over all possible MSH element types)
407  for(int mshType = 0; mshType < MSH_MAX_NUM + 1; mshType++) {
408  med_geometrie_element type = msh2medElementType(mshType);
409  if(type == MED_NONE) continue;
410 #if(MED_MAJOR_NUM >= 3)
411  med_bool changeOfCoord;
412  med_bool geoTransform;
413  med_int numEle = MEDmeshnEntity(fid, meshName, MED_NO_DT, MED_NO_IT,
414  MED_CELL, type, MED_CONNECTIVITY, MED_NODAL,
415  &changeOfCoord, &geoTransform);
416 #else
417  med_int numEle =
418  MEDnEntMaa(fid, meshName, MED_CONN, MED_MAILLE, type, MED_NOD);
419 #endif
420  if(numEle <= 0) continue;
421  int numNodPerEle = type % 100;
422  std::vector<med_int> conn(numEle * numNodPerEle);
423 #if(MED_MAJOR_NUM >= 3)
424  if(MEDmeshElementConnectivityRd(fid, meshName, MED_NO_DT, MED_NO_IT,
425  MED_CELL, type, MED_NODAL,
426  MED_FULL_INTERLACE, &conn[0]) < 0) {
427 #else
428  if(MEDconnLire(fid, meshName, spaceDim, &conn[0], MED_FULL_INTERLACE, 0,
429  MED_ALL, MED_MAILLE, type, MED_NOD) < 0) {
430 #endif
431  Msg::Error("Could not read MED elements");
432  return 0;
433  }
434  std::vector<med_int> elementFamily(numEle, 0);
435 #if(MED_MAJOR_NUM >= 3)
436  if(MEDmeshEntityFamilyNumberRd(fid, meshName, MED_NO_DT, MED_NO_IT,
437  MED_CELL, type, &elementFamily[0]) < 0) {
438 #else
439  if(MEDfamLire(fid, meshName, &elementFamily[0], numEle, MED_MAILLE, type) <
440  0) {
441 #endif
442  Msg::Info(
443  "No family number for elements: using 0 as default family number");
444  }
445  std::vector<med_int> eleTags(numEle);
446 #if(MED_MAJOR_NUM >= 3)
447  if(MEDmeshEntityNumberRd(fid, meshName, MED_NO_DT, MED_NO_IT, MED_CELL,
448  type, &eleTags[0]) < 0)
449 #else
450  if(MEDnumLire(fid, meshName, &eleTags[0], numEle, MED_MAILLE, type) < 0)
451 #endif
452  eleTags.clear();
453  std::map<int, std::vector<MElement *> > elements;
454  MElementFactory factory;
455  for(int j = 0; j < numEle; j++) {
456  std::vector<MVertex *> v(numNodPerEle);
457  bool ok = true;
458  for(int k = 0; k < numNodPerEle; k++) {
459  int idx = conn[numNodPerEle * j + med2mshNodeIndex(type, k)] - 1;
460  if(idx < 0 || idx > (int)verts.size() - 1) {
461  Msg::Error("Wrong node index %d in MED file", idx);
462  ok = false;
463  }
464  else {
465  v[k] = verts[idx];
466  }
467  }
468  if(ok) {
469  MElement *e =
470  factory.create(mshType, v, eleTags.empty() ? 0 : eleTags[j]);
471  // according to the MED documentation, elementFamily[j] should be
472  // negative (positive families are reserved for node families); still,
473  // accept all family ids, even positive, as some codes do not export
474  // valid MED files
475  if(e) elements[std::abs(elementFamily[j])].push_back(e);
476  }
477  }
478  _storeElementsInEntities(elements);
479  }
482 
483  // read family info
484  med_int numFamilies = MEDnFam(fid, meshName);
485  if(numFamilies < 0) {
486  Msg::Error("Could not read MED families");
487  return 0;
488  }
489  for(int i = 0; i < numFamilies; i++) {
490 #if(MED_MAJOR_NUM >= 3)
491  med_int numAttrib =
492  (vf[0] == 2) ? MEDnFamily23Attribute(fid, meshName, i + 1) : 0;
493  med_int numGroups = MEDnFamilyGroup(fid, meshName, i + 1);
494 #else
495  med_int numAttrib = MEDnAttribut(fid, meshName, i + 1);
496  med_int numGroups = MEDnGroupe(fid, meshName, i + 1);
497 #endif
498  if(numAttrib < 0 || numGroups < 0) {
499  Msg::Error("Could not read MED groups or attributes");
500  return 0;
501  }
502  std::vector<med_int> attribId(numAttrib + 1);
503  std::vector<med_int> attribVal(numAttrib + 1);
504  std::vector<char> attribDes(MED_TAILLE_DESC * numAttrib + 1);
505  std::vector<char> groupNames(MED_TAILLE_LNOM * numGroups + 1);
506  char familyName[MED_TAILLE_NOM + 1];
507  med_int familyNum;
508 #if(MED_MAJOR_NUM >= 3)
509  if(vf[0] == 2) { // MED2 file
510  if(MEDfamily23Info(fid, meshName, i + 1, familyName, &attribId[0],
511  &attribVal[0], &attribDes[0], &familyNum,
512  &groupNames[0]) < 0) {
513  Msg::Error("Could not read info for MED2 family %d", i + 1);
514  continue;
515  }
516  }
517  else {
518  if(MEDfamilyInfo(fid, meshName, i + 1, familyName, &familyNum,
519  &groupNames[0]) < 0) {
520  Msg::Error("Could not read info for MED3 family %d", i + 1);
521  continue;
522  }
523  }
524 #else
525  if(MEDfamInfo(fid, meshName, i + 1, familyName, &familyNum, &attribId[0],
526  &attribVal[0], &attribDes[0], &numAttrib, &groupNames[0],
527  &numGroups) < 0) {
528  Msg::Error("Could not read info for MED family %d", i + 1);
529  continue;
530  }
531 #endif
532 
533  // element family tags are unique (for all dimensions!) and <= 0
534  GEntity *ge = getRegionByTag(-familyNum);
535  if(!ge) ge = getFaceByTag(-familyNum);
536  if(!ge) ge = getEdgeByTag(-familyNum);
537  if(!ge) ge = getVertexByTag(-familyNum);
538  if(ge) {
539  setElementaryName(ge->dim(), -familyNum, familyName);
540  if(numGroups > 0) {
541  for(int j = 0; j < numGroups; j++) {
542  char tmp[MED_TAILLE_LNOM + 1];
543  strncpy(tmp, &groupNames[j * MED_TAILLE_LNOM], MED_TAILLE_LNOM);
544  tmp[MED_TAILLE_LNOM] = '\0';
545  // don't use same physical number across dimensions, as e.g. getdp
546  // does not support this
547  int pnum =
548  setPhysicalName(tmp, ge->dim(), getMaxPhysicalNumber(-1) + 1);
549  if(std::find(ge->physicals.begin(), ge->physicals.end(), pnum) ==
550  ge->physicals.end())
551  ge->physicals.push_back(pnum);
552  }
553  }
554  }
555  else if(familyNum > 0 && CTX::instance()->mesh.medImportGroupsOfNodes) {
556  // the concept of node family does not exist in Gmsh, so we simply create
557  // a geometrical point for each node (with a single point element); and we
558  // classify the node on the geometrical point if the node is not already
559  // classified on another entity. This is expensive, and should be disabled
560  // for large groups of nodes.
561  std::vector<GVertex *> newPoints;
562  for(int j = 0; j < numNodes; j++) {
563  if(nodeFamily[j] == familyNum) {
564  discreteVertex *gv =
565  new discreteVertex(this, getMaxElementaryNumber(0) + 1,
566  verts[j]->x(), verts[j]->y(), verts[j]->z());
567  add(gv);
568  if(!verts[j]->onWhat()) {
569  verts[j]->setEntity(gv);
570  gv->mesh_vertices.push_back(verts[j]);
571  }
572  gv->points.push_back(new MPoint(verts[j]));
573  setElementaryName(0, gv->tag(), familyName);
574  newPoints.push_back(gv);
575  }
576  }
577  if(numGroups > 0) {
578  for(int j = 0; j < numGroups; j++) {
579  char tmp[MED_TAILLE_LNOM + 1];
580  strncpy(tmp, &groupNames[j * MED_TAILLE_LNOM], MED_TAILLE_LNOM);
581  tmp[MED_TAILLE_LNOM] = '\0';
582  // don't use same physical number across dimensions, as e.g. getdp
583  // does not support this
584  int pnum = setPhysicalName(tmp, 0, getMaxPhysicalNumber(-1) + 1);
585  for(std::size_t k = 0; k < newPoints.size(); k++)
586  newPoints[k]->physicals.push_back(pnum);
587  }
588  }
589  }
590  }
591 
592  // check if we need to read some post-processing data later
593 #if(MED_MAJOR_NUM >= 3)
594  bool postpro = (MEDnField(fid) > 0) ? true : false;
595 #else
596  bool postpro = (MEDnChamp(fid, 0) > 0) ? true : false;
597 #endif
598 
599  if(MEDfermer(fid) < 0) {
600  Msg::Error("Unable to close file '%s'", name.c_str());
601  return 0;
602  }
603 
604  return postpro ? 2 : 1;
605 }
606 
607 template <class T>
608 static void
609 fillElementsMED(med_int family, std::vector<T *> &elements,
610  std::vector<med_int> &conn, std::vector<med_int> &fam,
611  std::vector<med_int> &tags, med_geometrie_element &type)
612 {
613  if(elements.empty()) return;
614  int msh = elements[0]->getTypeForMSH();
615  type = msh2medElementType(msh);
616  if(type == MED_NONE) {
617  Msg::Warning("Unsupported element type in MED format");
618  return;
619  }
620  for(std::size_t i = 0; i < elements.size(); i++) {
621  elements[i]->setVolumePositive();
622  for(std::size_t j = 0; j < elements[i]->getNumVertices(); j++)
623  conn.push_back(
624  elements[i]->getVertex(msh2medNodeIndex(msh, j))->getIndex());
625  fam.push_back(family);
626  tags.push_back(elements[i]->getNum());
627  }
628 }
629 
630 static void writeElementsMED(med_idt &fid, const char *meshName,
631  std::vector<med_int> &conn,
632  std::vector<med_int> &fam,
633  std::vector<med_int> &tags,
634  med_geometrie_element type)
635 {
636  if(fam.empty()) return;
637 #if(MED_MAJOR_NUM >= 3)
638  if(MEDmeshElementWr(fid, meshName, MED_NO_DT, MED_NO_IT, 0., MED_CELL, type,
639  MED_NODAL, MED_FULL_INTERLACE, (med_int)fam.size(),
640  &conn[0], MED_FALSE, nullptr, MED_TRUE, &tags[0],
641  MED_TRUE, &fam[0]) < 0)
642 #else
643  if(MEDelementsEcr(fid, meshName, (med_int)3, &conn[0], MED_FULL_INTERLACE, 0,
644  MED_FAUX, &tags[0], MED_VRAI, &fam[0], (med_int)fam.size(),
645  MED_MAILLE, type, MED_NOD) < 0)
646 #endif
647  Msg::Error("Could not write MED elements");
648 }
649 
650 int GModel::writeMED(const std::string &name, bool saveAll,
651  double scalingFactor)
652 {
653 #if (MED_MAJOR_NUM >= 4) || ((MED_MAJOR_NUM >= 3) && (MED_MINOR_NUM >= 3))
654  // MEDfileVersionOpen actually appeared in MED 3.2.1
655  med_int major = MED_MAJOR_NUM, minor = MED_MINOR_NUM,
656  release = MED_RELEASE_NUM;
657  if(CTX::instance()->mesh.medFileMinorVersion >= 0) {
658  minor = (int)CTX::instance()->mesh.medFileMinorVersion;
659  Msg::Info("Forcing MED file version to %d.%d", major, minor);
660  }
661  med_idt fid = MEDfileVersionOpen((char *)name.c_str(), MED_ACC_CREAT, major,
662  minor, release);
663 #else
664  med_idt fid = MEDouvrir((char *)name.c_str(), MED_CREATION);
665 #endif
666  if(fid < 0) {
667  Msg::Error("Unable to open file '%s'", name.c_str());
668  return 0;
669  }
670 
671  // write header
672  if(MEDfichDesEcr(fid, (char *)"MED file generated by Gmsh") < 0) {
673  Msg::Error("Unable to write MED descriptor");
674  return 0;
675  }
676 
677  std::string strMeshName = getName();
678  if(strMeshName.empty())
679  strMeshName = "untitled";
680  const char *meshName = (char *)strMeshName.c_str();
681 
682  // Gmsh always writes 3D unstructured meshes
683 #if(MED_MAJOR_NUM >= 3)
684  char dtUnit[MED_SNAME_SIZE + 1] = "";
685  char axisName[3 * MED_SNAME_SIZE + 1] = "";
686  char axisUnit[3 * MED_SNAME_SIZE + 1] = "";
687  if(MEDmeshCr(fid, meshName, 3, 3, MED_UNSTRUCTURED_MESH,
688  "Mesh created with Gmsh", dtUnit, MED_SORT_DTIT, MED_CARTESIAN,
689  axisName, axisUnit) < 0) {
690 #else
691  if(MEDmaaCr(fid, meshName, 3, MED_NON_STRUCTURE,
692  (char *)"Mesh created with Gmsh") < 0) {
693 #endif
694  Msg::Error("Could not create MED mesh");
695  return 0;
696  }
697 
698  // if there are no physicals we save all the elements
699  if(noPhysicalGroups()) saveAll = true;
700 
701  // index the vertices we save in a continuous sequence (MED
702  // connectivity is given in terms of vertex indices)
703  indexMeshVertices(saveAll);
704 
705  // get a vector containing all the geometrical entities in the
706  // model (the ordering of the entities must be the same as the one
707  // used during the indexing of the vertices)
708  std::vector<GEntity *> entities;
709  getEntities(entities);
710 
711  std::map<GEntity *, int> families;
712  // write the families
713  {
714  // always create a "0" family, with no groups or attributes
715 #if(MED_MAJOR_NUM >= 3)
716  if(MEDfamilyCr(fid, meshName, "F_0", 0, 0, "") < 0)
717 #else
718  if(MEDfamCr(fid, meshName, (char *)"F_0", 0, 0, 0, 0, 0, 0, 0) < 0)
719 #endif
720  Msg::Error("Could not create MED family 0");
721 
722  // create one family per elementary entity, with one group per
723  // physical entity and no attributes
724  for(std::size_t i = 0; i < entities.size(); i++) {
725  if(saveAll || entities[i]->physicals.size()) {
726  int num = -((int)families.size() + 1);
727  families[entities[i]] = num;
728  std::ostringstream fs;
729  fs << entities[i]->dim() << "D_" << entities[i]->tag();
730  std::string familyName = "F_" + fs.str();
731  std::string groupName;
732  for(unsigned j = 0; j < entities[i]->physicals.size(); j++) {
733  std::string tmp =
734  getPhysicalName(entities[i]->dim(), entities[i]->physicals[j]);
735  if(tmp.empty()) { // create unique name
736  std::ostringstream gs;
737  gs << entities[i]->dim() << "D_" << entities[i]->physicals[j];
738  groupName += "G_" + gs.str();
739  }
740  else
741  groupName += tmp;
742  // if an entity belongs to several groups, pad to multiples of
743  // MED_TAILLE_LNOM lengths
744  if(j) groupName.resize((j + 1) * MED_TAILLE_LNOM, ' ');
745  }
746 #if(MED_MAJOR_NUM >= 3)
747  if(MEDfamilyCr(fid, meshName, familyName.c_str(), (med_int)num,
748  (med_int)entities[i]->physicals.size(),
749  groupName.c_str()) < 0)
750 #else
751  if(MEDfamCr(fid, meshName, (char *)familyName.c_str(), (med_int)num, 0,
752  0, 0, 0, (char *)groupName.c_str(),
753  (med_int)entities[i]->physicals.size()) < 0)
754 #endif
755  Msg::Error("Could not create MED family %d", num);
756  }
757  }
758  }
759 
760  // write the nodes
761  {
762  std::vector<med_float> coord;
763  std::vector<med_int> fam;
764  std::vector<med_int> tags;
765  for(std::size_t i = 0; i < entities.size(); i++) {
766  for(std::size_t j = 0; j < entities[i]->mesh_vertices.size(); j++) {
767  MVertex *v = entities[i]->mesh_vertices[j];
768  if(v->getIndex() >= 0) {
769  coord.push_back(v->x() * scalingFactor);
770  coord.push_back(v->y() * scalingFactor);
771  coord.push_back(v->z() * scalingFactor);
772  fam.push_back(0); // we never create node families
773  tags.push_back(v->getNum());
774  }
775  }
776  }
777  if(fam.empty()) {
778  Msg::Error("No nodes to write in MED mesh");
779  return 0;
780  }
781 #if(MED_MAJOR_NUM >= 3)
782  if(MEDmeshNodeWr(fid, meshName, MED_NO_DT, MED_NO_IT, 0.,
783  MED_FULL_INTERLACE, (med_int)fam.size(), &coord[0],
784  MED_FALSE, "", MED_TRUE, &tags[0], MED_TRUE, &fam[0]) < 0)
785 #else
786  char coordName[3 * MED_TAILLE_PNOM + 1] =
787  "x y z ";
788  char coordUnit[3 * MED_TAILLE_PNOM + 1] =
789  "unknown unknown unknown ";
790  if(MEDnoeudsEcr(fid, meshName, (med_int)3, &coord[0], MED_FULL_INTERLACE,
791  MED_CART, coordName, coordUnit, 0, MED_FAUX, &tags[0],
792  MED_VRAI, &fam[0], (med_int)fam.size()) < 0)
793 #endif
794  Msg::Error("Could not write nodes");
795  }
796 
797  // write the elements
798  {
799  { // points
800  med_geometrie_element typ = MED_NONE;
801  std::vector<med_int> conn, fam, tags;
802  for(auto it = firstVertex(); it != lastVertex(); it++)
803  if(saveAll || (*it)->physicals.size())
804  fillElementsMED(families[*it], (*it)->points, conn, fam, tags, typ);
805  writeElementsMED(fid, meshName, conn, fam, tags, typ);
806  }
807  { // lines
808  med_geometrie_element typ = MED_NONE;
809  std::vector<med_int> conn, fam, tags;
810  for(auto it = firstEdge(); it != lastEdge(); it++)
811  if(saveAll || (*it)->physicals.size())
812  fillElementsMED(families[*it], (*it)->lines, conn, fam, tags, typ);
813  writeElementsMED(fid, meshName, conn, fam, tags, typ);
814  }
815  { // triangles
816  med_geometrie_element typ = MED_NONE;
817  std::vector<med_int> conn, fam, tags;
818  for(auto it = firstFace(); it != lastFace(); it++)
819  if(saveAll || (*it)->physicals.size())
820  fillElementsMED(families[*it], (*it)->triangles, conn, fam, tags,
821  typ);
822  writeElementsMED(fid, meshName, conn, fam, tags, typ);
823  }
824  { // quads
825  med_geometrie_element typ = MED_NONE;
826  std::vector<med_int> conn, fam, tags;
827  for(auto it = firstFace(); it != lastFace(); it++)
828  if(saveAll || (*it)->physicals.size())
829  fillElementsMED(families[*it], (*it)->quadrangles, conn, fam, tags,
830  typ);
831  writeElementsMED(fid, meshName, conn, fam, tags, typ);
832  }
833  { // tets
834  med_geometrie_element typ = MED_NONE;
835  std::vector<med_int> conn, fam, tags;
836  for(auto it = firstRegion(); it != lastRegion(); it++)
837  if(saveAll || (*it)->physicals.size())
838  fillElementsMED(families[*it], (*it)->tetrahedra, conn, fam, tags,
839  typ);
840  writeElementsMED(fid, meshName, conn, fam, tags, typ);
841  }
842  { // hexas
843  med_geometrie_element typ = MED_NONE;
844  std::vector<med_int> conn, fam, tags;
845  for(auto it = firstRegion(); it != lastRegion(); it++)
846  if(saveAll || (*it)->physicals.size())
847  fillElementsMED(families[*it], (*it)->hexahedra, conn, fam, tags,
848  typ);
849  writeElementsMED(fid, meshName, conn, fam, tags, typ);
850  }
851  { // prisms
852  med_geometrie_element typ = MED_NONE;
853  std::vector<med_int> conn, fam, tags;
854  for(auto it = firstRegion(); it != lastRegion(); it++)
855  if(saveAll || (*it)->physicals.size())
856  fillElementsMED(families[*it], (*it)->prisms, conn, fam, tags, typ);
857  writeElementsMED(fid, meshName, conn, fam, tags, typ);
858  }
859  { // pyramids
860  med_geometrie_element typ = MED_NONE;
861  std::vector<med_int> conn, fam, tags;
862  for(auto it = firstRegion(); it != lastRegion(); it++)
863  if(saveAll || (*it)->physicals.size())
864  fillElementsMED(families[*it], (*it)->pyramids, conn, fam, tags, typ);
865  writeElementsMED(fid, meshName, conn, fam, tags, typ);
866  }
867  }
868 
869  if(MEDfermer(fid) < 0) {
870  Msg::Error("Unable to close file '%s'", name.c_str());
871  return 0;
872  }
873 
874  return 1;
875 }
876 
877 #else
878 
879 int GModel::readMED(const std::string &name)
880 {
881  Msg::Error("Gmsh must be compiled with MED support to read '%s'",
882  name.c_str());
883  return 0;
884 }
885 
886 int GModel::readMED(const std::string &name, int meshIndex)
887 {
888  Msg::Error("Gmsh must be compiled with MED support to read '%s'",
889  name.c_str());
890  return 0;
891 }
892 
893 int GModel::writeMED(const std::string &name, bool saveAll,
894  double scalingFactor)
895 {
896  Msg::Error("Gmsh must be compiled with MED support to write '%s'",
897  name.c_str());
898  return 0;
899 }
900 
901 #endif
GModel::GModel
GModel(const std::string &name="")
Definition: GModel.cpp:72
MSH_LIN_2
#define MSH_LIN_2
Definition: GmshDefines.h:80
MSH_HEX_8
#define MSH_HEX_8
Definition: GmshDefines.h:84
MSH_TRI_6
#define MSH_TRI_6
Definition: GmshDefines.h:88
MTriangle.h
tags
static std::map< SPoint2, unsigned int > tags
Definition: drawGraph2d.cpp:400
GModel::firstEdge
eiter firstEdge()
Definition: GModel.h:356
GModel::getMaxElementaryNumber
int getMaxElementaryNumber(int dim)
Definition: GModel.cpp:817
MSH_PNT
#define MSH_PNT
Definition: GmshDefines.h:94
Msg::Info
static void Info(const char *fmt,...)
Definition: GmshMessage.cpp:587
GModel::checkPointMaxNumbers
void checkPointMaxNumbers()
Definition: GModel.h:264
MSH_PRI_15
#define MSH_PRI_15
Definition: GmshDefines.h:97
MElementFactory
Definition: MElement.h:517
MVertex
Definition: MVertex.h:24
MSH_QUA_4
#define MSH_QUA_4
Definition: GmshDefines.h:82
GModel::getName
std::string getName() const
Definition: GModel.h:329
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
GEntity::physicals
std::vector< int > physicals
Definition: GEntity.h:65
MVertex::getNum
std::size_t getNum() const
Definition: MVertex.h:86
GModel::getFaceByTag
GFace * getFaceByTag(int n) const
Definition: GModel.cpp:326
contextMeshOptions::medFileMinorVersion
double medFileMinorVersion
Definition: Context.h:58
GModel::_storeElementsInEntities
void _storeElementsInEntities(std::map< int, std::vector< MElement * > > &map)
Definition: GModel.cpp:2273
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
GEntity
Definition: GEntity.h:31
MSH_PYR_5
#define MSH_PYR_5
Definition: GmshDefines.h:86
discreteVertex.h
GVertex::points
std::vector< MPoint * > points
Definition: GVertex.h:120
GModel::findByName
static GModel * findByName(const std::string &name, const std::string &fileName="")
Definition: GModel.cpp:158
MSH_TRI_3
#define MSH_TRI_3
Definition: GmshDefines.h:81
CTX::instance
static CTX * instance()
Definition: Context.cpp:122
GModel::readMED
static int readMED(const std::string &name)
Definition: GModelIO_MED.cpp:879
GModel::lastFace
fiter lastFace()
Definition: GModel.h:359
conn
Definition: delaunay3d.cpp:257
discreteVertex
Definition: discreteVertex.h:15
GModel::getPhysicalName
std::string getPhysicalName(int dim, int num) const
Definition: GModel.cpp:961
GModel::setName
void setName(const std::string &name)
Definition: GModel.h:328
GModel::setFileName
void setFileName(const std::string &fileName)
Definition: GModel.cpp:123
GEntity::mesh_vertices
std::vector< MVertex * > mesh_vertices
Definition: GEntity.h:56
MHexahedron.h
GModel::setElementaryName
void setElementaryName(int dim, int tag, const std::string &name)
Definition: GModel.h:500
GModel::lastVertex
viter lastVertex()
Definition: GModel.h:361
GModel::getMaxPhysicalNumber
int getMaxPhysicalNumber(int dim)
Definition: GModel.cpp:917
MSH_LIN_3
#define MSH_LIN_3
Definition: GmshDefines.h:87
MVertex.h
GModel
Definition: GModel.h:44
MSH_QUA_8
#define MSH_QUA_8
Definition: GmshDefines.h:95
MPyramid.h
MSH_HEX_20
#define MSH_HEX_20
Definition: GmshDefines.h:96
GModel::firstFace
fiter firstFace()
Definition: GModel.h:355
GModel::add
bool add(GRegion *r)
Definition: GModel.h:394
CTX::mesh
contextMeshOptions mesh
Definition: Context.h:313
MElement
Definition: MElement.h:30
GEntity::tag
int tag() const
Definition: GEntity.h:280
MSH_TET_10
#define MSH_TET_10
Definition: GmshDefines.h:90
GModel::getEntities
void getEntities(std::vector< GEntity * > &entities, int dim=-1) const
Definition: GModel.cpp:651
MElementFactory::create
MElement * create(int type, std::vector< MVertex * > &v, std::size_t num=0, int part=0, bool owner=false, int parent=0, MElement *parent_ptr=nullptr, MElement *d1=nullptr, MElement *d2=nullptr)
Definition: MElement.cpp:2556
MSH_QUA_9
#define MSH_QUA_9
Definition: GmshDefines.h:89
GModel::firstRegion
riter firstRegion()
Definition: GModel.h:354
GModel::setCurrent
static int setCurrent(GModel *m)
Definition: GModel.cpp:147
GModel::lastRegion
riter lastRegion()
Definition: GModel.h:358
MSH_PRI_18
#define MSH_PRI_18
Definition: GmshDefines.h:92
MVertex::getIndex
long int getIndex() const
Definition: MVertex.h:93
Context.h
MSH_TET_4
#define MSH_TET_4
Definition: GmshDefines.h:83
MTetrahedron.h
z
const double z
Definition: GaussQuadratureQuad.cpp:56
MQuadrangle.h
MSH_HEX_27
#define MSH_HEX_27
Definition: GmshDefines.h:91
GModel::noPhysicalGroups
bool noPhysicalGroups()
Definition: GModel.cpp:828
MPoint
Definition: MPoint.h:16
MSH_MAX_NUM
#define MSH_MAX_NUM
Definition: GmshDefines.h:227
MPrism.h
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
GModel::lastEdge
eiter lastEdge()
Definition: GModel.h:360
GModel.h
MSH_PYR_13
#define MSH_PYR_13
Definition: GmshDefines.h:98
GModel::getRegionByTag
GRegion * getRegionByTag(int n) const
Definition: GModel.cpp:316
MVertex::y
double y() const
Definition: MVertex.h:61
GModel::_storeVerticesInEntities
void _storeVerticesInEntities(std::map< int, MVertex * > &vertices)
Definition: GModel.cpp:2496
MSH_PRI_6
#define MSH_PRI_6
Definition: GmshDefines.h:85
GModel::writeMED
int writeMED(const std::string &name, bool saveAll=false, double scalingFactor=1.0)
Definition: GModelIO_MED.cpp:893
GEntity::dim
virtual int dim() const
Definition: GEntity.h:196
GModel::getVertexByTag
GVertex * getVertexByTag(int n) const
Definition: GModel.cpp:346
GModel::_associateEntityWithMeshVertices
void _associateEntityWithMeshVertices()
Definition: GModel.cpp:2470
GModel::indexMeshVertices
std::size_t indexMeshVertices(bool all, int singlePartition=0, bool renumber=true)
Definition: GModel.cpp:2135
MVertex::x
double x() const
Definition: MVertex.h:60