Arcane  4.1.12.0
User 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
18#include "arcane/core/IMeshReader.h"
19#include "arcane/core/BasicService.h"
21#include "arcane/core/IPrimaryMesh.h"
22#include "arcane/core/IItemFamily.h"
23#include "arcane/core/ICaseMeshReader.h"
24#include "arcane/core/IMeshBuilder.h"
25#include "arcane/core/IParallelMng.h"
26#include "arcane/core/MeshPartInfo.h"
27#include "arcane/core/NodesOfItemReorderer.h"
29#include "arcane/core/ItemPrinter.h"
30
31#include <med.h>
32#define MESGERR 1
33#include <med_utils.h>
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
37
38namespace Arcane
39{
40
41/*---------------------------------------------------------------------------*/
42/*---------------------------------------------------------------------------*/
43/*!
44 * \brief MED format mesh reader.
45 *
46 * First version of a MED reader handling only 2D, 3D, and
47 * unstructured meshes.
48 */
49class MEDMeshReader
50: public TraceAccessor
51{
52 public:
53
54 /*!
55 * \brief Information for mapping MED types to Arcane types for entities.
56 *
57 * \a indirection() is non-null if the MED connectivity differs from the
58 * Arcane connectivity, which is the case for 2D and 3D entities.
59 */
60 class MEDToArcaneItemInfo
61 {
62 public:
63
64 MEDToArcaneItemInfo(int dimension, int nb_node, med_int med_type,
65 ItemTypeId arcane_type, const Int32* indirection)
66 : m_dimension(dimension)
67 , m_nb_node(nb_node)
68 , m_med_type(med_type)
69 , m_arcane_type(arcane_type)
70 , m_indirection(indirection)
71 {}
72
73 public:
74
75 int dimension() const { return m_dimension; }
76 int nbNode() const { return m_nb_node; }
77 med_int medType() const { return m_med_type; }
78 Int16 arcaneType() const { return m_arcane_type; }
79 const Int32* indirection() const { return m_indirection; }
80
81 private:
82
83 int m_dimension = -1;
84 int m_nb_node = -1;
85 med_int m_med_type = {};
86 ItemTypeId m_arcane_type = ITI_NullType;
87 const Int32* m_indirection = nullptr;
88 };
89
90 //! Information about a MED entity family
91 class MEDFamilyInfo
92 {
93 public:
94
95 explicit MEDFamilyInfo(Int32 family_id)
96 : m_family_id(family_id)
97 {}
98
99 public:
100
101 //! Family ID for MED
103 //! Index in the Arcane group list.
105 };
106
107 /*!
108 * \brief List of groups and the entities belonging to them.
109 *
110 * For each group, we can provide either the list of uniqueId()
111 * of the entities inside, or the list of localId().
112 * The first case is used by cells and the second
113 * by faces and nodes
114 */
115 class MEDGroupInfo
116 {
117 public:
118
119 explicit MEDGroupInfo(Int32 index)
120 : m_index(index)
121 {}
122
123 public:
124
125 //! Index of the group in the group list
127 //! Associated group names
129 //! List of uniqueId() of the group's entities.
131 //! List of localId() of the group's entities.
133 };
134
135 public:
136
137 explicit MEDMeshReader(ITraceMng* tm)
138 : TraceAccessor(tm)
139 {
140 _initMEDToArcaneTypes();
141 }
142
143 public:
144
145 [[nodiscard]] IMeshReader::eReturnType
146 readMesh(IPrimaryMesh* mesh, const String& file_name);
147
148 private:
149
150 IMeshReader::eReturnType _readMesh(IPrimaryMesh* mesh, const String& filename);
151
152 private:
153
154 // Structure to automatically close open MED files
155 struct AutoCloseMED
156 {
157 explicit AutoCloseMED(med_idt id)
158 : fid(id)
159 {}
160 ~AutoCloseMED()
161 {
162 if (fid >= 0)
163 ::MEDfileClose(fid);
164 }
165
166 med_idt fid;
167 };
168
169 //! Mesh currently being read
170 IPrimaryMesh* m_mesh = nullptr;
171 //! Conversion table between MED and Arcane types
172 UniqueArray<MEDToArcaneItemInfo> m_med_to_arcane_types;
173 //! Table of indices in \a m_med_to_arcane_type for each geotype
174 std::unordered_map<med_int, Int32> m_med_geotype_to_arcane_type_index;
175 //! List of families
176 std::unordered_map<Int32, MEDFamilyInfo> m_med_families_map;
177 //! List of group information
178 UniqueArray<MEDGroupInfo> m_med_groups;
179 //! List of 'geotypes' present in the mesh
180 UniqueArray<med_int> m_med_geotypes_in_mesh;
181
182 private:
183
184 Int32 _readItems(med_idt fid, const char* meshnane, const MEDToArcaneItemInfo& iinfo,
185 Array<Int16>& polygon_nb_nodes, Array<med_int>& connectivity, Array<med_int>& family_values);
186 void _initMEDToArcaneTypes();
187 void _addTypeInfo(int dimension, int nb_node, med_int med_type, ItemTypeId arcane_type)
188 {
189 _addTypeInfo(dimension, nb_node, med_type, arcane_type, nullptr);
190 }
191 void _addTypeInfo(int dimension, int nb_node, med_int med_type, ItemTypeId arcane_type,
192 const Int32* indirection)
193 {
194 MEDToArcaneItemInfo t(dimension, nb_node, med_type, arcane_type, indirection);
195 Int32 index = m_med_to_arcane_types.size();
196 m_med_to_arcane_types.add(t);
197 m_med_geotype_to_arcane_type_index.insert(std::make_pair(med_type, index));
198 }
199 void _readAndCreateCells(IPrimaryMesh* mesh, Int32 mesh_dimension, med_idt fid, const char* meshname);
200 void _readFaces(IPrimaryMesh* mesh, Int32 mesh_dimension, med_idt fid, const char* meshname);
201
202 [[nodiscard]] IMeshReader::eReturnType
203 _readNodesCoordinates(IPrimaryMesh* mesh, Int64 nb_node, Int32 spacedim,
204 med_idt fid, const char* meshname);
205 void _readFamilies(med_idt fid, const char* meshname);
206 void _readAvailableTypes(med_idt fid, const char* meshname);
207 void _clearItemsInGroups()
208 {
209 for (MEDGroupInfo& g : m_med_groups) {
210 g.m_unique_ids.clear();
211 g.m_local_ids.clear();
212 }
213 }
214 void _broadcastGroups(ConstArrayView<String> names, IItemFamily* family);
215};
216
217/*---------------------------------------------------------------------------*/
218/*---------------------------------------------------------------------------*/
219
220namespace
221{
222 // MED numbering conventions are different from those used in Arcane.
223 // These arrays allow for renumbering.
224 const Int32 Hexaedron8_indirection[] = { 1, 0, 3, 2, 5, 4, 7, 6 };
225 const Int32 Hexaedron20_indirection[] = { 1, 8, 10, 3, 9, 2, 0, 11, 5, 14, 18, 7, 6, 4, 16, 15, 13, 12, 17, 19 };
226 const Int32 Pyramid5_indirection[] = { 1, 0, 3, 2, 4 };
227 const Int32 Quad4_indirection[] = { 1, 0, 3, 2 };
228 const Int32 Quad8_indirection[] = { 1, 0, 3, 2, 4, 7, 6, 5 };
229 const Int32 Triangle3_indirection[] = { 1, 0, 2 };
230 // Not used for now. To be tested.
231 const Int32 Tetraedron4_indirection[] = { 1, 0, 2, 3 };
232} // namespace
233
234/*---------------------------------------------------------------------------*/
235/*---------------------------------------------------------------------------*/
236
237void MEDMeshReader::
238_initMEDToArcaneTypes()
239{
240 m_med_to_arcane_types.clear();
241
242 // TODO: check the connectivity correspondence between
243 // Arcane and MED for quadrilateral elements
244 // 1D Types
245 _addTypeInfo(1, 2, MED_SEG2, ITI_Line2);
246 _addTypeInfo(1, 3, MED_SEG3, ITI_Line3); // Not supported
247 _addTypeInfo(1, 4, MED_SEG4, ITI_NullType); // Not supported
248
249 // 2D Types.
250 _addTypeInfo(2, 3, MED_TRIA3, ITI_Triangle3, Triangle3_indirection);
251 _addTypeInfo(2, 4, MED_QUAD4, ITI_Quad4, Quad4_indirection);
252 _addTypeInfo(2, 6, MED_TRIA6, ITI_NullType); // Not supported
253 _addTypeInfo(2, 7, MED_TRIA7, ITI_NullType); // Not supported
254 _addTypeInfo(2, 8, MED_QUAD8, ITI_Quad8, Quad8_indirection);
255 _addTypeInfo(2, 9, MED_QUAD9, ITI_NullType); // Not supported
256
257 // 3D Types
258 _addTypeInfo(3, 4, MED_TETRA4, ITI_Tetraedron4);
259 _addTypeInfo(3, 5, MED_PYRA5, ITI_Pyramid5, Pyramid5_indirection);
260 _addTypeInfo(3, 6, MED_PENTA6, ITI_Pentaedron6);
261 _addTypeInfo(3, 8, MED_HEXA8, ITI_Hexaedron8);
262 _addTypeInfo(3, 10, MED_TETRA10, ITI_Tetraedron10);
263 _addTypeInfo(3, 12, MED_OCTA12, ITI_Octaedron12);
264 _addTypeInfo(3, 13, MED_PYRA13, ITI_NullType); // Not supported
265 _addTypeInfo(3, 15, MED_PENTA15, ITI_NullType); // Not supported
266 _addTypeInfo(3, 18, MED_PENTA18, ITI_NullType); // Not supported
267 _addTypeInfo(3, 20, MED_HEXA20, ITI_Hexaedron20);
268 _addTypeInfo(3, 27, MED_HEXA27, ITI_NullType); // Not supported
269
270 // Cells whose geometry has variable connectivity.
271 // For now, we do not support any of these types in Arcane.
272 // We still process these elements to display an error if they are
273 // present in the mesh. By setting the node count to (0), we signal to _readItems()
274 // that we cannot process these elements.
275
276 _addTypeInfo(2, 0, MED_POLYGON, ITI_GenericPolygon);
277 _addTypeInfo(2, 0, MED_POLYGON2, ITI_NullType);
278 _addTypeInfo(3, 0, MED_POLYHEDRON, ITI_NullType);
279
280 // Cells whose geometry is dynamic (model discovery in the file)
281 // TODO: check how to process them
282 //#define MED_STRUCT_GEO_INTERNAL 600
283 //#define MED_STRUCT_GEO_SUP_INTERNAL 700
284}
285
286/*---------------------------------------------------------------------------*/
287/*---------------------------------------------------------------------------*/
288
289IMeshReader::eReturnType MEDMeshReader::
290readMesh(IPrimaryMesh* mesh, const String& file_name)
291{
292 info() << "Trying to read MED File name=" << file_name;
293 m_mesh = mesh;
294 return _readMesh(mesh, file_name);
295}
296
297/*---------------------------------------------------------------------------*/
298/*---------------------------------------------------------------------------*/
299
300IMeshReader::eReturnType MEDMeshReader::
301_readMesh(IPrimaryMesh* mesh, const String& filename)
302{
303 const med_idt fid = MEDfileOpen(filename.localstr(), MED_ACC_RDONLY);
304 if (fid < 0) {
305 MESSAGE("ERROR: can not open MED file ");
306 error() << "ERROR: can not open MED file '" << filename << "'";
308 }
309 // To guarantee file closure.
310 AutoCloseMED auto_close_med(fid);
311
312 int nb_mesh = MEDnMesh(fid);
313 if (nb_mesh < 0) {
314 error() << "Error reading number of meshes";
316 }
317 info() << "MED: nb_mesh=" << nb_mesh;
318 if (nb_mesh == 0) {
319 error() << "No mesh is present";
321 }
322
323 // The mesh we read is always the first one
324 int mesh_index = 1;
325
326 // Get the space dimension. This is necessary to dimension axisname and unitname
327 int nb_axis = MEDmeshnAxis(fid, mesh_index);
328 if (nb_axis < 0) {
329 error() << "Can not read number of axis (MEDmeshnAxis)";
331 }
332 info() << "MED: nb_axis=" << nb_axis;
333
334 UniqueArray<char> axisname(MED_SNAME_SIZE * nb_axis + 1, '\0');
335 UniqueArray<char> unitname(MED_SNAME_SIZE * nb_axis + 1, '\0');
336
337 char meshname[MED_NAME_SIZE + 1];
338 meshname[0] = '\0';
339 char meshdescription[MED_COMMENT_SIZE + 1];
340 meshdescription[0] = '\0';
341 char dtunit[MED_SNAME_SIZE + 1];
342 dtunit[0] = '\0';
343 med_int spacedim = 0;
344 med_int meshdim = 0;
345 med_mesh_type meshtype = MED_UNDEF_MESH_TYPE;
346 med_sorting_type sortingtype = MED_SORT_UNDEF;
347 med_int nstep = 0;
348 med_axis_type axistype = MED_UNDEF_AXIS_TYPE;
349 int err = 0;
350 err = MEDmeshInfo(fid, mesh_index, meshname, &spacedim, &meshdim, &meshtype, meshdescription,
351 dtunit, &sortingtype, &nstep, &axistype, axisname.data(), unitname.data());
352 if (err < 0) {
353 error() << "Can not read mesh info (MEDmeshInfo) r=" << err;
355 }
356 if (meshtype != MED_UNSTRUCTURED_MESH) {
357 error() << "Arcane handle only MED unstructured mesh (MED_UNSTRUCTURED_MESH) type=" << meshtype;
359 }
360 Integer mesh_dimension = meshdim;
361 if (mesh_dimension != 2 && mesh_dimension != 3)
362 ARCANE_FATAL("MED reader handles only 2D or 3D meshes");
363
364 info() << "MED: name=" << meshname;
365 info() << "MED: description=" << meshdescription;
366 info() << "MED: spacedim=" << spacedim;
367 info() << "MED: meshdim=" << meshdim;
368 info() << "MED: dtunit=" << dtunit;
369 info() << "MED: meshtype=" << meshtype;
370 info() << "MED: sortingtype=" << sortingtype;
371 info() << "MED: axistype=" << axistype;
372 info() << "MED: nstep=" << nstep;
373
374 Int64 nb_node = 0;
375 // Reading the number of nodes.
376 {
377 med_bool coordinatechangement;
378 med_bool geotransformation;
379 // TODO: process information such as coordinatechangement
380 // and geotransformation if needed
381 med_int med_nb_node = MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT, MED_NODE, MED_NO_GEOTYPE,
382 MED_COORDINATE, MED_NO_CMODE, &coordinatechangement,
383 &geotransformation);
384 if (med_nb_node < 0) {
385 error() << "Can not read number of nodes (MEDmeshnEntity) err=" << med_nb_node;
387 }
388 nb_node = med_nb_node;
389 }
390 info() << "MED: nb_node=" << nb_node;
391
392 mesh->setDimension(mesh_dimension);
393
394 // MED meshes can contain polygons.
395 // We therefore build the corresponding types.
396 // (NOTE: all subdomains must do this)
397 mesh->itemTypeMng()->buildPolygonTypes();
398
399 IParallelMng* pm = mesh->parallelMng();
400 bool is_parallel = pm->isParallel();
401 Int32 rank = mesh->meshPartInfo().partRank();
402 // In parallel, only rank 0 reads the mesh
403 bool is_read_items = !(is_parallel && rank != 0);
404 if (is_read_items) {
405 _readAvailableTypes(fid, meshname);
406 _readFamilies(fid, meshname);
407 _readAndCreateCells(mesh, mesh_dimension, fid, meshname);
408 }
409 // The IPrimaryMesh::endAllocate() method is collective, so everyone
410 // must call it even if ranks other than rank 0
411 // do not have cells.
412 mesh->endAllocate();
413
414 // List of names of created cell groups
415 // It will be used to transfer the list of groups to all ranks.
416 UniqueArray<String> cell_group_names;
417 IItemFamily* cell_family = mesh->cellFamily();
418 if (is_read_items) {
419 // Now that all cells have been created, we create the corresponding groups
420 // To do this, we iterate through all instances of 'm_med_groups' and if one has entities
421 // then they are cells to be added to a group.
422 // ATTENTION ATTENTION:
423 // NOTE: The groups must be common to all ranks. They must be broadcasted
424 UniqueArray<Int32> cell_local_ids;
425 for (const MEDGroupInfo& g : m_med_groups) {
426 Int32 nb_cell_in_group = g.m_unique_ids.size();
427 cell_local_ids.resize(nb_cell_in_group);
428 cell_family->itemsUniqueIdToLocalId(cell_local_ids, g.m_unique_ids);
429 for (const String& name : g.m_names) {
430 info() << "Group=" << name << " index=" << g.m_index << " nb_item=" << nb_cell_in_group;
431 CellGroup cell_group = cell_family->findGroup(name, true);
432 cell_group.addItems(cell_local_ids);
433 cell_group_names.add(name);
434 }
435 }
436 }
437 _broadcastGroups(cell_group_names, cell_family);
438
439 // Reading the faces
440 if (is_read_items) {
441 // Since the face numbering is not necessarily correct for all
442 // entity types (especially for order 2), we add an option to
443 // not read the faces.
444 bool is_face_group_disabled = false;
445 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_MED_DISABLE_FACEGROUP", true))
446 is_face_group_disabled = (v.value());
447 if (!is_face_group_disabled)
448 _readFaces(mesh, mesh_dimension, fid, meshname);
449 }
450
451 UniqueArray<String> face_group_names;
452 IItemFamily* face_family = mesh->faceFamily();
453 // Now add the faces to the groups.
454 if (is_read_items) {
455 for (const MEDGroupInfo& g : m_med_groups) {
456 Int32 nb_face_in_group = g.m_local_ids.size();
457 info() << "Check Group index=" << g.m_index << " nb_item=" << nb_face_in_group;
458 if (nb_face_in_group == 0)
459 continue;
460 for (const String& name : g.m_names) {
461 info() << "FaceGroup=" << name << " index=" << g.m_index << " nb_item=" << nb_face_in_group;
462 FaceGroup face_group = face_family->findGroup(name, true);
463 face_group.addItems(g.m_local_ids);
464 face_group_names.add(name);
465 }
466 }
467 }
468 _broadcastGroups(face_group_names, face_family);
469
470 if (is_read_items) {
471 // Reading the coordinates
472 return _readNodesCoordinates(mesh, nb_node, spacedim, fid, meshname);
473 }
474 return IMeshReader::RTOk;
475}
476
477/*---------------------------------------------------------------------------*/
478/*---------------------------------------------------------------------------*/
479/*!
480 * \brief Retrieves the list of geometric types present in the mesh.
481 */
482void MEDMeshReader::
483_readAvailableTypes(med_idt fid, const char* meshname)
484{
485 // Retrieves the number of geometric types
486 med_bool coordinatechangement;
487 med_bool geotransformation;
488 med_int nb_geo = MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, MED_GEO_ALL,
489 MED_CONNECTIVITY, MED_NODAL, &coordinatechangement,
490 &geotransformation);
491 if (nb_geo < 0)
492 ARCANE_FATAL("Can not read number of geometric entities nb_geo={0}", nb_geo);
493 info() << "MED: nb_geotype = " << nb_geo;
494
495 // Loop through the present types
496 for (med_int it = 1; it <= nb_geo; it++) {
497
498 med_geometry_type geotype = MED_GEO_ALL;
499 FixedArray<char, MED_NAME_SIZE + 1> geotype_name;
500
501 /* get geometry type */
502 med_int type_ret = MEDmeshEntityInfo(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, it,
503 geotype_name.data(), &geotype);
504 if (type_ret < 0)
505 ARCANE_FATAL("Can not read informations for geotype index={0} ret={1}", it, type_ret);
506 /* how many cells of type geotype ? */
507 med_int nb_item = MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, geotype,
508 MED_CONNECTIVITY, MED_NODAL, &coordinatechangement,
509 &geotransformation);
510 if (nb_item < 0)
511 ARCANE_FATAL("Can not read number of items for geotype={0} name={1} ret={2}",
512 geotype, geotype_name.data(), nb_item);
513 info() << "MED: type=" << geotype << " '" << geotype_name.data() << "' nb_item=" << nb_item;
514 m_med_geotypes_in_mesh.add(geotype);
515 }
516}
517
518/*---------------------------------------------------------------------------*/
519/*---------------------------------------------------------------------------*/
520
521void MEDMeshReader::
522_readAndCreateCells(IPrimaryMesh* mesh, Int32 mesh_dimension, med_idt fid, const char* meshname)
523{
524 _clearItemsInGroups();
525
526 // As a matter of principle, there is no uniqueId() for entities in MED (TODO: to verify)
527 // So we number the cells starting from zero and increment for each
528 // cell created.
529 Int64 cell_unique_id = 0;
530
531 UniqueArray<Int16> polygon_nb_nodes;
532 UniqueArray<med_int> med_connectivity;
533 UniqueArray<med_int> med_family_values;
534
535 ItemTypeMng* itm = mesh->itemTypeMng();
536 // Allocates cells type by type.
537 // Iterates through the available types and processes those that match the dimension
538 // of the mesh.
539 for (med_int geotype : m_med_geotypes_in_mesh) {
540 Int32 index_in_list = m_med_geotype_to_arcane_type_index[geotype];
541 const MEDToArcaneItemInfo& iinfo = m_med_to_arcane_types[index_in_list];
542
543 Int32 item_dimension = iinfo.dimension();
544 // We only process entities of the mesh dimension.
545 if (item_dimension != mesh_dimension)
546 continue;
547 Int32 nb_item = _readItems(fid, meshname, iinfo, polygon_nb_nodes, med_connectivity, med_family_values);
548 if (nb_item == 0)
549 continue;
550 Int16 arcane_type = iinfo.arcaneType();
551 Int32 nb_item_node = iinfo.nbNode();
552 Int32 nb_family_values = med_family_values.size();
553 if (arcane_type == IT_NullType) {
554 // Indicates a type supported by MED but not by Arcane
555 ARCANE_FATAL("MED type '{0}' is not supported by Arcane", iinfo.medType());
556 }
557 Int64 cells_infos_index = 0;
558 Int64 med_connectivity_index = 0;
559 const bool is_polygon = (iinfo.medType() == MED_POLYGON);
560
561 UniqueArray<Int64> cells_infos;
562 if (is_polygon)
563 cells_infos.resize(2 * nb_item + med_connectivity.size());
564 else
565 cells_infos.resize((2 + nb_item_node) * nb_item);
566
567 info() << "CELL_INFOS size=" << cells_infos.size() << " nb_item=" << nb_item
568 << " type=" << arcane_type;
569
570 const Int32* indirection = iinfo.indirection();
571 for (Int32 i = 0; i < nb_item; ++i) {
572 Int64 current_cell_unique_id = cell_unique_id;
573 ++cell_unique_id;
574 if (is_polygon) {
575 nb_item_node = polygon_nb_nodes[i];
576 arcane_type = itm->getPolygonType(static_cast<Int16>(nb_item_node));
577 cells_infos[cells_infos_index] = arcane_type;
578 ++cells_infos_index;
579 cells_infos[cells_infos_index] = current_cell_unique_id;
580 ++cells_infos_index;
581 Span<Int64> cinfo_span(cells_infos.span().subspan(cells_infos_index, nb_item_node));
582 Span<med_int> med_cinfo_span(med_connectivity.span().subspan(med_connectivity_index, nb_item_node));
583 for (Integer k = 0; k < nb_item_node; ++k) {
584 cinfo_span[k] = med_cinfo_span[k];
585 }
586 }
587 else {
588 cells_infos[cells_infos_index] = arcane_type;
589 ++cells_infos_index;
590
591 cells_infos[cells_infos_index] = current_cell_unique_id;
592 ++cells_infos_index;
593 Span<Int64> cinfo_span(cells_infos.span().subspan(cells_infos_index, nb_item_node));
594 Span<med_int> med_cinfo_span(med_connectivity.span().subspan(med_connectivity_index, nb_item_node));
595 if (indirection) {
596 for (Integer k = 0; k < nb_item_node; ++k) {
597 cinfo_span[k] = med_cinfo_span[indirection[k]];
598 }
599 }
600 else {
601 for (Integer k = 0; k < nb_item_node; ++k)
602 cinfo_span[k] = med_cinfo_span[k];
603 }
604 }
605 if (i < nb_family_values) {
606 // There is a family associated with the entity
607 med_int f = med_family_values[i];
608 auto x = m_med_families_map.find(f);
609 if (x == m_med_families_map.end()) {
610 ARCANE_FATAL("Can not find family id '{0}' for cell '{1}' of geotype '{2}'",
611 f, i, iinfo.medType());
612 }
613 m_med_groups[x->second.m_index].m_unique_ids.add(current_cell_unique_id);
614 }
615
616 med_connectivity_index += nb_item_node;
617 cells_infos_index += nb_item_node;
618 }
619 mesh->allocateCells(nb_item, cells_infos, false);
620 }
621}
622
623/*---------------------------------------------------------------------------*/
624/*---------------------------------------------------------------------------*/
625/*!
626 * \brief Reads the faces.
627 *
628 * There is no need to explicitly create the faces because this is done
629 * automatically in Arcane. We therefore use the MED faces only
630 * to add the faces into the corresponding groups in the mesh file.
631 */
632void MEDMeshReader::
633_readFaces(IPrimaryMesh* mesh, Int32 mesh_dimension, med_idt fid, const char* meshname)
634{
635 _clearItemsInGroups();
636 ItemTypeMng* itm = mesh->itemTypeMng();
637 NodesOfItemReorderer nodes_reorderer(itm);
638
639 IItemFamily* node_family = mesh->nodeFamily();
640 NodeInfoListView mesh_nodes(node_family);
641
642 UniqueArray<Int16> polygon_nb_nodes;
643 UniqueArray<med_int> med_connectivity;
644 UniqueArray<med_int> med_family_values;
645 // Iterates through the available types and processes those that correspond to the dimension
646 // of the mesh minus 1.
647 for (med_int geotype : m_med_geotypes_in_mesh) {
648 Int32 index_in_list = m_med_geotype_to_arcane_type_index[geotype];
649 const MEDToArcaneItemInfo& iinfo = m_med_to_arcane_types[index_in_list];
650
651 Int32 item_dimension = iinfo.dimension();
652 // We only process entities of the mesh dimension.
653 if (item_dimension != (mesh_dimension - 1))
654 continue;
655 ItemTypeInfo* iti = itm->typeFromId(iinfo.arcaneType());
656 info() << "Reading faces geotype=" << geotype << " arcane_type=" << iinfo.arcaneType()
657 << " " << iti->typeName();
658
659 Int32 nb_item = _readItems(fid, meshname, iinfo, polygon_nb_nodes, med_connectivity, med_family_values);
660 if (nb_item == 0)
661 continue;
662 ItemTypeId arcane_type(iinfo.arcaneType());
663 Int32 nb_item_node = iinfo.nbNode();
664 Int32 nb_family_values = med_family_values.size();
665 if (arcane_type == IT_NullType) {
666 // Indicates a type supported by MED but not by Arcane
667 ARCANE_FATAL("MED type '{0}' is not supported by Arcane", iinfo.medType());
668 }
669
670 SmallArray<Int64> orig_nodes_id(nb_item_node);
671 info() << "FACES_INFOS nb_item=" << nb_item << " type=" << arcane_type
672 << " nb_family_values=" << nb_family_values;
673
674 const Int32* indirection = iinfo.indirection();
675 Int64 med_connectivity_index = 0;
676
677 for (Int32 i = 0; i < nb_item; ++i) {
678 ArrayView<Int64> cinfo_span(orig_nodes_id);
679 Span<med_int> med_cinfo_span(med_connectivity.span().subspan(med_connectivity_index, nb_item_node));
680 if (indirection) {
681 for (Integer k = 0; k < nb_item_node; ++k) {
682 cinfo_span[k] = med_cinfo_span[indirection[k]];
683 }
684 }
685 else {
686 for (Integer k = 0; k < nb_item_node; ++k)
687 cinfo_span[k] = med_cinfo_span[k];
688 }
689 med_connectivity_index += nb_item_node;
690 // Search for the face in the mesh starting from the sorted uniqueIds of its nodes
691 nodes_reorderer.reorder(arcane_type, cinfo_span);
692 ConstArrayView<Int64> ordered_nodes = nodes_reorderer.sortedNodes();
693 //info() << "OrigMedNodes=" << med_cinfo_span;
694 //info() << "OrigNodes=" << orig_nodes_id;
695 //info() << "Nodes=" << ordered_nodes;
696 Node first_node(MeshUtils::findOneItem(node_family, ordered_nodes[0]));
697 if (first_node.null())
698 ARCANE_FATAL("Can not find node uid={0} for face index '{1}'", ordered_nodes[0], i);
699 Face face = MeshUtils::getFaceFromNodesUniqueId(first_node, ordered_nodes);
700 if (face.null()) {
701 info() << "ERROR: Can not find face in mesh i=" << i << " nodes=" << ordered_nodes;
702 info() << "List of faces for node=" << ItemPrinter(first_node);
703 for (Face subface : first_node.faces()) {
704 info() << "Face=" << ItemPrinter(subface);
705 for (Node subnode : subface.nodes()) {
706 info() << " Node=" << ItemPrinter(subnode);
707 }
708 }
709 ARCANE_FATAL("Can not find face with nodes=", ordered_nodes);
710 }
711 //info() << "Face=" << ItemPrinter(face);
712
713 // Add the face to the corresponding groups
714 if (i < nb_family_values) {
715 // There is a family associated with the entity
716 med_int f = med_family_values[i];
717 auto x = m_med_families_map.find(f);
718 if (x == m_med_families_map.end()) {
719 ARCANE_FATAL("Can not find family id '{0}' for face '{1}' of geotype '{2}'",
720 f, i, iinfo.medType());
721 }
722 //info() << "Add face to group_index=" << x->second.m_index;
723 m_med_groups[x->second.m_index].m_local_ids.add(face.localId());
724 }
725 }
726 info() << "END_READING_ITEMS";
727 }
728}
729
730/*---------------------------------------------------------------------------*/
731/*---------------------------------------------------------------------------*/
732
733IMeshReader::eReturnType MEDMeshReader::
734_readNodesCoordinates(IPrimaryMesh* mesh, Int64 nb_node, Int32 spacedim,
735 med_idt fid, const char* meshname)
736{
737 const bool do_verbose = false;
738 // Reads the node coordinates and positions the coordinates in Arcane
739
740 // Connectivity in MED starts at 1 and in Arcane at 0.
741 // The first node therefore has the value for uniqueId()
742 UniqueArray<Real3> nodes_coordinates(nb_node + 1);
743 {
744 UniqueArray<med_float> coordinates(nb_node * spacedim);
745 int err = MEDmeshNodeCoordinateRd(fid, meshname, MED_NO_DT, MED_NO_IT, MED_FULL_INTERLACE,
746 coordinates.data());
747 if (err < 0) {
748 error() << "Can not read nodes coordinates err=" << err;
750 }
751
752 if (spacedim == 3) {
753 for (Int64 i = 0; i < nb_node; ++i) {
754 Real3 xyz(coordinates[i * 3], coordinates[(i * 3) + 1], coordinates[(i * 3) + 2]);
755 if (do_verbose)
756 info() << "I=" << i << " XYZ=" << xyz;
757 nodes_coordinates[i + 1] = xyz;
758 }
759 }
760 else if (spacedim == 2) {
761 for (Int64 i = 0; i < nb_node; ++i) {
762 Real3 xyz(coordinates[i * 2], coordinates[(i * 2) + 1], 0.0);
763 if (do_verbose)
764 info() << "I=" << i << " XYZ=" << xyz;
765 nodes_coordinates[i + 1] = xyz;
766 }
767 }
768 else
769 ARCANE_THROW(NotImplementedException, "spacedim!=2 && spacedim!=3");
770 }
771
772 // Positions the coordinates
773 {
774 VariableNodeReal3& nodes_coord_var(mesh->nodesCoordinates());
775 ENUMERATE_NODE (inode, mesh->allNodes()) {
776 Node node = *inode;
777 nodes_coord_var[inode] = nodes_coordinates[node.uniqueId()];
778 }
779 }
780 return IMeshReader::RTOk;
781}
782
783/*---------------------------------------------------------------------------*/
784/*---------------------------------------------------------------------------*/
785/*!
786 * \brief Reads information about entities of a given type.
787 *
788 * Reads information about entities whose type is given by \a iinfo.
789 * The entities are cells in the MED sense, i.e., Edge, Face, or Cell.
790 * Returns the number of entities read.
791 * \a connectivity will contain the connectivities for the entities read and
792 * \a family_values the array for each entity of the family it belongs to. Note
793 * that \a family_values may be empty if there is no family associated with the
794 * entities.
795 *
796 * If the type is MED_POLYGON, then \a polygon_nb_nodes will contain the number
797 * of nodes for each polygon.
798 */
799Int32 MEDMeshReader::
800_readItems(med_idt fid, const char* meshname, const MEDToArcaneItemInfo& iinfo,
801 Array<Int16>& polygon_nb_nodes, Array<med_int>& connectivity,
802 Array<med_int>& family_values)
803{
804 constexpr bool is_verbose = false;
805
806 connectivity.clear();
807 family_values.clear();
808
809 int med_item_type = iinfo.medType();
810 med_bool coordinatechangement = {};
811 med_bool geotransformation = {};
812 med_int nb_med_item = 0;
813 if (iinfo.medType() == MED_POLYGON) {
814 // For polygons, a specific call is needed for the number of indices.
815 // This number corresponds to the number of entities plus one.
816 med_int nb_index = ::MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, med_item_type,
817 MED_INDEX_NODE, MED_NODAL, &coordinatechangement,
818 &geotransformation);
819 if (nb_index < 0)
820 ARCANE_FATAL("Can not read MED med_item_type '{0}' error={1}", med_item_type, nb_index);
821
822 info() << "MED: Reading items";
823 info() << "MED: type=" << med_item_type << " nb_index=" << nb_index;
824 if (nb_index < 1)
825 return 0;
826 nb_med_item = nb_index - 1;
827 polygon_nb_nodes.resize(nb_med_item);
828 // how many nodes for the polygon connectivity ?
829 med_int nb_connectivity = MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT,
830 MED_CELL, MED_POLYGON, MED_CONNECTIVITY, MED_NODAL,
831 &coordinatechangement, &geotransformation);
832 if (nb_connectivity < 0)
833 ARCANE_FATAL("Can not get connectivity size for MED_POLYGON err={0}", nb_connectivity);
834
835 // The table \a indexes contains for each cell the index of its first
836 // node in the connectivity. The number of nodes of the i-th entity
837 // is therefore equal to (indexes[i+1]-indexes[i]).
838 UniqueArray<med_int> indexes(nb_index);
839 connectivity.resize(nb_connectivity);
840 info() << "Reading polygons nb_connectivity=" << nb_connectivity;
841 int r = MEDmeshPolygonRd(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, MED_NODAL,
842 indexes.data(), connectivity.data());
843 if (r < 0)
844 ARCANE_FATAL("Can not read connectivity for MED_POLYGON err={0}", r);
845 info() << "INDEXES=" << indexes;
846 for (Int32 i = 0; i < nb_med_item; ++i)
847 polygon_nb_nodes[i] = static_cast<Int16>(indexes[i + 1] - indexes[i]);
848 }
849 else {
850 nb_med_item = ::MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, med_item_type,
851 MED_CONNECTIVITY, MED_NODAL, &coordinatechangement,
852 &geotransformation);
853 if (nb_med_item < 0)
854 ARCANE_FATAL("Can not read MED med_item_type '{0}' error={1}", med_item_type, nb_med_item);
855
856 info() << "MED: Reading items";
857 info() << "MED: type=" << med_item_type << " nb_item=" << nb_med_item;
858 if (nb_med_item == 0)
859 return 0;
860
861 Int64 nb_node = iinfo.nbNode();
862 if (nb_node == 0)
863 // Indicates an element that we do not know how to process.
864 ARCANE_THROW(NotImplementedException, "Reading items with MED type '{0}'", med_item_type);
865
866 connectivity.resize(nb_node * nb_med_item);
867 int err = MEDmeshElementConnectivityRd(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL,
868 med_item_type, MED_NODAL, MED_FULL_INTERLACE,
869 connectivity.data());
870 if (err < 0)
871 ARCANE_FATAL("Can not read connectivity MED med_item_type '{0}' error={1}",
872 med_item_type, err);
873 }
874 if (is_verbose)
875 info() << "CON: " << connectivity;
876 {
877 med_int nb_med_family = MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT,
878 MED_CELL, med_item_type, MED_FAMILY_NUMBER, MED_NODAL,
879 &coordinatechangement, &geotransformation);
880 info() << "nb_family=" << nb_med_family;
881 if (nb_med_family < 0)
882 ARCANE_FATAL("Can not read family size for type med_item_type={0} error={1}", med_item_type, nb_med_family);
883 if (nb_med_family > 0) {
884 family_values.resize(nb_med_family);
885 int r = MEDmeshEntityFamilyNumberRd(fid, meshname, MED_NO_DT, MED_NO_IT,
886 MED_CELL, med_item_type, family_values.data());
887 if (r < 0)
888 ARCANE_FATAL("Can not read family values for type med_item_type={0} error={1}", med_item_type, nb_med_family);
889 if (is_verbose)
890 info() << "FAM: " << family_values;
891 }
892 }
893 return nb_med_item;
894}
895
896/*---------------------------------------------------------------------------*/
897/*---------------------------------------------------------------------------*/
898
899void MEDMeshReader::
900_readFamilies(med_idt fid, const char* meshname)
901{
902 FixedArray<char, MED_NAME_SIZE + 1> familyname;
903
904 info() << "Read families";
905
906 // Retrieves the number of families
907 med_int nb_family = MEDnFamily(fid, meshname);
908 if (nb_family < 0)
909 ARCANE_FATAL("Can not read number of families (error={0})", nb_family);
910
911 info() << "MED: nb_family= " << nb_family;
912 for (med_int i = 0; i < nb_family; i++) {
913 info() << "MED: Read family i=" << i;
914
915 med_int nb_group = MEDnFamilyGroup(fid, meshname, i + 1);
916 if (nb_group < 0)
917 ARCANE_FATAL("Can not read number of groups for family index={0}", i);
918 info() << "MED: family index=" << i << " nb_group=" << nb_group;
919
920 // Reads the family groups
921 // Even if there are no groups associated with the family, we continue
922 // the processing because entities may reference families without groups.
923
924 // In MED, groups have a fixed maximum size MED_LNAME_SIZE
925 UniqueArray<char> all_group_names(MED_LNAME_SIZE * nb_group + 1);
926 med_int family_number = 0;
927 if (MEDfamilyInfo(fid, meshname, i + 1, familyname.data(), &family_number, all_group_names.data()) < 0)
928 ARCANE_FATAL("Can not read group names from family index={0}", i);
929
930 MEDFamilyInfo med_family(family_number);
931 Int32 group_index = m_med_groups.size();
932 med_family.m_index = group_index;
933 MEDGroupInfo med_group(group_index);
934
935 // Retrieves the names of the family groups
936 for (Int32 z = 0; z < nb_group; ++z) {
937 //info() << " groupname=" << group_names << " number=" << familynumber;
938 SmallSpan<char> med_group_name = all_group_names.smallSpan().subSpan(MED_LNAME_SIZE * z, MED_LNAME_SIZE);
939 // Groups in MED may contain characters not supported by Arcane.
940 // We remove them.
941 SmallArray<Byte, MED_LNAME_SIZE + 1> valid_name;
942 Int32 pos = 0;
943 for (; pos < MED_LNAME_SIZE; ++pos) {
944 char c = med_group_name[pos];
945 if (c == '\0')
946 break;
947 if (c == ' ' || c == '_')
948 continue;
949 valid_name.add(static_cast<Byte>(c));
950 }
951 String name(valid_name.view());
952 med_group.m_names.add(name);
953 info() << "Family id=" << family_number << " group='" << name << "'";
954 }
955
956 m_med_families_map.insert(std::make_pair(family_number, med_family));
957 m_med_groups.add(med_group);
958 }
959}
960
961/*---------------------------------------------------------------------------*/
962/*---------------------------------------------------------------------------*/
963/*!
964 * \brief Broadcast the groups of \a group_names for the family \a family.
965 *
966 * The list of groups \a group_names is only used for rank 0.
967 */
968void MEDMeshReader::
969_broadcastGroups(ConstArrayView<String> group_names, IItemFamily* family)
970{
971 IParallelMng* pm = m_mesh->parallelMng();
972
973 Int32 rank = pm->commRank();
974 // Ensures that all ranks know the groups
975 if (rank == 0) {
976 Int32 nb_group = group_names.size();
977 pm->broadcast(ArrayView<Int32>(1, &nb_group), 0);
978 for (String name : group_names)
979 pm->broadcastString(name, 0);
980 }
981 else {
982 Int32 nb_group = 0;
983 pm->broadcast(ArrayView<Int32>(1, &nb_group), 0);
984 String current_group_name;
985 for (Int32 i = 0; i < nb_group; ++i) {
986 pm->broadcastString(current_group_name, 0);
987 CellGroup cell_group = family->findGroup(current_group_name, true);
988 }
989 }
990}
991
992/*---------------------------------------------------------------------------*/
993/*---------------------------------------------------------------------------*/
994
995/*---------------------------------------------------------------------------*/
996/*---------------------------------------------------------------------------*/
997/*!
998 * \brief Service for reading a mesh in MED format.
999 */
1000class MEDMeshReaderService
1001: public BasicService
1002, public IMeshReader
1003{
1004 public:
1005
1006 explicit MEDMeshReaderService(const ServiceBuildInfo& sbi)
1007 : BasicService(sbi)
1008 {}
1009
1010 public:
1011
1012 void build() override {}
1013 bool allowExtension(const String& str) override
1014 {
1015 return str == "med";
1016 }
1018 [[maybe_unused]] const XmlNode& mesh_element,
1019 const String& file_name,
1020 const String& dir_name,
1021 [[maybe_unused]] bool use_internal_partition) override
1022 {
1023 ARCANE_UNUSED(dir_name);
1024 MEDMeshReader reader(traceMng());
1025 return reader.readMesh(mesh, file_name);
1026 }
1027};
1028
1029/*---------------------------------------------------------------------------*/
1030/*---------------------------------------------------------------------------*/
1031
1032ARCANE_REGISTER_SERVICE(MEDMeshReaderService,
1033 ServiceProperty("MEDMeshReader", ST_SubDomain),
1034 ARCANE_SERVICE_INTERFACE(IMeshReader));
1035
1036/*---------------------------------------------------------------------------*/
1037/*---------------------------------------------------------------------------*/
1038
1039/*---------------------------------------------------------------------------*/
1040/*---------------------------------------------------------------------------*/
1041/*!
1042 * \brief Service for reading a mesh in MED format from the dataset.
1043 */
1044class MEDCaseMeshReader
1045: public AbstractService
1046, public ICaseMeshReader
1047{
1048 public:
1049
1050 class Builder
1051 : public IMeshBuilder
1052 {
1053 public:
1054
1055 explicit Builder(ITraceMng* tm, const CaseMeshReaderReadInfo& read_info)
1056 : m_trace_mng(tm)
1057 , m_read_info(read_info)
1058 {}
1059
1060 public:
1061
1062 void fillMeshBuildInfo(MeshBuildInfo& build_info) override
1063 {
1064 ARCANE_UNUSED(build_info);
1065 }
1067 {
1068 MEDMeshReader reader(m_trace_mng);
1069 String fname = m_read_info.fileName();
1070 m_trace_mng->info() << "MED Reader (ICaseMeshReader) file_name=" << fname;
1071 IMeshReader::eReturnType ret = reader.readMesh(pm, fname);
1072 if (ret != IMeshReader::RTOk)
1073 ARCANE_FATAL("Can not read MED File");
1074 }
1075
1076 private:
1077
1078 ITraceMng* m_trace_mng;
1079 CaseMeshReaderReadInfo m_read_info;
1080 };
1081
1082 public:
1083
1084 explicit MEDCaseMeshReader(const ServiceBuildInfo& sbi)
1085 : AbstractService(sbi)
1086 {}
1087
1088 public:
1089
1091 {
1092 IMeshBuilder* builder = nullptr;
1093 if (read_info.format() == "med")
1094 builder = new Builder(traceMng(), read_info);
1095 return makeRef(builder);
1096 }
1097};
1098
1099/*---------------------------------------------------------------------------*/
1100/*---------------------------------------------------------------------------*/
1101
1102ARCANE_REGISTER_SERVICE(MEDCaseMeshReader,
1103 ServiceProperty("MEDCaseMeshReader", ST_SubDomain),
1104 ARCANE_SERVICE_INTERFACE(ICaseMeshReader));
1105
1106/*---------------------------------------------------------------------------*/
1107/*---------------------------------------------------------------------------*/
1108
1109} // namespace Arcane
1110
1111/*---------------------------------------------------------------------------*/
1112/*---------------------------------------------------------------------------*/
#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.
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.
Base class of a service.
AbstractService(const ServiceBuildInfo &)
Constructor from a ServiceBuildInfo.
Base class for 1D data vectors.
Necessary information for reading a mesh file.
Constant view of an array of type T.
static std::optional< Int32 > tryParseFromEnvironment(StringView s, bool throw_if_invalid)
Interface for the mesh reading service from the dataset.
Interface of an entity family.
Definition IItemFamily.h:83
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
void addItems(Int32ConstArrayView items_local_id, bool check_if_present=true)
Adds entities.
Definition ItemGroup.cc:439
Type of an entity (Item).
Definition ItemTypeId.h:33
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.
Parameters necessary for building a mesh.
Reference to an instance.
Structure containing the information to create a service.
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:43
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Creates a reference on a pointer.
std::int32_t Int32
Signed integer type of 32 bits.