Arcane  4.2.3.0
Developer documentation
Loading...
Searching...
No Matches
MEDMeshReaderService.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* MEDMeshReaderService.cc (C) 2000-2026 */
9/* */
10/* Reading a mesh in MED format. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/ITraceMng.h"
15#include "arcane/utils/SmallArray.h"
16#include "arcane/utils/FixedArray.h"
17#include "arcane/utils/Convert.h"
18#include "arcane/utils/CheckedConvert.h"
19
20#include "arcane/core/IMeshReader.h"
21#include "arcane/core/BasicService.h"
23#include "arcane/core/IPrimaryMesh.h"
24#include "arcane/core/IItemFamily.h"
25#include "arcane/core/ICaseMeshReader.h"
26#include "arcane/core/IMeshBuilder.h"
27#include "arcane/core/IParallelMng.h"
28#include "arcane/core/MeshPartInfo.h"
29#include "arcane/core/NodesOfItemReorderer.h"
31#include "arcane/core/ItemPrinter.h"
32#include "arcane/core/internal/ItemTypeMngInternal.h"
33
34#include <med.h>
35#define MESGERR 1
36#include <med_utils.h>
37
38#include <map>
39
40/*---------------------------------------------------------------------------*/
41/*---------------------------------------------------------------------------*/
42
43namespace Arcane
44{
45
46/*---------------------------------------------------------------------------*/
47/*---------------------------------------------------------------------------*/
54class MEDMeshReader
55: public TraceAccessor
56{
57 public:
58
65 class MEDToArcaneItemInfo
66 {
67 public:
68
69 MEDToArcaneItemInfo(int dimension, int nb_node, med_int med_type,
70 ItemTypeId arcane_type, const Int32* indirection)
71 : m_dimension(dimension)
72 , m_nb_node(nb_node)
73 , m_med_type(med_type)
74 , m_arcane_type(arcane_type)
75 , m_indirection(indirection)
76 {}
77
78 public:
79
80 int dimension() const { return m_dimension; }
81 int nbNode() const { return m_nb_node; }
82 med_int medType() const { return m_med_type; }
83 Int16 arcaneType() const { return m_arcane_type; }
84 const Int32* indirection() const { return m_indirection; }
85
86 private:
87
88 int m_dimension = -1;
89 int m_nb_node = -1;
90 med_int m_med_type = {};
91 ItemTypeId m_arcane_type = ITI_NullType;
92 const Int32* m_indirection = nullptr;
93 };
94
96 class MEDFamilyInfo
97 {
98 public:
99
100 explicit MEDFamilyInfo(Int32 family_id)
101 : m_family_id(family_id)
102 {}
103
104 public:
105
110 };
111
120 class MEDGroupInfo
121 {
122 public:
123
124 explicit MEDGroupInfo(Int32 index)
125 : m_index(index)
126 {}
127
128 public:
129
138 };
139
140 public:
141
142 explicit MEDMeshReader(ITraceMng* tm)
143 : TraceAccessor(tm)
144 {
145 _initMEDToArcaneTypes();
146 }
147
148 public:
149
150 [[nodiscard]] IMeshReader::eReturnType
151 readMesh(IPrimaryMesh* mesh, const String& file_name);
152
153 private:
154
155 IMeshReader::eReturnType _readMesh(IPrimaryMesh* mesh, const String& filename);
156
157 private:
158
159 // Structure to automatically close open MED files
160 struct AutoCloseMED
161 {
162 explicit AutoCloseMED(med_idt id)
163 : fid(id)
164 {}
165 ~AutoCloseMED()
166 {
167 if (fid >= 0)
168 ::MEDfileClose(fid);
169 }
170
171 med_idt fid;
172 };
173
179 std::unordered_map<med_int, Int32> m_med_geotype_to_arcane_type_index;
181 std::unordered_map<Int32, MEDFamilyInfo> m_med_families_map;
186
187 private:
188
189 Int32 _readItems(IPrimaryMesh* mesh, med_idt fid, const char* meshnane, const MEDToArcaneItemInfo& iinfo,
190 Array<Int16>& poly_nb_nodes, Array<Int16>& poly_types, Array<med_int>& connectivity, Array<med_int>& family_values);
191 void _initMEDToArcaneTypes();
192 void _addTypeInfo(int dimension, int nb_node, med_int med_type, ItemTypeId arcane_type)
193 {
194 _addTypeInfo(dimension, nb_node, med_type, arcane_type, nullptr);
195 }
196 void _addTypeInfo(int dimension, int nb_node, med_int med_type, ItemTypeId arcane_type,
197 const Int32* indirection)
198 {
199 MEDToArcaneItemInfo t(dimension, nb_node, med_type, arcane_type, indirection);
200 Int32 index = m_med_to_arcane_types.size();
202 m_med_geotype_to_arcane_type_index.insert(std::make_pair(med_type, index));
203 }
204 void _readAndCreateCells(IPrimaryMesh* mesh, Int32 mesh_dimension, med_idt fid, const char* meshname);
205 void _readFaces(IPrimaryMesh* mesh, Int32 mesh_dimension, med_idt fid, const char* meshname);
206
207 [[nodiscard]] IMeshReader::eReturnType
208 _readNodesCoordinates(IPrimaryMesh* mesh, Int64 nb_node, Int32 spacedim,
209 med_idt fid, const char* meshname);
210 void _readFamilies(med_idt fid, const char* meshname);
211 void _readAvailableTypes(med_idt fid, const char* meshname);
212 void _clearItemsInGroups()
213 {
214 for (MEDGroupInfo& g : m_med_groups) {
215 g.m_unique_ids.clear();
216 g.m_local_ids.clear();
217 }
218 }
219 void _broadcastGroups(ConstArrayView<String> names, IItemFamily* family);
220 med_int _readPolyhedrons(IPrimaryMesh* mesh, med_idt fid, const char* meshname,
221 Array<Int16>& poly_nb_nodes,
222 Array<Int16>& poly_types_id,
223 Array<med_int>& connectivity);
224};
225
226/*---------------------------------------------------------------------------*/
227/*---------------------------------------------------------------------------*/
228
229namespace
230{
231 // MED numbering conventions are different from those used in Arcane.
232 // These arrays allow for renumbering.
233 const Int32 Hexaedron8_indirection[] = { 1, 0, 3, 2, 5, 4, 7, 6 };
234 const Int32 Hexaedron20_indirection[] = { 1, 8, 10, 3, 9, 2, 0, 11, 5, 14, 18, 7, 6, 4, 16, 15, 13, 12, 17, 19 };
235 const Int32 Pyramid5_indirection[] = { 1, 0, 3, 2, 4 };
236 const Int32 Quad4_indirection[] = { 1, 0, 3, 2 };
237 const Int32 Quad8_indirection[] = { 1, 0, 3, 2, 4, 7, 6, 5 };
238 const Int32 Triangle3_indirection[] = { 1, 0, 2 };
239 // Not used for now. To be tested.
240 const Int32 Tetraedron4_indirection[] = { 1, 0, 2, 3 };
241} // namespace
242
243/*---------------------------------------------------------------------------*/
244/*---------------------------------------------------------------------------*/
245
246void MEDMeshReader::
247_initMEDToArcaneTypes()
248{
249 m_med_to_arcane_types.clear();
250
251 // TODO: check the connectivity correspondence between
252 // Arcane and MED for quadrilateral elements
253 // 1D Types
254 _addTypeInfo(1, 2, MED_SEG2, ITI_Line2);
255 _addTypeInfo(1, 3, MED_SEG3, ITI_Line3); // Not supported
256 _addTypeInfo(1, 4, MED_SEG4, ITI_NullType); // Not supported
257
258 // 2D Types.
259 _addTypeInfo(2, 3, MED_TRIA3, ITI_Triangle3, Triangle3_indirection);
260 _addTypeInfo(2, 4, MED_QUAD4, ITI_Quad4, Quad4_indirection);
261 _addTypeInfo(2, 6, MED_TRIA6, ITI_NullType); // Not supported
262 _addTypeInfo(2, 7, MED_TRIA7, ITI_NullType); // Not supported
263 _addTypeInfo(2, 8, MED_QUAD8, ITI_Quad8, Quad8_indirection);
264 _addTypeInfo(2, 9, MED_QUAD9, ITI_NullType); // Not supported
265
266 // 3D Types
267 _addTypeInfo(3, 4, MED_TETRA4, ITI_Tetraedron4);
268 _addTypeInfo(3, 5, MED_PYRA5, ITI_Pyramid5, Pyramid5_indirection);
269 _addTypeInfo(3, 6, MED_PENTA6, ITI_Pentaedron6);
270 _addTypeInfo(3, 8, MED_HEXA8, ITI_Hexaedron8);
271 _addTypeInfo(3, 10, MED_TETRA10, ITI_Tetraedron10);
272 _addTypeInfo(3, 12, MED_OCTA12, ITI_Octaedron12);
273 _addTypeInfo(3, 13, MED_PYRA13, ITI_NullType); // Not supported
274 _addTypeInfo(3, 15, MED_PENTA15, ITI_NullType); // Not supported
275 _addTypeInfo(3, 18, MED_PENTA18, ITI_NullType); // Not supported
276 _addTypeInfo(3, 20, MED_HEXA20, ITI_Hexaedron20);
277 _addTypeInfo(3, 27, MED_HEXA27, ITI_NullType); // Not supported
278
279 // Cells whose geometry has variable connectivity.
280 // For now, we do not support any of these types in Arcane.
281 // We still process these elements to display an error if they are
282 // present in the mesh. By setting the node count to (0), we signal to _readItems()
283 // that we cannot process these elements.
284
285 _addTypeInfo(2, 0, MED_POLYGON, ITI_GenericPolygon);
286 _addTypeInfo(2, 0, MED_POLYGON2, ITI_NullType);
287 _addTypeInfo(3, 0, MED_POLYHEDRON, ITI_GenericPolyhedron);
288
289 // Cells whose geometry is dynamic (model discovery in the file)
290 // TODO: check how to process them
291 //#define MED_STRUCT_GEO_INTERNAL 600
292 //#define MED_STRUCT_GEO_SUP_INTERNAL 700
293}
294
295/*---------------------------------------------------------------------------*/
296/*---------------------------------------------------------------------------*/
297
298IMeshReader::eReturnType MEDMeshReader::
299readMesh(IPrimaryMesh* mesh, const String& file_name)
300{
301 info() << "Trying to read MED File name=" << file_name;
302 m_mesh = mesh;
303 return _readMesh(mesh, file_name);
304}
305
306/*---------------------------------------------------------------------------*/
307/*---------------------------------------------------------------------------*/
308
309IMeshReader::eReturnType MEDMeshReader::
310_readMesh(IPrimaryMesh* mesh, const String& filename)
311{
312 const med_idt fid = MEDfileOpen(filename.localstr(), MED_ACC_RDONLY);
313 if (fid < 0) {
314 MESSAGE("ERROR: can not open MED file ");
315 error() << "ERROR: can not open MED file '" << filename << "'";
317 }
318 // To guarantee file closure.
319 AutoCloseMED auto_close_med(fid);
320
321 int nb_mesh = MEDnMesh(fid);
322 if (nb_mesh < 0) {
323 error() << "Error reading number of meshes";
325 }
326 info() << "MED: nb_mesh=" << nb_mesh;
327 if (nb_mesh == 0) {
328 error() << "No mesh is present";
330 }
331
332 // The mesh we read is always the first one
333 int mesh_index = 1;
334
335 // Get the space dimension. This is necessary to dimension axisname and unitname
336 int nb_axis = MEDmeshnAxis(fid, mesh_index);
337 if (nb_axis < 0) {
338 error() << "Can not read number of axis (MEDmeshnAxis)";
340 }
341 info() << "MED: nb_axis=" << nb_axis;
342
343 UniqueArray<char> axisname(MED_SNAME_SIZE * nb_axis + 1, '\0');
344 UniqueArray<char> unitname(MED_SNAME_SIZE * nb_axis + 1, '\0');
345
346 char meshname[MED_NAME_SIZE + 1];
347 meshname[0] = '\0';
348 char meshdescription[MED_COMMENT_SIZE + 1];
349 meshdescription[0] = '\0';
350 char dtunit[MED_SNAME_SIZE + 1];
351 dtunit[0] = '\0';
352 med_int spacedim = 0;
353 med_int meshdim = 0;
354 med_mesh_type meshtype = MED_UNDEF_MESH_TYPE;
355 med_sorting_type sortingtype = MED_SORT_UNDEF;
356 med_int nstep = 0;
357 med_axis_type axistype = MED_UNDEF_AXIS_TYPE;
358 int err = 0;
359 err = MEDmeshInfo(fid, mesh_index, meshname, &spacedim, &meshdim, &meshtype, meshdescription,
360 dtunit, &sortingtype, &nstep, &axistype, axisname.data(), unitname.data());
361 if (err < 0) {
362 error() << "Can not read mesh info (MEDmeshInfo) r=" << err;
364 }
365 if (meshtype != MED_UNSTRUCTURED_MESH) {
366 error() << "Arcane handle only MED unstructured mesh (MED_UNSTRUCTURED_MESH) type=" << meshtype;
368 }
369 Integer mesh_dimension = meshdim;
370 if (mesh_dimension != 2 && mesh_dimension != 3)
371 ARCANE_FATAL("MED reader handles only 2D or 3D meshes");
372
373 info() << "MED: name=" << meshname;
374 info() << "MED: description=" << meshdescription;
375 info() << "MED: spacedim=" << spacedim;
376 info() << "MED: meshdim=" << meshdim;
377 info() << "MED: dtunit=" << dtunit;
378 info() << "MED: meshtype=" << meshtype;
379 info() << "MED: sortingtype=" << sortingtype;
380 info() << "MED: axistype=" << axistype;
381 info() << "MED: nstep=" << nstep;
382
383 Int64 nb_node = 0;
384 // Reading the number of nodes.
385 {
386 med_bool coordinatechangement;
387 med_bool geotransformation;
388 // TODO: process information such as coordinatechangement
389 // and geotransformation if needed
390 med_int med_nb_node = MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT, MED_NODE, MED_NO_GEOTYPE,
391 MED_COORDINATE, MED_NO_CMODE, &coordinatechangement,
392 &geotransformation);
393 if (med_nb_node < 0) {
394 error() << "Can not read number of nodes (MEDmeshnEntity) err=" << med_nb_node;
396 }
397 nb_node = med_nb_node;
398 }
399 info() << "MED: nb_node=" << nb_node;
400
401 mesh->setDimension(mesh_dimension);
402
403 // MED meshes can contain polygons or polyhedrons
404 // We therefore build the corresponding types.
405 // (NOTE: all subdomains must do this)
406 mesh->itemTypeMng()->buildPolygonTypes();
407
408 IParallelMng* pm = mesh->parallelMng();
409 bool is_parallel = pm->isParallel();
410 Int32 rank = mesh->meshPartInfo().partRank();
411 // In parallel, only rank 0 reads the mesh
412 bool is_read_items = !(is_parallel && rank != 0);
413 if (is_read_items) {
414 _readAvailableTypes(fid, meshname);
415 _readFamilies(fid, meshname);
416 _readAndCreateCells(mesh, mesh_dimension, fid, meshname);
417 }
418 // The IPrimaryMesh::endAllocate() method is collective, so everyone
419 // must call it even if ranks other than rank 0
420 // do not have cells.
421 mesh->endAllocate();
422
423 // List of names of created cell groups
424 // It will be used to transfer the list of groups to all ranks.
425 UniqueArray<String> cell_group_names;
426 IItemFamily* cell_family = mesh->cellFamily();
427 if (is_read_items) {
428 // Now that all cells have been created, we create the corresponding groups
429 // To do this, we iterate through all instances of 'm_med_groups' and if one has entities
430 // then they are cells to be added to a group.
431 // ATTENTION ATTENTION:
432 // NOTE: The groups must be common to all ranks. They must be broadcasted
433 UniqueArray<Int32> cell_local_ids;
434 for (const MEDGroupInfo& g : m_med_groups) {
435 Int32 nb_cell_in_group = g.m_unique_ids.size();
436 cell_local_ids.resize(nb_cell_in_group);
437 cell_family->itemsUniqueIdToLocalId(cell_local_ids, g.m_unique_ids);
438 for (const String& name : g.m_names) {
439 info() << "Group=" << name << " index=" << g.m_index << " nb_item=" << nb_cell_in_group;
440 CellGroup cell_group = cell_family->findGroup(name, true);
441 cell_group.addItems(cell_local_ids);
442 cell_group_names.add(name);
443 }
444 }
445 }
446 _broadcastGroups(cell_group_names, cell_family);
447
448 // Reading the faces
449 if (is_read_items) {
450 // Since the face numbering is not necessarily correct for all
451 // entity types (especially for order 2), we add an option to
452 // not read the faces.
453 bool is_face_group_disabled = false;
454 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_MED_DISABLE_FACEGROUP", true))
455 is_face_group_disabled = (v.value());
456 if (!is_face_group_disabled)
457 _readFaces(mesh, mesh_dimension, fid, meshname);
458 }
459
460 UniqueArray<String> face_group_names;
461 IItemFamily* face_family = mesh->faceFamily();
462 // Now add the faces to the groups.
463 if (is_read_items) {
464 for (const MEDGroupInfo& g : m_med_groups) {
465 Int32 nb_face_in_group = g.m_local_ids.size();
466 info() << "Check Group index=" << g.m_index << " nb_item=" << nb_face_in_group;
467 if (nb_face_in_group == 0)
468 continue;
469 for (const String& name : g.m_names) {
470 info() << "FaceGroup=" << name << " index=" << g.m_index << " nb_item=" << nb_face_in_group;
471 FaceGroup face_group = face_family->findGroup(name, true);
472 face_group.addItems(g.m_local_ids);
473 face_group_names.add(name);
474 }
475 }
476 }
477 _broadcastGroups(face_group_names, face_family);
478
479 if (is_read_items) {
480 // Reading the coordinates
481 return _readNodesCoordinates(mesh, nb_node, spacedim, fid, meshname);
482 }
483 return IMeshReader::RTOk;
484}
485
486/*---------------------------------------------------------------------------*/
487/*---------------------------------------------------------------------------*/
492_readAvailableTypes(med_idt fid, const char* meshname)
493{
494 // Retrieves the number of geometric types
495 med_bool coordinatechangement;
496 med_bool geotransformation;
497 med_int nb_geo = MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, MED_GEO_ALL,
498 MED_CONNECTIVITY, MED_NODAL, &coordinatechangement,
499 &geotransformation);
500 if (nb_geo < 0)
501 ARCANE_FATAL("Can not read number of geometric entities nb_geo={0}", nb_geo);
502 info() << "MED: nb_geotype = " << nb_geo;
503
504 // Loop through the present types
505 for (med_int it = 1; it <= nb_geo; it++) {
506
507 med_geometry_type geotype = MED_GEO_ALL;
509
510 /* get geometry type */
511 med_int type_ret = MEDmeshEntityInfo(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, it,
512 geotype_name.data(), &geotype);
513 if (type_ret < 0)
514 ARCANE_FATAL("Can not read informations for geotype index={0} ret={1}", it, type_ret);
515 /* how many cells of type geotype ? */
516 med_int nb_item = MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, geotype,
517 MED_CONNECTIVITY, MED_NODAL, &coordinatechangement,
518 &geotransformation);
519 if (nb_item < 0)
520 ARCANE_FATAL("Can not read number of items for geotype={0} name={1} ret={2}",
521 geotype, geotype_name.data(), nb_item);
522 info() << "MED: type=" << geotype << " '" << geotype_name.data() << "' nb_item=" << nb_item;
523 m_med_geotypes_in_mesh.add(geotype);
524 }
525}
526
527/*---------------------------------------------------------------------------*/
528/*---------------------------------------------------------------------------*/
529
530void MEDMeshReader::
531_readAndCreateCells(IPrimaryMesh* mesh, Int32 mesh_dimension, med_idt fid, const char* meshname)
532{
533 _clearItemsInGroups();
534
535 // As a matter of principle, there is no uniqueId() for entities in MED (TODO: to verify)
536 // So we number the cells starting from zero and increment for each
537 // cell created.
538 Int64 cell_unique_id = 0;
539
540 // Number of nodes for each polygon or polyhedron
541 UniqueArray<Int16> poly_nb_nodes;
542 // Type of each polygon or polyhedron
543 UniqueArray<Int16> poly_types_id;
544 UniqueArray<med_int> med_connectivity;
545 UniqueArray<med_int> med_family_values;
546
547 // Allocates cells type by type.
548 // Iterates through the available types and processes those that match the dimension
549 // of the mesh.
550 for (med_int geotype : m_med_geotypes_in_mesh) {
551 Int32 index_in_list = m_med_geotype_to_arcane_type_index[geotype];
552 const MEDToArcaneItemInfo& iinfo = m_med_to_arcane_types[index_in_list];
553
554 Int32 item_dimension = iinfo.dimension();
555 // We only process entities of the mesh dimension.
556 if (item_dimension != mesh_dimension)
557 continue;
558 Int32 nb_item = _readItems(mesh, fid, meshname, iinfo, poly_nb_nodes, poly_types_id, med_connectivity, med_family_values);
559 if (nb_item == 0)
560 continue;
561
562 Int16 arcane_type = iinfo.arcaneType();
563 Int32 nb_item_node = iinfo.nbNode();
564 Int32 nb_family_values = med_family_values.size();
565 if (arcane_type == IT_NullType) {
566 // Indicates a type supported by MED but not by Arcane
567 ARCANE_FATAL("MED type '{0}' is not supported by Arcane", iinfo.medType());
568 }
569 Int64 cells_infos_index = 0;
570 Int64 med_connectivity_index = 0;
571 const bool is_poly = (iinfo.medType() == MED_POLYGON) || (iinfo.medType() == MED_POLYHEDRON);
572 // Set information that the mesh has polygon or polyhedron cells.
573 if (is_poly)
575 UniqueArray<Int64> cells_infos;
576 if (is_poly)
577 cells_infos.resize(2 * nb_item + med_connectivity.size());
578 else
579 cells_infos.resize((2 + nb_item_node) * nb_item);
580
581 info() << "CELL_INFOS size=" << cells_infos.size() << " nb_item=" << nb_item
582 << " type=" << arcane_type;
583
584 const Int32* indirection = iinfo.indirection();
585 for (Int32 i = 0; i < nb_item; ++i) {
586 Int64 current_cell_unique_id = cell_unique_id;
587 ++cell_unique_id;
588 if (is_poly) {
589 nb_item_node = poly_nb_nodes[i];
590 arcane_type = poly_types_id[i];
591 cells_infos[cells_infos_index] = arcane_type;
592 ++cells_infos_index;
593 cells_infos[cells_infos_index] = current_cell_unique_id;
594 ++cells_infos_index;
595 Span<Int64> cinfo_span(cells_infos.span().subspan(cells_infos_index, nb_item_node));
596 Span<med_int> med_cinfo_span(med_connectivity.span().subspan(med_connectivity_index, nb_item_node));
597 for (Integer k = 0; k < nb_item_node; ++k) {
598 cinfo_span[k] = med_cinfo_span[k];
599 }
600 }
601 else {
602 cells_infos[cells_infos_index] = arcane_type;
603 ++cells_infos_index;
604 cells_infos[cells_infos_index] = current_cell_unique_id;
605 ++cells_infos_index;
606 Span<Int64> cinfo_span(cells_infos.span().subspan(cells_infos_index, nb_item_node));
607 Span<med_int> med_cinfo_span(med_connectivity.span().subspan(med_connectivity_index, nb_item_node));
608 if (indirection) {
609 for (Integer k = 0; k < nb_item_node; ++k) {
610 cinfo_span[k] = med_cinfo_span[indirection[k]];
611 }
612 }
613 else {
614 for (Integer k = 0; k < nb_item_node; ++k)
615 cinfo_span[k] = med_cinfo_span[k];
616 }
617 }
618 if (i < nb_family_values) {
619 // There is a family associated with the entity
620 med_int f = med_family_values[i];
621 auto x = m_med_families_map.find(f);
622 if (x == m_med_families_map.end()) {
623 ARCANE_FATAL("Can not find family id '{0}' for cell '{1}' of geotype '{2}'",
624 f, i, iinfo.medType());
625 }
626 m_med_groups[x->second.m_index].m_unique_ids.add(current_cell_unique_id);
627 }
628
629 med_connectivity_index += nb_item_node;
630 cells_infos_index += nb_item_node;
631 }
632 mesh->allocateCells(nb_item, cells_infos, false);
633 }
634}
635
636/*---------------------------------------------------------------------------*/
637/*---------------------------------------------------------------------------*/
646_readFaces(IPrimaryMesh* mesh, Int32 mesh_dimension, med_idt fid, const char* meshname)
647{
648 _clearItemsInGroups();
649 ItemTypeMng* itm = mesh->itemTypeMng();
650 NodesOfItemReorderer nodes_reorderer(itm);
651
652 IItemFamily* node_family = mesh->nodeFamily();
653 NodeInfoListView mesh_nodes(node_family);
654
655 UniqueArray<Int16> poly_nb_nodes;
656 UniqueArray<Int16> poly_types_id;
657 UniqueArray<med_int> med_connectivity;
658 UniqueArray<med_int> med_family_values;
659 // Iterates through the available types and processes those that correspond to the dimension
660 // of the mesh minus 1.
661 for (med_int geotype : m_med_geotypes_in_mesh) {
662 Int32 index_in_list = m_med_geotype_to_arcane_type_index[geotype];
663 const MEDToArcaneItemInfo& iinfo = m_med_to_arcane_types[index_in_list];
664
665 Int32 item_dimension = iinfo.dimension();
666 // We only process entities of the mesh dimension.
667 if (item_dimension != (mesh_dimension - 1))
668 continue;
669 ItemTypeInfo* iti = itm->typeFromId(iinfo.arcaneType());
670 info() << "Reading faces geotype=" << geotype << " arcane_type=" << iinfo.arcaneType()
671 << " " << iti->typeName();
672 // At the moment we can not read faces which are polygons
673 const bool is_polygon = (iinfo.medType() == MED_POLYGON);
674
675 Int32 nb_item = _readItems(mesh, fid, meshname, iinfo, poly_nb_nodes, poly_types_id, med_connectivity, med_family_values);
676 if (nb_item == 0)
677 continue;
678
679 ItemTypeId arcane_type(iinfo.arcaneType());
680 Int32 nb_item_node = iinfo.nbNode();
681 Int32 nb_family_values = med_family_values.size();
682 if (arcane_type == IT_NullType) {
683 // Indicates a type supported by MED but not by Arcane
684 ARCANE_FATAL("MED type '{0}' is not supported by Arcane", iinfo.medType());
685 }
686
687 SmallArray<Int64> orig_nodes_id(nb_item_node);
688 info() << "FACES_INFOS nb_item=" << nb_item << " type=" << arcane_type
689 << " nb_family_values=" << nb_family_values << " connectivity_size=" << med_connectivity.size();
690
691 const Int32* indirection = iinfo.indirection();
692 Int64 med_connectivity_index = 0;
693
694 for (Int32 i = 0; i < nb_item; ++i) {
695 ArrayView<Int64> cinfo_span(orig_nodes_id);
696 if (is_polygon) {
697 // Each polygon has its own number of nodes so we need to resize the working array.
698 nb_item_node = poly_nb_nodes[i];
699 orig_nodes_id.resize(nb_item_node);
700 cinfo_span = orig_nodes_id;
701 arcane_type = ItemTypeId(poly_types_id[i]);
702 }
703 Span<med_int> med_cinfo_span(med_connectivity.span().subspan(med_connectivity_index, nb_item_node));
704 if (indirection) {
705 for (Integer k = 0; k < nb_item_node; ++k) {
706 cinfo_span[k] = med_cinfo_span[indirection[k]];
707 }
708 }
709 else {
710 for (Integer k = 0; k < nb_item_node; ++k)
711 cinfo_span[k] = med_cinfo_span[k];
712 }
713 //info() << "HANDLE_FACE nb_item=" << nb_item_node;
714 med_connectivity_index += nb_item_node;
715 // Search for the face in the mesh starting from the sorted uniqueIds of its nodes
716 nodes_reorderer.reorder(arcane_type, cinfo_span);
717 ConstArrayView<Int64> ordered_nodes = nodes_reorderer.sortedNodes();
718 //info() << "OrigMedNodes=" << med_cinfo_span;
719 //info() << "OrigNodes=" << orig_nodes_id;
720 //info() << "Nodes=" << ordered_nodes;
721 Node first_node(MeshUtils::findOneItem(node_family, ordered_nodes[0]));
722 if (first_node.null())
723 ARCANE_FATAL("Can not find node uid={0} for face index '{1}'", ordered_nodes[0], i);
724 Face face = MeshUtils::getFaceFromNodesUniqueId(first_node, ordered_nodes);
725 if (face.null()) {
726 info() << "ERROR: Can not find face in mesh i=" << i << " nodes=" << ordered_nodes;
727 info() << "List of faces for node=" << ItemPrinter(first_node);
728 for (Face subface : first_node.faces()) {
729 info() << "Face=" << ItemPrinter(subface);
730 for (Node subnode : subface.nodes()) {
731 info() << " Node=" << ItemPrinter(subnode);
732 }
733 }
734 ARCANE_FATAL("Can not find face with nodes=", ordered_nodes);
735 }
736 //info() << "Face=" << ItemPrinter(face);
737
738 // Add the face to the corresponding groups
739 if (i < nb_family_values) {
740 // There is a family associated with the entity
741 med_int f = med_family_values[i];
742 auto x = m_med_families_map.find(f);
743 if (x == m_med_families_map.end()) {
744 ARCANE_FATAL("Can not find family id '{0}' for face '{1}' of geotype '{2}'",
745 f, i, iinfo.medType());
746 }
747 //info() << "Add face to group_index=" << x->second.m_index;
748 m_med_groups[x->second.m_index].m_local_ids.add(face.localId());
749 }
750 }
751 info() << "END_READING_ITEMS";
752 }
753}
754
755/*---------------------------------------------------------------------------*/
756/*---------------------------------------------------------------------------*/
757
758IMeshReader::eReturnType MEDMeshReader::
759_readNodesCoordinates(IPrimaryMesh* mesh, Int64 nb_node, Int32 spacedim,
760 med_idt fid, const char* meshname)
761{
762 const bool do_verbose = false;
763 // Reads the node coordinates and positions the coordinates in Arcane
764
765 // Connectivity in MED starts at 1 and in Arcane at 0.
766 // The first node therefore has the value for uniqueId()
767 UniqueArray<Real3> nodes_coordinates(nb_node + 1);
768 {
769 UniqueArray<med_float> coordinates(nb_node * spacedim);
770 int err = MEDmeshNodeCoordinateRd(fid, meshname, MED_NO_DT, MED_NO_IT, MED_FULL_INTERLACE,
771 coordinates.data());
772 if (err < 0) {
773 error() << "Can not read nodes coordinates err=" << err;
775 }
776
777 if (spacedim == 3) {
778 for (Int64 i = 0; i < nb_node; ++i) {
779 Real3 xyz(coordinates[i * 3], coordinates[(i * 3) + 1], coordinates[(i * 3) + 2]);
780 if (do_verbose)
781 info() << "I=" << i << " XYZ=" << xyz;
782 nodes_coordinates[i + 1] = xyz;
783 }
784 }
785 else if (spacedim == 2) {
786 for (Int64 i = 0; i < nb_node; ++i) {
787 Real3 xyz(coordinates[i * 2], coordinates[(i * 2) + 1], 0.0);
788 if (do_verbose)
789 info() << "I=" << i << " XYZ=" << xyz;
790 nodes_coordinates[i + 1] = xyz;
791 }
792 }
793 else
794 ARCANE_THROW(NotImplementedException, "spacedim!=2 && spacedim!=3");
795 }
796
797 // Positions the coordinates
798 {
799 VariableNodeReal3& nodes_coord_var(mesh->nodesCoordinates());
800 ENUMERATE_NODE (inode, mesh->allNodes()) {
801 Node node = *inode;
802 nodes_coord_var[inode] = nodes_coordinates[node.uniqueId()];
803 }
804 }
805 return IMeshReader::RTOk;
806}
807
808/*---------------------------------------------------------------------------*/
809/*---------------------------------------------------------------------------*/
825_readItems(IPrimaryMesh* mesh, med_idt fid, const char* meshname,
826 const MEDToArcaneItemInfo& iinfo,
827 Array<Int16>& poly_nb_nodes,
828 Array<Int16>& poly_types_id,
829 Array<med_int>& connectivity,
830 Array<med_int>& family_values)
831{
832 constexpr bool is_verbose = false;
833
834 connectivity.clear();
835 family_values.clear();
836
837 ItemTypeMng* itm = mesh->itemTypeMng();
838 int med_item_type = iinfo.medType();
839 med_bool coordinatechangement = {};
840 med_bool geotransformation = {};
841 med_int nb_med_item = 0;
842 if (iinfo.medType() == MED_POLYHEDRON) {
843 nb_med_item = _readPolyhedrons(mesh, fid, meshname, poly_nb_nodes, poly_types_id, connectivity);
844 }
845 else if (iinfo.medType() == MED_POLYGON) {
846 // For polygons, a specific call is needed for the number of indices.
847 // This number corresponds to the number of entities plus one.
848 med_int nb_index = ::MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, med_item_type,
849 MED_INDEX_NODE, MED_NODAL, &coordinatechangement,
850 &geotransformation);
851 if (nb_index < 0)
852 ARCANE_FATAL("Can not read MED med_item_type '{0}' error={1}", med_item_type, nb_index);
853
854 info() << "MED: Reading items";
855 info() << "MED: type=" << med_item_type << " nb_index=" << nb_index;
856 if (nb_index < 1)
857 return 0;
858 nb_med_item = nb_index - 1;
859 poly_nb_nodes.resize(nb_med_item);
860 poly_types_id.resize(nb_med_item);
861 // how many nodes for the polygon connectivity ?
862 med_int nb_connectivity = MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT,
863 MED_CELL, MED_POLYGON, MED_CONNECTIVITY, MED_NODAL,
864 &coordinatechangement, &geotransformation);
865 if (nb_connectivity < 0)
866 ARCANE_FATAL("Can not get connectivity size for MED_POLYGON err={0}", nb_connectivity);
867
868 // The table \a indexes contains for each cell the index of its first
869 // node in the connectivity. The number of nodes of the i-th entity
870 // is therefore equal to (indexes[i+1]-indexes[i]).
871 UniqueArray<med_int> indexes(nb_index);
872 connectivity.resize(nb_connectivity);
873 info() << "Reading polygons nb_connectivity=" << nb_connectivity;
874 int r = MEDmeshPolygonRd(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, MED_NODAL,
875 indexes.data(), connectivity.data());
876 if (r < 0)
877 ARCANE_FATAL("Can not read connectivity for MED_POLYGON err={0}", r);
878 info() << "INDEXES=" << indexes;
879 for (Int32 i = 0; i < nb_med_item; ++i) {
880 Int16 nb_node_for_cell = CheckedConvert::toInt16(indexes[i + 1] - indexes[i]);
881 poly_nb_nodes[i] = nb_node_for_cell;
882 poly_types_id[i] = itm->getPolygonType(static_cast<Int16>(nb_node_for_cell));
883 }
884 }
885 else {
886 nb_med_item = ::MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, med_item_type,
887 MED_CONNECTIVITY, MED_NODAL, &coordinatechangement,
888 &geotransformation);
889 if (nb_med_item < 0)
890 ARCANE_FATAL("Can not read MED med_item_type '{0}' error={1}", med_item_type, nb_med_item);
891
892 info() << "MED: Reading items";
893 info() << "MED: type=" << med_item_type << " nb_item=" << nb_med_item;
894 if (nb_med_item == 0)
895 return 0;
896
897 Int64 nb_node = iinfo.nbNode();
898 if (nb_node == 0)
899 // Indicates an element that we do not know how to process.
900 ARCANE_THROW(NotImplementedException, "Reading items with MED type '{0}'", med_item_type);
901
902 connectivity.resize(nb_node * nb_med_item);
903 int err = MEDmeshElementConnectivityRd(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL,
904 med_item_type, MED_NODAL, MED_FULL_INTERLACE,
905 connectivity.data());
906 if (err < 0)
907 ARCANE_FATAL("Can not read connectivity MED med_item_type '{0}' error={1}",
908 med_item_type, err);
909 }
910 if (is_verbose)
911 info() << "CON: " << connectivity;
912 {
913 med_int nb_med_family = MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT,
914 MED_CELL, med_item_type, MED_FAMILY_NUMBER, MED_NODAL,
915 &coordinatechangement, &geotransformation);
916 info() << "nb_family=" << nb_med_family;
917 if (nb_med_family < 0)
918 ARCANE_FATAL("Can not read family size for type med_item_type={0} error={1}", med_item_type, nb_med_family);
919 if (nb_med_family > 0) {
920 family_values.resize(nb_med_family);
921 int r = MEDmeshEntityFamilyNumberRd(fid, meshname, MED_NO_DT, MED_NO_IT,
922 MED_CELL, med_item_type, family_values.data());
923 if (r < 0)
924 ARCANE_FATAL("Can not read family values for type med_item_type={0} error={1}", med_item_type, nb_med_family);
925 if (is_verbose)
926 info() << "FAM: " << family_values;
927 }
928 }
929 return nb_med_item;
930}
931
932/*---------------------------------------------------------------------------*/
933/*---------------------------------------------------------------------------*/
934
935med_int MEDMeshReader::
936_readPolyhedrons(IPrimaryMesh* mesh, med_idt fid, const char* meshname,
937 Array<Int16>& poly_nb_nodes,
938 Array<Int16>& poly_types_id,
939 Array<med_int>& connectivity)
940{
941 if (mesh->parallelMng()->commSize() > 1)
942 ARCANE_FATAL("MED polyhedral mesh in not support in parallel");
943 const bool is_verbose = false;
944 ItemTypeMngInternal* itmi = mesh->itemTypeMng()->_internalApi();
945 med_bool coordinatechangement = {};
946 med_bool geotransformation = {};
947 const med_int med_item_type = MED_POLYHEDRON;
948 info() << "MED: Reading polyhedron items";
949 // For polyhedrons, a specific call is needed for the number of faces and connectivity of nodes
950 med_int nb_face_index = ::MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, med_item_type,
951 MED_INDEX_FACE, MED_NODAL, &coordinatechangement,
952 &geotransformation);
953 if (nb_face_index < 0)
954 ARCANE_FATAL("Can not read MED_INDEX_FACE for Polyhedron type error={0}", nb_face_index);
955 info() << "MED: type=" << med_item_type << " nb_face_index=" << nb_face_index;
956 if (nb_face_index < 1)
957 return 0;
958
959 med_int nb_node_index = ::MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, med_item_type,
960 MED_INDEX_NODE, MED_NODAL, &coordinatechangement,
961 &geotransformation);
962 if (nb_node_index < 0)
963 ARCANE_FATAL("Can not read MED_INDEX_NODE for Polyhedron type error={0}", nb_node_index);
964
965 info() << "MED: type=" << med_item_type << " nb_face_index=" << nb_face_index << " nb_node_index=" << nb_node_index;
966 med_int nb_med_item = nb_face_index - 1;
967 poly_nb_nodes.resize(nb_med_item);
968 poly_types_id.resize(nb_med_item);
969 // how many nodes for the polygon connectivity ?
970 med_int nb_connectivity = MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT,
971 MED_CELL, MED_POLYHEDRON, MED_CONNECTIVITY, MED_NODAL,
972 &coordinatechangement, &geotransformation);
973 if (nb_connectivity < 0)
974 ARCANE_FATAL("Can not get connectivity size for MED_POLYHEDRON err={0}", nb_connectivity);
975
976 // The table \a face_indexes contains for each cell the index of its first
977 // face in the connectivity. The number of faces of the i-th entity
978 // is therefore equal to (face_indexes[i+1] - face_indexes[i]).
979 UniqueArray<med_int> face_indexes(nb_face_index);
980 UniqueArray<med_int> node_indexes(nb_node_index);
981 connectivity.clear();
982 connectivity.reserve(nb_connectivity);
983 UniqueArray<med_int> med_connectivity(nb_connectivity);
984 info() << "Reading polyhedron nb_connectivity=" << nb_connectivity;
985 int r = MEDmeshPolyhedronRd(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, MED_NODAL,
986 face_indexes.data(), node_indexes.data(), med_connectivity.data());
987 if (r < 0)
988 ARCANE_FATAL("Can not read connectivity for MED_POLYGON err={0}", r);
989 if (is_verbose) {
990 info() << "FACE_INDEXES=" << face_indexes;
991 info() << "NODE_INDEXES=" << node_indexes;
992 info() << "CONNECTIVITY=" << med_connectivity;
993 }
994 UniqueArray<Int16> local_nodes_of_cell;
995 UniqueArray<Int32> nodes_of_cell;
996 UniqueArray<Int32> nodes_of_face;
997
998 // Infos for creating the corresponding Arcane type
999 UniqueArray<Int16> arcane_faces_nb_node;
1000 UniqueArray<Int16> arcane_faces_nodes;
1001 // Local index in the cell of the nodes;
1002 std::map<Int32, Int16> connectivity_to_local_index;
1003 for (Int32 z = 0; z < nb_med_item; ++z) {
1004 Int16 nb_local_node = 0;
1005 nodes_of_cell.clear();
1006 connectivity_to_local_index.clear();
1007 local_nodes_of_cell.clear();
1008 arcane_faces_nb_node.clear();
1009 arcane_faces_nodes.clear();
1010 Int32 connectivity_index = connectivity.size();
1011 // Numbering begins at 1 so we need to remove 1 to face_indexes and node_indexes
1012 Int32 first_face_index = face_indexes[z] - 1;
1013 Int32 next_face_index = face_indexes[z + 1] - 1;
1014 Int32 cell_nb_face = next_face_index - first_face_index;
1015 Int32 cell_nb_node = node_indexes[next_face_index] - node_indexes[first_face_index];
1016 if (is_verbose)
1017 info() << "POLYHEDRAL_CELL=" << z << " nb_face=" << cell_nb_face
1018 << " nb_node=" << cell_nb_node << " first_face_index=" << first_face_index
1019 << " nb_info_in_connectivity=" << node_indexes[cell_nb_face];
1020 Int16 nb_connectivity_for_cell = 3 + cell_nb_node + cell_nb_face;
1021 connectivity.add(nb_connectivity_for_cell);
1022 const Int64 scheme_version = 1;
1023 connectivity.add(scheme_version);
1024 connectivity.add(cell_nb_face);
1025 for (Int32 k = 0; k < cell_nb_face; ++k) {
1026 Int32 first_node_index = node_indexes[first_face_index + k] - 1;
1027 Int32 next_node_index = node_indexes[first_face_index + k + 1] - 1;
1028 Int16 face_nb_node = CheckedConvert::toInt16(next_node_index - first_node_index);
1029 nodes_of_face.resize(face_nb_node);
1030 arcane_faces_nb_node.add(face_nb_node);
1031 connectivity.add(face_nb_node);
1032 for (Int32 p = 0; p < face_nb_node; ++p) {
1033 // TODO: check if (-1) is needed
1034 Int32 node_id = med_connectivity[first_node_index + p];
1035 auto x = connectivity_to_local_index.find(node_id);
1036 Int16 local_node_index = -1;
1037 if (x == connectivity_to_local_index.end()) {
1038 local_node_index = nb_local_node;
1039 connectivity_to_local_index[node_id] = nb_local_node;
1040 ++nb_local_node;
1041 local_nodes_of_cell.add(local_node_index);
1042 nodes_of_cell.add(node_id);
1043 }
1044 else
1045 local_node_index = x->second;
1046 connectivity.add(node_id);
1047 nodes_of_face[p] = local_node_index;
1048 arcane_faces_nodes.add(local_node_index);
1049 }
1050 if (is_verbose)
1051 info() << " POLYHEDRAL_FACE=" << k << " nb_node=" << face_nb_node << " nodes=" << nodes_of_face.view();
1052 //Int32 face_nb_node = face_indexes[z+1] - face_indexes[z];
1053 }
1054 if (is_verbose) {
1055 info() << "POLYHEDRAL_CELL=" << z << " nb_local_node=" << nodes_of_cell.size() << " nodes=" << nodes_of_cell
1056 << " nb_connectivity_for_cell=" << nb_connectivity_for_cell;
1057 info() << "POLYHEDRAL_CELL=" << z << " arcane_faces_nb_node=" << arcane_faces_nb_node << " nodes=" << arcane_faces_nodes;
1058 }
1059 poly_types_id[z] = IT_GenericPolyhedron;
1060 poly_nb_nodes[z] = nb_connectivity_for_cell;
1061 }
1062 return nb_med_item;
1063}
1064
1065/*---------------------------------------------------------------------------*/
1066/*---------------------------------------------------------------------------*/
1067
1068void MEDMeshReader::
1069_readFamilies(med_idt fid, const char* meshname)
1070{
1071 FixedArray<char, MED_NAME_SIZE + 1> familyname;
1072
1073 info() << "Read families";
1074
1075 // Retrieves the number of families
1076 med_int nb_family = MEDnFamily(fid, meshname);
1077 if (nb_family < 0)
1078 ARCANE_FATAL("Can not read number of families (error={0})", nb_family);
1079
1080 info() << "MED: nb_family= " << nb_family;
1081 for (med_int i = 0; i < nb_family; i++) {
1082 info() << "MED: Read family i=" << i;
1083
1084 med_int nb_group = MEDnFamilyGroup(fid, meshname, i + 1);
1085 if (nb_group < 0)
1086 ARCANE_FATAL("Can not read number of groups for family index={0}", i);
1087 info() << "MED: family index=" << i << " nb_group=" << nb_group;
1088
1089 // Reads the family groups
1090 // Even if there are no groups associated with the family, we continue
1091 // the processing because entities may reference families without groups.
1092
1093 // In MED, groups have a fixed maximum size MED_LNAME_SIZE
1094 UniqueArray<char> all_group_names(MED_LNAME_SIZE * nb_group + 1);
1095 med_int family_number = 0;
1096 if (MEDfamilyInfo(fid, meshname, i + 1, familyname.data(), &family_number, all_group_names.data()) < 0)
1097 ARCANE_FATAL("Can not read group names from family index={0}", i);
1098
1099 MEDFamilyInfo med_family(family_number);
1100 Int32 group_index = m_med_groups.size();
1101 med_family.m_index = group_index;
1102 MEDGroupInfo med_group(group_index);
1103
1104 // Retrieves the names of the family groups
1105 for (Int32 z = 0; z < nb_group; ++z) {
1106 //info() << " groupname=" << group_names << " number=" << familynumber;
1107 SmallSpan<char> med_group_name = all_group_names.smallSpan().subSpan(MED_LNAME_SIZE * z, MED_LNAME_SIZE);
1108 // Groups in MED may contain characters not supported by Arcane.
1109 // We remove them.
1110 SmallArray<Byte, MED_LNAME_SIZE + 1> valid_name;
1111 Int32 pos = 0;
1112 for (; pos < MED_LNAME_SIZE; ++pos) {
1113 char c = med_group_name[pos];
1114 if (c == '\0')
1115 break;
1116 if (c == ' ' || c == '_')
1117 continue;
1118 valid_name.add(static_cast<Byte>(c));
1119 }
1120 String name(valid_name.view());
1121 med_group.m_names.add(name);
1122 info() << "Family id=" << family_number << " group='" << name << "'";
1123 }
1124
1125 m_med_families_map.insert(std::make_pair(family_number, med_family));
1126 m_med_groups.add(med_group);
1127 }
1128}
1129
1130/*---------------------------------------------------------------------------*/
1131/*---------------------------------------------------------------------------*/
1139{
1140 IParallelMng* pm = m_mesh->parallelMng();
1141
1142 Int32 rank = pm->commRank();
1143 // Ensures that all ranks know the groups
1144 if (rank == 0) {
1145 Int32 nb_group = group_names.size();
1146 pm->broadcast(ArrayView<Int32>(1, &nb_group), 0);
1147 for (String name : group_names)
1148 pm->broadcastString(name, 0);
1149 }
1150 else {
1151 Int32 nb_group = 0;
1152 pm->broadcast(ArrayView<Int32>(1, &nb_group), 0);
1153 String current_group_name;
1154 for (Int32 i = 0; i < nb_group; ++i) {
1155 pm->broadcastString(current_group_name, 0);
1156 CellGroup cell_group = family->findGroup(current_group_name, true);
1157 }
1158 }
1159}
1160
1161/*---------------------------------------------------------------------------*/
1162/*---------------------------------------------------------------------------*/
1163
1164/*---------------------------------------------------------------------------*/
1165/*---------------------------------------------------------------------------*/
1169class MEDMeshReaderService
1170: public BasicService
1171, public IMeshReader
1172{
1173 public:
1174
1175 explicit MEDMeshReaderService(const ServiceBuildInfo& sbi)
1176 : BasicService(sbi)
1177 {}
1178
1179 public:
1180
1181 void build() override {}
1182 bool allowExtension(const String& str) override
1183 {
1184 return str == "med";
1185 }
1187 [[maybe_unused]] const XmlNode& mesh_element,
1188 const String& file_name,
1189 const String& dir_name,
1190 [[maybe_unused]] bool use_internal_partition) override
1191 {
1192 ARCANE_UNUSED(dir_name);
1193 MEDMeshReader reader(traceMng());
1194 return reader.readMesh(mesh, file_name);
1195 }
1196};
1197
1198/*---------------------------------------------------------------------------*/
1199/*---------------------------------------------------------------------------*/
1200
1201ARCANE_REGISTER_SERVICE(MEDMeshReaderService,
1202 ServiceProperty("MEDMeshReader", ST_SubDomain),
1203 ARCANE_SERVICE_INTERFACE(IMeshReader));
1204
1205/*---------------------------------------------------------------------------*/
1206/*---------------------------------------------------------------------------*/
1207
1208/*---------------------------------------------------------------------------*/
1209/*---------------------------------------------------------------------------*/
1213class MEDCaseMeshReader
1214: public AbstractService
1215, public ICaseMeshReader
1216{
1217 public:
1218
1219 class Builder
1220 : public IMeshBuilder
1221 {
1222 public:
1223
1224 explicit Builder(ITraceMng* tm, const CaseMeshReaderReadInfo& read_info)
1225 : m_trace_mng(tm)
1226 , m_read_info(read_info)
1227 {}
1228
1229 public:
1230
1231 void fillMeshBuildInfo(MeshBuildInfo& build_info) override
1232 {
1233 ARCANE_UNUSED(build_info);
1234 }
1236 {
1237 MEDMeshReader reader(m_trace_mng);
1238 String fname = m_read_info.fileName();
1239 m_trace_mng->info() << "MED Reader (ICaseMeshReader) file_name=" << fname;
1240 IMeshReader::eReturnType ret = reader.readMesh(pm, fname);
1241 if (ret != IMeshReader::RTOk)
1242 ARCANE_FATAL("Can not read MED File");
1243 }
1244
1245 private:
1246
1247 ITraceMng* m_trace_mng;
1248 CaseMeshReaderReadInfo m_read_info;
1249 };
1250
1251 public:
1252
1253 explicit MEDCaseMeshReader(const ServiceBuildInfo& sbi)
1254 : AbstractService(sbi)
1255 {}
1256
1257 public:
1258
1260 {
1261 IMeshBuilder* builder = nullptr;
1262 if (read_info.format() == "med")
1263 builder = new Builder(traceMng(), read_info);
1264 return makeRef(builder);
1265 }
1266};
1267
1268/*---------------------------------------------------------------------------*/
1269/*---------------------------------------------------------------------------*/
1270
1271ARCANE_REGISTER_SERVICE(MEDCaseMeshReader,
1272 ServiceProperty("MEDCaseMeshReader", ST_SubDomain),
1273 ARCANE_SERVICE_INTERFACE(ICaseMeshReader));
1274
1275/*---------------------------------------------------------------------------*/
1276/*---------------------------------------------------------------------------*/
1277
1278} // namespace Arcane
1279
1280/*---------------------------------------------------------------------------*/
1281/*---------------------------------------------------------------------------*/
#define ARCANE_THROW(exception_class,...)
Macro for throwing an exception with formatting.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
#define ENUMERATE_NODE(name, group)
Generic enumerator for a node group.
Utility functions for the mesh.
Face getFaceFromNodesUniqueId(Node node, Int64ConstArrayView face_nodes_unique_id)
Searches for a face entity using the unique numbers of these nodes.
This file contains the various service factories and macros for registering services.
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro to declare an interface when registering a service.
Integer size() const
Number of elements in the vector.
Base class of a service.
AbstractService(const ServiceBuildInfo &)
Constructor from a ServiceBuildInfo.
Modifiable view of an array of type T.
Base class for 1D data vectors.
Span< const T > span() const
Immutable view of this array.
void resize(Int64 s)
Changes the number of elements in the array to s.
void clear()
Removes the elements from the array.
void add(ConstReferenceType val)
Adds element val to the end of the array.
const T * data() const
Access to the root of the array without any protection.
void reserve(Int64 new_capacity)
Reserves memory for new_capacity elements.
Necessary information for reading a mesh file.
Constant view of an array of type T.
constexpr Integer size() const noexcept
Number of elements in the array.
static std::optional< Int32 > tryParseFromEnvironment(StringView s, bool throw_if_invalid)
Face of a cell.
Definition Item.h:1032
Interface for the mesh reading service from the dataset.
Interface of an entity family.
Definition IItemFamily.h:85
virtual ItemGroup findGroup(const String &name) const =0
Searches for a group.
virtual NodeGroup allNodes()=0
Group of all nodes.
Interface of a mesh creation/reading service.
Interface of the service managing the reading of a mesh.
Definition IMeshReader.h:33
eReturnType
Types of return codes for a read or write operation.
Definition IMeshReader.h:38
@ RTError
Error during the operation.
Definition IMeshReader.h:40
@ RTOk
Operation successfully performed.
Definition IMeshReader.h:39
virtual ItemTypeMng * itemTypeMng() const =0
Associated entity type manager.
Interface of the parallelism manager for a subdomain.
virtual Int32 commRank() const =0
Rank of this instance in the communicator.
virtual VariableNodeReal3 & nodesCoordinates()=0
Node coordinates.
virtual void allocateCells(Integer nb_cell, Int64ConstArrayView cells_infos, bool one_alloc=true)=0
Allocation of a mesh.
void addItems(Int32ConstArrayView items_local_id, bool check_if_present=true)
Adds entities.
Definition ItemGroup.cc:439
Utility class for printing information about an entity.
Definition ItemPrinter.h:35
Type of an entity (Item).
Definition ItemTypeId.h:33
Info on a mesh entity type.
String typeName() const
Type name.
Mesh entity type manager.
Definition ItemTypeMng.h:64
void setMeshWithGeneralCells(IMesh *mesh) noexcept
Allows the mesh to indicate to the ItemTypeMng if it has generic cells.
ItemTypeId getPolygonType(Int16 nb_node) const
Returns the type for a polygon having nb_node.
ItemTypeInfo * typeFromId(Integer id) const
Type corresponding to the number id.
constexpr Int32 localId() const
Local identifier of the entity in the processor subdomain.
Definition Item.h:233
constexpr bool null() const
true if the entity is null (i.e. not connected to the mesh)
Definition Item.h:230
void allocateMeshItems(IPrimaryMesh *pm) override
Allocates the mesh entities managed by this service.
void fillMeshBuildInfo(MeshBuildInfo &build_info) override
Fills build_info with the necessary information to create the mesh.
Service for reading a mesh in MED format from the dataset.
Ref< IMeshBuilder > createBuilder(const CaseMeshReaderReadInfo &read_info) const override
Returns a builder to create and read the mesh whose information is specified in read_info.
bool allowExtension(const String &str) override
Checks if the service supports files with the extension str.
void build() override
Build-level construction of the service.
eReturnType readMeshFromFile(IPrimaryMesh *mesh, const XmlNode &mesh_element, const String &file_name, const String &dir_name, bool use_internal_partition) override
Reads a mesh from a file.
Information about a MED entity family.
Int32 m_index
Index in the Arcane group list.
List of groups and the entities belonging to them.
Int32 m_index
Index of the group in the group list.
UniqueArray< Int64 > m_unique_ids
List of uniqueId() of the group's entities.
UniqueArray< String > m_names
Associated group names.
UniqueArray< Int32 > m_local_ids
List of localId() of the group's entities.
Information for mapping MED types to Arcane types for entities.
MED format mesh reader.
void _broadcastGroups(ConstArrayView< String > names, IItemFamily *family)
Broadcast the groups of group_names for the family family.
UniqueArray< MEDToArcaneItemInfo > m_med_to_arcane_types
Conversion table between MED and Arcane types.
void _readAvailableTypes(med_idt fid, const char *meshname)
Retrieves the list of geometric types present in the mesh.
IPrimaryMesh * m_mesh
Mesh currently being read.
UniqueArray< MEDGroupInfo > m_med_groups
List of group information.
std::unordered_map< Int32, MEDFamilyInfo > m_med_families_map
List of families.
std::unordered_map< med_int, Int32 > m_med_geotype_to_arcane_type_index
Table of indices in m_med_to_arcane_type for each geotype.
UniqueArray< med_int > m_med_geotypes_in_mesh
List of 'geotypes' present in the mesh.
Int32 _readItems(IPrimaryMesh *mesh, med_idt fid, const char *meshnane, const MEDToArcaneItemInfo &iinfo, Array< Int16 > &poly_nb_nodes, Array< Int16 > &poly_types, Array< med_int > &connectivity, Array< med_int > &family_values)
Reads information about entities of a given type.
void _readFaces(IPrimaryMesh *mesh, Int32 mesh_dimension, med_idt fid, const char *meshname)
Reads the faces.
Parameters necessary for building a mesh.
View of node information.
Node of a mesh.
Definition Item.h:598
FaceConnectedListViewType faces() const
List of faces of the node.
Definition Item.h:725
Utility class to reorder the nodes of an entity.
Reference to an instance.
Structure containing the information to create a service.
1D data array with pre-allocated stack buffer.
View of an array of elements of type T.
Definition Span.h:633
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
TraceMessage info() const
Flow for an information message.
TraceMessage error() const
Flow for an error message.
ITraceMng * traceMng() const
Trace manager.
1D data vector with value semantics (STL style).
Node of a DOM tree.
Definition XmlNode.h:51
ItemGroupT< Cell > CellGroup
Group of cells.
Definition ItemTypes.h:184
ItemGroupT< Face > FaceGroup
Group of faces.
Definition ItemTypes.h:179
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro for registering a service.
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Coordinate type quantity at node.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
@ ST_SubDomain
The service is used at the subdomain level.
std::int16_t Int16
Signed integer type of 16 bits.
unsigned char Byte
Type of a byte.
Definition BaseTypes.h:42
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Creates a reference on a pointer.
std::int32_t Int32
Signed integer type of 32 bits.