Arcane  4.2.1.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
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/* Lecture d'un maillage au format MED. */
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
19#include "arcane/core/IMeshReader.h"
20#include "arcane/core/BasicService.h"
22#include "arcane/core/IPrimaryMesh.h"
23#include "arcane/core/IItemFamily.h"
24#include "arcane/core/ICaseMeshReader.h"
25#include "arcane/core/IMeshBuilder.h"
26#include "arcane/core/IParallelMng.h"
27#include "arcane/core/MeshPartInfo.h"
28#include "arcane/core/NodesOfItemReorderer.h"
30#include "arcane/core/ItemPrinter.h"
31
32#include <med.h>
33#define MESGERR 1
34#include <med_utils.h>
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38
39namespace Arcane
40{
41
42/*---------------------------------------------------------------------------*/
43/*---------------------------------------------------------------------------*/
44/*!
45 * \brief Lecteur de maillages au format MED.
46 *
47 * Première version d'un lecteur MED gérant uniquement les maillages 2D, 3D et
48 * non structurés.
49 */
50class MEDMeshReader
51: public TraceAccessor
52{
53 public:
54
55 /*!
56 * \brief Informations pour passer des types MED aux types Arcane pour les entités.
57 *
58 * \a indirection() est non nul si la connectivité MED est différente de la
59 * connectivité Arcane, ce qui est le cas pour les entités 2D et 3D.
60 */
61 class MEDToArcaneItemInfo
62 {
63 public:
64
65 MEDToArcaneItemInfo(int dimension, int nb_node, med_int med_type,
66 ItemTypeId arcane_type, const Int32* indirection)
67 : m_dimension(dimension)
68 , m_nb_node(nb_node)
69 , m_med_type(med_type)
70 , m_arcane_type(arcane_type)
71 , m_indirection(indirection)
72 {}
73
74 public:
75
76 int dimension() const { return m_dimension; }
77 int nbNode() const { return m_nb_node; }
78 med_int medType() const { return m_med_type; }
79 Int16 arcaneType() const { return m_arcane_type; }
80 const Int32* indirection() const { return m_indirection; }
81
82 private:
83
84 int m_dimension = -1;
85 int m_nb_node = -1;
86 med_int m_med_type = {};
87 ItemTypeId m_arcane_type = ITI_NullType;
88 const Int32* m_indirection = nullptr;
89 };
90
91 //! Information sur une famille d'entité MED
92 class MEDFamilyInfo
93 {
94 public:
95
96 explicit MEDFamilyInfo(Int32 family_id)
97 : m_family_id(family_id)
98 {}
99
100 public:
101
102 //! Id de la famille pour MED
104 //! Index dans la liste des groupes Arcane.
106 };
107
108 /*!
109 * \brief Liste des groupes et des entités leur appartenant.
110 *
111 * Pour chaque groupe, on peut soit donner la liste des uniqueId()
112 * des entités qui vont être dedans, soit la liste des localId().
113 * Le premier cas est utilisé par les mailles et le second
114 * par les faces et les noeuds
115 */
116 class MEDGroupInfo
117 {
118 public:
119
120 explicit MEDGroupInfo(Int32 index)
121 : m_index(index)
122 {}
123
124 public:
125
126 //! Index du groupe dans la liste des groupes
128 //! Nom des groupes associés
130 //! Liste des uniqueId() des entités du groupe.
132 //! Liste des localId() des entités du groupe.
134 };
135
136 public:
137
138 explicit MEDMeshReader(ITraceMng* tm)
139 : TraceAccessor(tm)
140 {
141 _initMEDToArcaneTypes();
142 }
143
144 public:
145
146 [[nodiscard]] IMeshReader::eReturnType
147 readMesh(IPrimaryMesh* mesh, const String& file_name);
148
149 private:
150
151 IMeshReader::eReturnType _readMesh(IPrimaryMesh* mesh, const String& filename);
152
153 private:
154
155 // Structure pour fermer automatiquement les fichiers MED ouverts
156 struct AutoCloseMED
157 {
158 explicit AutoCloseMED(med_idt id)
159 : fid(id)
160 {}
161 ~AutoCloseMED()
162 {
163 if (fid >= 0)
164 ::MEDfileClose(fid);
165 }
166
167 med_idt fid;
168 };
169
170 //! Maillage en cours de lecture
171 IPrimaryMesh* m_mesh = nullptr;
172 //! Tableau de conversion entre les types MED et Arcane
173 UniqueArray<MEDToArcaneItemInfo> m_med_to_arcane_types;
174 //! Table des index dans \a m_med_to_arcane_type de chaque geotype
175 std::unordered_map<med_int, Int32> m_med_geotype_to_arcane_type_index;
176 //! Liste des familles
177 std::unordered_map<Int32, MEDFamilyInfo> m_med_families_map;
178 //! Liste des informations sur les groupes
179 UniqueArray<MEDGroupInfo> m_med_groups;
180 //! Liste des 'geotype' présents dans le maillage
181 UniqueArray<med_int> m_med_geotypes_in_mesh;
182
183 private:
184
185 Int32 _readItems(med_idt fid, const char* meshnane, const MEDToArcaneItemInfo& iinfo,
186 Array<Int16>& polygon_nb_nodes, Array<med_int>& connectivity, Array<med_int>& family_values);
187 void _initMEDToArcaneTypes();
188 void _addTypeInfo(int dimension, int nb_node, med_int med_type, ItemTypeId arcane_type)
189 {
190 _addTypeInfo(dimension, nb_node, med_type, arcane_type, nullptr);
191 }
192 void _addTypeInfo(int dimension, int nb_node, med_int med_type, ItemTypeId arcane_type,
193 const Int32* indirection)
194 {
195 MEDToArcaneItemInfo t(dimension, nb_node, med_type, arcane_type, indirection);
196 Int32 index = m_med_to_arcane_types.size();
197 m_med_to_arcane_types.add(t);
198 m_med_geotype_to_arcane_type_index.insert(std::make_pair(med_type, index));
199 }
200 void _readAndCreateCells(IPrimaryMesh* mesh, Int32 mesh_dimension, med_idt fid, const char* meshname);
201 void _readFaces(IPrimaryMesh* mesh, Int32 mesh_dimension, med_idt fid, const char* meshname);
202
203 [[nodiscard]] IMeshReader::eReturnType
204 _readNodesCoordinates(IPrimaryMesh* mesh, Int64 nb_node, Int32 spacedim,
205 med_idt fid, const char* meshname);
206 void _readFamilies(med_idt fid, const char* meshname);
207 void _readAvailableTypes(med_idt fid, const char* meshname);
208 void _clearItemsInGroups()
209 {
210 for (MEDGroupInfo& g : m_med_groups) {
211 g.m_unique_ids.clear();
212 g.m_local_ids.clear();
213 }
214 }
215 void _broadcastGroups(ConstArrayView<String> names, IItemFamily* family);
216};
217
218/*---------------------------------------------------------------------------*/
219/*---------------------------------------------------------------------------*/
220
221namespace
222{
223 // Les conventions de numérotations de MED sont différentes de celles
224 // utilisées dans Arcane. Ces tableaux permettent d'effectuer la renumérotation.
225 const Int32 Hexaedron8_indirection[] = { 1, 0, 3, 2, 5, 4, 7, 6 };
226 const Int32 Hexaedron20_indirection[] = { 1, 8, 10, 3, 9, 2, 0, 11, 5, 14, 18, 7, 6, 4, 16, 15, 13, 12, 17, 19 };
227 const Int32 Pyramid5_indirection[] = { 1, 0, 3, 2, 4 };
228 const Int32 Quad4_indirection[] = { 1, 0, 3, 2 };
229 const Int32 Quad8_indirection[] = { 1, 0, 3, 2, 4, 7, 6, 5 };
230 const Int32 Triangle3_indirection[] = { 1, 0, 2 };
231 // PAS utilisé pour l'instant. À tester.
232 const Int32 Tetraedron4_indirection[] = { 1, 0, 2, 3 };
233} // namespace
234
235/*---------------------------------------------------------------------------*/
236/*---------------------------------------------------------------------------*/
237
238void MEDMeshReader::
239_initMEDToArcaneTypes()
240{
241 m_med_to_arcane_types.clear();
242
243 // TODO: regarder la correspondance de connectivité entre
244 // Arcane et MED pour les éléments quadratiques
245 // Types 1D
246 _addTypeInfo(1, 2, MED_SEG2, ITI_Line2);
247 _addTypeInfo(1, 3, MED_SEG3, ITI_Line3); // Non supporté
248 _addTypeInfo(1, 4, MED_SEG4, ITI_NullType); // Non supporté
249
250 // Types 2D.
251 _addTypeInfo(2, 3, MED_TRIA3, ITI_Triangle3, Triangle3_indirection);
252 _addTypeInfo(2, 4, MED_QUAD4, ITI_Quad4, Quad4_indirection);
253 _addTypeInfo(2, 6, MED_TRIA6, ITI_NullType); // Non supporté
254 _addTypeInfo(2, 7, MED_TRIA7, ITI_NullType); // Non supporté
255 _addTypeInfo(2, 8, MED_QUAD8, ITI_Quad8, Quad8_indirection);
256 _addTypeInfo(2, 9, MED_QUAD9, ITI_NullType); // Non supporté
257
258 // Types 3D
259 _addTypeInfo(3, 4, MED_TETRA4, ITI_Tetraedron4);
260 _addTypeInfo(3, 5, MED_PYRA5, ITI_Pyramid5, Pyramid5_indirection);
261 _addTypeInfo(3, 6, MED_PENTA6, ITI_Pentaedron6);
262 _addTypeInfo(3, 8, MED_HEXA8, ITI_Hexaedron8);
263 _addTypeInfo(3, 10, MED_TETRA10, ITI_Tetraedron10);
264 _addTypeInfo(3, 12, MED_OCTA12, ITI_Octaedron12);
265 _addTypeInfo(3, 13, MED_PYRA13, ITI_NullType); // Non supporté
266 _addTypeInfo(3, 15, MED_PENTA15, ITI_NullType); // Non supporté
267 _addTypeInfo(3, 18, MED_PENTA18, ITI_NullType); // Non supporté
268 _addTypeInfo(3, 20, MED_HEXA20, ITI_Hexaedron20);
269 _addTypeInfo(3, 27, MED_HEXA27, ITI_NullType); // Non supporté
270
271 // Mailles dont la géométrie à une connectivité variable.
272 // Pour l'instant, on ne supporte aucun de ces types dans Arcane.
273 // On traite quand même ces éléments pour afficher une erreur s'ils sont
274 // présents dans le maillage. En mettant la valeur (0) pour le nombre
275 // de noeuds, on signale à _readItems() qu'on ne sait pas traiter ces éléments.
276
277 _addTypeInfo(2, 0, MED_POLYGON, ITI_GenericPolygon);
278 _addTypeInfo(2, 0, MED_POLYGON2, ITI_NullType);
279 _addTypeInfo(3, 0, MED_POLYHEDRON, ITI_NullType);
280
281 // Mailles dont la géométrie est dynamique (découverte du modèle dans le fichier)
282 // TODO: regarder comment les traiter
283 //#define MED_STRUCT_GEO_INTERNAL 600
284 //#define MED_STRUCT_GEO_SUP_INTERNAL 700
285}
286
287/*---------------------------------------------------------------------------*/
288/*---------------------------------------------------------------------------*/
289
290IMeshReader::eReturnType MEDMeshReader::
291readMesh(IPrimaryMesh* mesh, const String& file_name)
292{
293 info() << "Tentative de lecture du fichier MED nommé=" << file_name;
294 m_mesh = mesh;
295 return _readMesh(mesh, file_name);
296}
297
298/*---------------------------------------------------------------------------*/
299/*---------------------------------------------------------------------------*/
300
301IMeshReader::eReturnType MEDMeshReader::
302_readMesh(IPrimaryMesh* mesh, const String& filename)
303{
304 const med_idt fid = MEDfileOpen(filename.localstr(), MED_ACC_RDONLY);
305 if (fid < 0) {
306 MESSAGE("ERROR: can not open MED file ");
307 error() << "ERROR: can not open MED file '" << filename << "'";
309 }
310 // Pour garantir la fermeture du fichier.
311 AutoCloseMED auto_close_med(fid);
312
313 int nb_mesh = MEDnMesh(fid);
314 if (nb_mesh < 0) {
315 error() << "Erreur lors de la lecture du nombre de maillages";
317 }
318 info() << "MED: nb_mesh=" << nb_mesh;
319 if (nb_mesh == 0) {
320 error() << "Aucun maillage n'est présent";
322 }
323
324 // Le maillage qu'on lit est toujours le premier
325 int mesh_index = 1;
326
327 // Récupère la dimension d'espace. Cela est nécessaire pour dimensionner axisname eet unitname
328 int nb_axis = MEDmeshnAxis(fid, mesh_index);
329 if (nb_axis < 0) {
330 error() << "Impossible de lire le nombre d'axes (MEDmeshnAxis)";
332 }
333 info() << "MED: nb_axis=" << nb_axis;
334
335 UniqueArray<char> axisname(MED_SNAME_SIZE * nb_axis + 1, '\0');
336 UniqueArray<char> unitname(MED_SNAME_SIZE * nb_axis + 1, '\0');
337
338 char meshname[MED_NAME_SIZE + 1];
339 meshname[0] = '\0';
340 char meshdescription[MED_COMMENT_SIZE + 1];
341 meshdescription[0] = '\0';
342 char dtunit[MED_SNAME_SIZE + 1];
343 dtunit[0] = '\0';
344 med_int spacedim = 0;
345 med_int meshdim = 0;
346 med_mesh_type meshtype = MED_UNDEF_MESH_TYPE;
347 med_sorting_type sortingtype = MED_SORT_UNDEF;
348 med_int nstep = 0;
349 med_axis_type axistype = MED_UNDEF_AXIS_TYPE;
350 int err = 0;
351 err = MEDmeshInfo(fid, mesh_index, meshname, &spacedim, &meshdim, &meshtype, meshdescription,
352 dtunit, &sortingtype, &nstep, &axistype, axisname.data(), unitname.data());
353 if (err < 0) {
354 error() << "Impossible de lire les informations du maillage (MEDmeshInfo) r=" << err;
356 }
357 if (meshtype != MED_UNSTRUCTURED_MESH) {
358 error() << "Arcane ne gère que les maillages non structurés MED (MED_UNSTRUCTURED_MESH) type=" << meshtype;
360 }
361 Integer mesh_dimension = meshdim;
362 if (mesh_dimension != 2 && mesh_dimension != 3)
363 ARCANE_FATAL("Le lecteur MED ne gère que les maillages 2D ou 3D");
364
365 info() << "MED: name=" << meshname;
366 info() << "MED: description=" << meshdescription;
367 info() << "MED: spacedim=" << spacedim;
368 info() << "MED: meshdim=" << meshdim;
369 info() << "MED: dtunit=" << dtunit;
370 info() << "MED: meshtype=" << meshtype;
371 info() << "MED: sortingtype=" << sortingtype;
372 info() << "MED: axistype=" << axistype;
373 info() << "MED: nstep=" << nstep;
374
375 Int64 nb_node = 0;
376 // Lecture du nombre de noeuds.
377 {
378 med_bool coordinatechangement;
379 med_bool geotransformation;
380 // TODO: traiter les informations telles que coordinatechangement
381 // et geotransformation si besoin
382 med_int med_nb_node = MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT, MED_NODE, MED_NO_GEOTYPE,
383 MED_COORDINATE, MED_NO_CMODE, &coordinatechangement,
384 &geotransformation);
385 if (med_nb_node < 0) {
386 error() << "Impossible de lire le nombre de nœuds (MEDmeshnEntity) err=" << med_nb_node;
388 }
389 nb_node = med_nb_node;
390 }
391 info() << "MED: nb_node=" << nb_node;
392
393 mesh->setDimension(mesh_dimension);
394
395 // Les maillages MED peuvent contenir des polygones.
396 // On construit donc les types correspondants.
397 // (NOTE : tous les sous-domaines doivent faire cela)
398 mesh->itemTypeMng()->buildPolygonTypes();
399
400 IParallelMng* pm = mesh->parallelMng();
401 bool is_parallel = pm->isParallel();
402 Int32 rank = mesh->meshPartInfo().partRank();
403 // En parallèle, seul le rang 0 lit le maillage
404 bool is_read_items = !(is_parallel && rank != 0);
405 if (is_read_items) {
406 _readAvailableTypes(fid, meshname);
407 _readFamilies(fid, meshname);
408 _readAndCreateCells(mesh, mesh_dimension, fid, meshname);
409 }
410 // La méthode IPrimaryMesh::endAllocate() est collective donc tout
411 // le monde doit l'appeler même si les rangs autres que le rang 0
412 // qui n'ont pas de mailles.
413 mesh->endAllocate();
414
415 // Liste des noms des groupes de mailles créées
416 // Elle servira à transférer la liste des groupes à tous les rangs.
417 UniqueArray<String> cell_group_names;
418 IItemFamily* cell_family = mesh->cellFamily();
419 if (is_read_items) {
420 // Maintenant qu'on a créé toutes les mailles, on crée les groupes correspondants
421 // Pour cela, on parcourt toutes les instances de 'm_med_groups' et si une a des entités
422 // alors ce sont des mailles à ajouter à un groupe.
423 // ATTENTION ATTENTION:
424 // NOTE: Les groupes doivent être communs à tous les rangs. Il faut les broadcaster
425 UniqueArray<Int32> cell_local_ids;
426 for (const MEDGroupInfo& g : m_med_groups) {
427 Int32 nb_cell_in_group = g.m_unique_ids.size();
428 cell_local_ids.resize(nb_cell_in_group);
429 cell_family->itemsUniqueIdToLocalId(cell_local_ids, g.m_unique_ids);
430 for (const String& name : g.m_names) {
431 info() << "Group=" << name << " index=" << g.m_index << " nb_item=" << nb_cell_in_group;
432 CellGroup cell_group = cell_family->findGroup(name, true);
433 cell_group.addItems(cell_local_ids);
434 cell_group_names.add(name);
435 }
436 }
437 }
438 _broadcastGroups(cell_group_names, cell_family);
439
440 // Lit les faces
441 if (is_read_items) {
442 // Comme la numérotation des faces n'est pas forcément correcte pour tous
443 // les types d'entités (notamment pour l'ordre 2), on ajoute une option pour
444 // ne pas lire les faces.
445 bool is_face_group_disabled = false;
446 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_MED_DISABLE_FACEGROUP", true))
447 is_face_group_disabled = (v.value());
448 if (!is_face_group_disabled)
449 _readFaces(mesh, mesh_dimension, fid, meshname);
450 }
451
452 UniqueArray<String> face_group_names;
453 IItemFamily* face_family = mesh->faceFamily();
454 // Maintenant ajoute les faces aux groupes.
455 if (is_read_items) {
456 for (const MEDGroupInfo& g : m_med_groups) {
457 Int32 nb_face_in_group = g.m_local_ids.size();
458 info() << "Vérification du groupe index=" << g.m_index << " nb_item=" << nb_face_in_group;
459 if (nb_face_in_group == 0)
460 continue;
461 for (const String& name : g.m_names) {
462 info() << "FaceGroup=" << name << " index=" << g.m_index << " nb_item=" << nb_face_in_group;
463 FaceGroup face_group = face_family->findGroup(name, true);
464 face_group.addItems(g.m_local_ids);
465 face_group_names.add(name);
466 }
467 }
468 }
469 _broadcastGroups(face_group_names, face_family);
470
471 if (is_read_items) {
472 // Lit les coordonnées
473 return _readNodesCoordinates(mesh, nb_node, spacedim, fid, meshname);
474 }
475 return IMeshReader::RTOk;
476}
477
478/*---------------------------------------------------------------------------*/
479/*---------------------------------------------------------------------------*/
480/*!
481 * \brief Récupère la liste des types géométriques présents dans le maillage.
482 */
483void MEDMeshReader::
484_readAvailableTypes(med_idt fid, const char* meshname)
485{
486 // Récupère le nombre de types géométriques
487 med_bool coordinatechangement;
488 med_bool geotransformation;
489 med_int nb_geo = MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, MED_GEO_ALL,
490 MED_CONNECTIVITY, MED_NODAL, &coordinatechangement,
491 &geotransformation);
492 if (nb_geo < 0)
493 ARCANE_FATAL("Impossible de lire le nombre d'entités géométriques nb_geo={0}", nb_geo);
494 info() << "MED: nb_geotype = " << nb_geo;
495
496 // Boucle sur les types présents
497 for (med_int it = 1; it <= nb_geo; it++) {
498
499 med_geometry_type geotype = MED_GEO_ALL;
500 FixedArray<char, MED_NAME_SIZE + 1> geotype_name;
501
502 /* get geometry type */
503 med_int type_ret = MEDmeshEntityInfo(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, it,
504 geotype_name.data(), &geotype);
505 if (type_ret < 0)
506 ARCANE_FATAL("Impossible de lire les informations pour le géotype index={0} ret={1}", it, type_ret);
507 /* combien de mailles de type géotype ? */
508 med_int nb_item = MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, geotype,
509 MED_CONNECTIVITY, MED_NODAL, &coordinatechangement,
510 &geotransformation);
511 if (nb_item < 0)
512 ARCANE_FATAL("Impossible de lire le nombre d'éléments pour le géotype={0} nom={1} ret={2}",
513 geotype, geotype_name.data(), nb_item);
514 info() << "MED: type=" << geotype << " '" << geotype_name.data() << "' nb_item=" << nb_item;
515 m_med_geotypes_in_mesh.add(geotype);
516 }
517}
518
519/*---------------------------------------------------------------------------*/
520/*---------------------------------------------------------------------------*/
521
522void MEDMeshReader::
523_readAndCreateCells(IPrimaryMesh* mesh, Int32 mesh_dimension, med_idt fid, const char* meshname)
524{
525 _clearItemsInGroups();
526
527 // A priori il n'y a pas de uniqueId() pour les entités dans MED (TODO: à vérifier)
528 // Donc on numérote les mailles en commencant par zéro et on incrémente à chaque
529 // maille créée.
530 Int64 cell_unique_id = 0;
531
532 UniqueArray<Int16> polygon_nb_nodes;
533 UniqueArray<med_int> med_connectivity;
534 UniqueArray<med_int> med_family_values;
535
536 ItemTypeMng* itm = mesh->itemTypeMng();
537 // Alloue les mailles types par type.
538 // Parcours les types disponibles et traite ceux qui correspondent à la dimension
539 // du maillage.
540 for (med_int geotype : m_med_geotypes_in_mesh) {
541 Int32 index_in_list = m_med_geotype_to_arcane_type_index[geotype];
542 const MEDToArcaneItemInfo& iinfo = m_med_to_arcane_types[index_in_list];
543
544 Int32 item_dimension = iinfo.dimension();
545 // On ne traite que les entités de la dimension du maillage.
546 if (item_dimension != mesh_dimension)
547 continue;
548 Int32 nb_item = _readItems(fid, meshname, iinfo, polygon_nb_nodes, med_connectivity, med_family_values);
549 if (nb_item == 0)
550 continue;
551 Int16 arcane_type = iinfo.arcaneType();
552 Int32 nb_item_node = iinfo.nbNode();
553 Int32 nb_family_values = med_family_values.size();
554 if (arcane_type == IT_NullType) {
555 // Indique un type pris en charge par MED mais pas par Arcane
556 ARCANE_FATAL("Le type MED '{0}' n'est pas pris en charge par Arcane", iinfo.medType());
557 }
558 Int64 cells_infos_index = 0;
559 Int64 med_connectivity_index = 0;
560 const bool is_polygon = (iinfo.medType() == MED_POLYGON);
561
562 UniqueArray<Int64> cells_infos;
563 if (is_polygon)
564 cells_infos.resize(2 * nb_item + med_connectivity.size());
565 else
566 cells_infos.resize((2 + nb_item_node) * nb_item);
567
568 info() << "CELL_INFOS size=" << cells_infos.size() << " nb_item=" << nb_item
569 << " type=" << arcane_type;
570
571 const Int32* indirection = iinfo.indirection();
572 for (Int32 i = 0; i < nb_item; ++i) {
573 Int64 current_cell_unique_id = cell_unique_id;
574 ++cell_unique_id;
575 if (is_polygon) {
576 nb_item_node = polygon_nb_nodes[i];
577 arcane_type = itm->getPolygonType(static_cast<Int16>(nb_item_node));
578 cells_infos[cells_infos_index] = arcane_type;
579 ++cells_infos_index;
580 cells_infos[cells_infos_index] = current_cell_unique_id;
581 ++cells_infos_index;
582 Span<Int64> cinfo_span(cells_infos.span().subspan(cells_infos_index, nb_item_node));
583 Span<med_int> med_cinfo_span(med_connectivity.span().subspan(med_connectivity_index, nb_item_node));
584 for (Integer k = 0; k < nb_item_node; ++k) {
585 cinfo_span[k] = med_cinfo_span[k];
586 }
587 }
588 else {
589 cells_infos[cells_infos_index] = arcane_type;
590 ++cells_infos_index;
591
592 cells_infos[cells_infos_index] = current_cell_unique_id;
593 ++cells_infos_index;
594 Span<Int64> cinfo_span(cells_infos.span().subspan(cells_infos_index, nb_item_node));
595 Span<med_int> med_cinfo_span(med_connectivity.span().subspan(med_connectivity_index, nb_item_node));
596 if (indirection) {
597 for (Integer k = 0; k < nb_item_node; ++k) {
598 cinfo_span[k] = med_cinfo_span[indirection[k]];
599 }
600 }
601 else {
602 for (Integer k = 0; k < nb_item_node; ++k)
603 cinfo_span[k] = med_cinfo_span[k];
604 }
605 }
606 if (i < nb_family_values) {
607 // Il y a une famille associée à l'entité
608 med_int f = med_family_values[i];
609 auto x = m_med_families_map.find(f);
610 if (x == m_med_families_map.end()) {
611 ARCANE_FATAL("Impossible de trouver l'ID de famille '{0}' pour la maille '{1}' de géotype '{2}'",
612 f, i, iinfo.medType());
613 }
614 m_med_groups[x->second.m_index].m_unique_ids.add(current_cell_unique_id);
615 }
616
617 med_connectivity_index += nb_item_node;
618 cells_infos_index += nb_item_node;
619 }
620 mesh->allocateCells(nb_item, cells_infos, false);
621 }
622}
623
624/*---------------------------------------------------------------------------*/
625/*---------------------------------------------------------------------------*/
626/*!
627 * \brief Lit les faces.
628 *
629 * Il n'y a pas besoin de créer explicitement les faces car cela est fait
630 * automatiquement dans Arcane. On se sert donc des faces de MED uniquement
631 * pour ajouter les faces dans les groupes correspondants dans le fichier
632 * de maillage.
633 */
634void MEDMeshReader::
635_readFaces(IPrimaryMesh* mesh, Int32 mesh_dimension, med_idt fid, const char* meshname)
636{
637 _clearItemsInGroups();
638 ItemTypeMng* itm = mesh->itemTypeMng();
639 NodesOfItemReorderer nodes_reorderer(itm);
640
641 IItemFamily* node_family = mesh->nodeFamily();
642 NodeInfoListView mesh_nodes(node_family);
643
644 UniqueArray<Int16> polygon_nb_nodes;
645 UniqueArray<med_int> med_connectivity;
646 UniqueArray<med_int> med_family_values;
647 // Parcours les types disponibles et traite ceux qui correspondent à la dimension
648 // du maillage moins 1.
649 for (med_int geotype : m_med_geotypes_in_mesh) {
650 Int32 index_in_list = m_med_geotype_to_arcane_type_index[geotype];
651 const MEDToArcaneItemInfo& iinfo = m_med_to_arcane_types[index_in_list];
652
653 Int32 item_dimension = iinfo.dimension();
654 // On ne traite que les entités de la dimension du maillage.
655 if (item_dimension != (mesh_dimension - 1))
656 continue;
657 ItemTypeInfo* iti = itm->typeFromId(iinfo.arcaneType());
658 info() << "Lecture des faces géotype=" << geotype << " arcane_type=" << iinfo.arcaneType()
659 << " " << iti->typeName();
660
661 Int32 nb_item = _readItems(fid, meshname, iinfo, polygon_nb_nodes, med_connectivity, med_family_values);
662 if (nb_item == 0)
663 continue;
664 ItemTypeId arcane_type(iinfo.arcaneType());
665 Int32 nb_item_node = iinfo.nbNode();
666 Int32 nb_family_values = med_family_values.size();
667 if (arcane_type == IT_NullType) {
668 // Indique un type pris en charge par MED mais pas par Arcane
669 ARCANE_FATAL("Le type MED '{0}' n'est pas pris en charge par Arcane", iinfo.medType());
670 }
671
672 SmallArray<Int64> orig_nodes_id(nb_item_node);
673 info() << "FACES_INFOS nb_item=" << nb_item << " type=" << arcane_type
674 << " nb_family_values=" << nb_family_values;
675
676 const Int32* indirection = iinfo.indirection();
677 Int64 med_connectivity_index = 0;
678
679 for (Int32 i = 0; i < nb_item; ++i) {
680 ArrayView<Int64> cinfo_span(orig_nodes_id);
681 Span<med_int> med_cinfo_span(med_connectivity.span().subspan(med_connectivity_index, nb_item_node));
682 if (indirection) {
683 for (Integer k = 0; k < nb_item_node; ++k) {
684 cinfo_span[k] = med_cinfo_span[indirection[k]];
685 }
686 }
687 else {
688 for (Integer k = 0; k < nb_item_node; ++k)
689 cinfo_span[k] = med_cinfo_span[k];
690 }
691 med_connectivity_index += nb_item_node;
692 // Recherche la face dans le maillage à partir des uniqueId() triés de ses noeuds
693 nodes_reorderer.reorder(arcane_type, cinfo_span);
694 ConstArrayView<Int64> ordered_nodes = nodes_reorderer.sortedNodes();
695 //info() << "OrigMedNodes=" << med_cinfo_span;
696 //info() << "OrigNodes=" << orig_nodes_id;
697 //info() << "Nodes=" << ordered_nodes;
698 Node first_node(MeshUtils::findOneItem(node_family, ordered_nodes[0]));
699 if (first_node.null())
700 ARCANE_FATAL("Impossible de trouver le nœud uid={0} pour l'indice de face '{1}'", ordered_nodes[0], i);
701 Face face = MeshUtils::getFaceFromNodesUniqueId(first_node, ordered_nodes);
702 if (face.null()) {
703 info() << "ERREUR: Impossible de trouver la face dans le maillage i=" << i << " nœuds=" << ordered_nodes;
704 info() << "Liste des faces pour le nœud=" << ItemPrinter(first_node);
705 for (Face subface : first_node.faces()) {
706 info() << "Face=" << ItemPrinter(subface);
707 for (Node subnode : subface.nodes()) {
708 info() << " Nœud=" << ItemPrinter(subnode);
709 }
710 }
711 ARCANE_FATAL("Impossible de trouver la face avec les nœuds=", ordered_nodes);
712 }
713 //info() << "Face=" << ItemPrinter(face);
714
715 // Ajoute la face dans les groupes correspondants
716 if (i < nb_family_values) {
717 // Il y a une famille associée à l'entité
718 med_int f = med_family_values[i];
719 auto x = m_med_families_map.find(f);
720 if (x == m_med_families_map.end()) {
721 ARCANE_FATAL("Impossible de trouver l'ID de famille '{0}' pour la face '{1}' de géotype '{2}'",
722 f, i, iinfo.medType());
723 }
724 //info() << "Ajout de la face au groupe_index=" << x->second.m_index;
725 m_med_groups[x->second.m_index].m_local_ids.add(face.localId());
726 }
727 }
728 info() << "FIN_LECTURE_DES_ENTITES";
729 }
730}
731
732/*---------------------------------------------------------------------------*/
733/*---------------------------------------------------------------------------*/
734
735IMeshReader::eReturnType MEDMeshReader::
736_readNodesCoordinates(IPrimaryMesh* mesh, Int64 nb_node, Int32 spacedim,
737 med_idt fid, const char* meshname)
738{
739 const bool do_verbose = false;
740 // Lit les coordonnées des noeuds et positionne les coordonnées dans Arcane
741
742 // La connectivité dans MED commence à 1 et Arcane à 0.
743 // Le premier noeud a donc un pour uniqueId() la valeur
744 UniqueArray<Real3> nodes_coordinates(nb_node + 1);
745 {
746 UniqueArray<med_float> coordinates(nb_node * spacedim);
747 int err = MEDmeshNodeCoordinateRd(fid, meshname, MED_NO_DT, MED_NO_IT, MED_FULL_INTERLACE,
748 coordinates.data());
749 if (err < 0) {
750 error() << "Impossible de lire les coordonnées des nœuds err=" << err;
752 }
753
754 if (spacedim == 3) {
755 for (Int64 i = 0; i < nb_node; ++i) {
756 Real3 xyz(coordinates[i * 3], coordinates[(i * 3) + 1], coordinates[(i * 3) + 2]);
757 if (do_verbose)
758 info() << "I=" << i << " XYZ=" << xyz;
759 nodes_coordinates[i + 1] = xyz;
760 }
761 }
762 else if (spacedim == 2) {
763 for (Int64 i = 0; i < nb_node; ++i) {
764 Real3 xyz(coordinates[i * 2], coordinates[(i * 2) + 1], 0.0);
765 if (do_verbose)
766 info() << "I=" << i << " XYZ=" << xyz;
767 nodes_coordinates[i + 1] = xyz;
768 }
769 }
770 else
771 ARCANE_THROW(NotImplementedException, "spacedim!=2 && spacedim!=3");
772 }
773
774 // Positionne les coordonnées
775 {
776 VariableNodeReal3& nodes_coord_var(mesh->nodesCoordinates());
777 ENUMERATE_NODE (inode, mesh->allNodes()) {
778 Node node = *inode;
779 nodes_coord_var[inode] = nodes_coordinates[node.uniqueId()];
780 }
781 }
782 return IMeshReader::RTOk;
783}
784
785/*---------------------------------------------------------------------------*/
786/*---------------------------------------------------------------------------*/
787/*!
788 * \brief Lit les informations des entités d'un type donné.
789 *
790 * Lit les informations des entités dont le type est donné par \a iinfo.
791 * Les entités sont des mailles au sens MED, donc des Edge, Face ou Cell.
792 * En retour, indique le nombre d'entités lues.
793 * \a connectivity contiendra les connectivités pour les entités lues et
794 * \a family_values le tableau pour chaque entité de la famille à laquelle elle
795 * appartient. À noter qu'il est possible que \a family_values soit vide s'il n'y
796 * a pas de famille associée aux entités.
797 *
798 * Si le type est MED_POLYGON, alors \a polygon_nb_nodes contiendra le nombre
799 * de noeuds de chaque polygone.
800 */
801Int32 MEDMeshReader::
802_readItems(med_idt fid, const char* meshname, const MEDToArcaneItemInfo& iinfo,
803 Array<Int16>& polygon_nb_nodes, Array<med_int>& connectivity,
804 Array<med_int>& family_values)
805{
806 constexpr bool is_verbose = false;
807
808 connectivity.clear();
809 family_values.clear();
810
811 int med_item_type = iinfo.medType();
812 med_bool coordinatechangement = {};
813 med_bool geotransformation = {};
814 med_int nb_med_item = 0;
815 if (iinfo.medType() == MED_POLYGON) {
816 // Pour les polygones, il faut un appel spécifique pour le nombre d'index.
817 // Ce nombre correspond au nombre d'entités plus un.
818 med_int nb_index = ::MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, med_item_type,
819 MED_INDEX_NODE, MED_NODAL, &coordinatechangement,
820 &geotransformation);
821 if (nb_index < 0)
822 ARCANE_FATAL("Impossible de lire le med_item_type MED '{0}' erreur={1}", med_item_type, nb_index);
823
824 info() << "MED: Lecture des entités";
825 info() << "MED: type=" << med_item_type << " nb_index=" << nb_index;
826 if (nb_index < 1)
827 return 0;
828 nb_med_item = nb_index - 1;
829 polygon_nb_nodes.resize(nb_med_item);
830 // Combien de nœuds pour la connectivité du polygone ?
831 med_int nb_connectivity = MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT,
832 MED_CELL, MED_POLYGON, MED_CONNECTIVITY, MED_NODAL,
833 &coordinatechangement, &geotransformation);
834 if (nb_connectivity < 0)
835 ARCANE_FATAL("Impossible d'obtenir la taille de connectivité pour MED_POLYGON err={0}", nb_connectivity);
836
837 // La table \a indexes contient pour chaque maille l'indice de son premier
838 // noeud dans la connectivité. Le nombre de noeuds de la i-ème entité
839 // est donc égal à (indexes[i+1]-indexes[i]).
840 UniqueArray<med_int> indexes(nb_index);
841 connectivity.resize(nb_connectivity);
842 info() << "Lecture des polygones nb_connectivity=" << nb_connectivity;
843 int r = MEDmeshPolygonRd(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, MED_NODAL,
844 indexes.data(), connectivity.data());
845 if (r < 0)
846 ARCANE_FATAL("Impossible de lire la connectivité pour MED_POLYGON err={0}", r);
847 info() << "INDEXES=" << indexes;
848 for (Int32 i = 0; i < nb_med_item; ++i)
849 polygon_nb_nodes[i] = static_cast<Int16>(indexes[i + 1] - indexes[i]);
850 }
851 else {
852 nb_med_item = ::MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL, med_item_type,
853 MED_CONNECTIVITY, MED_NODAL, &coordinatechangement,
854 &geotransformation);
855 if (nb_med_item < 0)
856 ARCANE_FATAL("Impossible de lire le med_item_type MED '{0}' erreur={1}", med_item_type, nb_med_item);
857
858 info() << "MED: Lecture des entités";
859 info() << "MED: type=" << med_item_type << " nb_item=" << nb_med_item;
860 if (nb_med_item == 0)
861 return 0;
862
863 Int64 nb_node = iinfo.nbNode();
864 if (nb_node == 0)
865 // Indique un élément que nous ne savons pas comment traiter.
866 ARCANE_THROW(NotImplementedException, "Lecture des entités avec le type MED '{0}'", med_item_type);
867
868 connectivity.resize(nb_node * nb_med_item);
869 int err = MEDmeshElementConnectivityRd(fid, meshname, MED_NO_DT, MED_NO_IT, MED_CELL,
870 med_item_type, MED_NODAL, MED_FULL_INTERLACE,
871 connectivity.data());
872 if (err < 0)
873 ARCANE_FATAL("Impossible de lire la connectivité MED med_item_type '{0}' erreur={1}",
874 med_item_type, err);
875 }
876 if (is_verbose)
877 info() << "CON: " << connectivity;
878 {
879 med_int nb_med_family = MEDmeshnEntity(fid, meshname, MED_NO_DT, MED_NO_IT,
880 MED_CELL, med_item_type, MED_FAMILY_NUMBER, MED_NODAL,
881 &coordinatechangement, &geotransformation);
882 info() << "nb_family=" << nb_med_family;
883 if (nb_med_family < 0)
884 ARCANE_FATAL("Impossible de lire la taille de la famille pour le type med_item_type={0} erreur={1}", med_item_type, nb_med_family);
885 if (nb_med_family > 0) {
886 family_values.resize(nb_med_family);
887 int r = MEDmeshEntityFamilyNumberRd(fid, meshname, MED_NO_DT, MED_NO_IT,
888 MED_CELL, med_item_type, family_values.data());
889 if (r < 0)
890 ARCANE_FATAL("Impossible de lire les valeurs de famille pour le type med_item_type={0} erreur={1}", med_item_type, nb_med_family);
891 if (is_verbose)
892 info() << "FAM: " << family_values;
893 }
894 }
895 return nb_med_item;
896}
897
898/*---------------------------------------------------------------------------*/
899/*---------------------------------------------------------------------------*/
900
901void MEDMeshReader::
902_readFamilies(med_idt fid, const char* meshname)
903{
904 FixedArray<char, MED_NAME_SIZE + 1> familyname;
905
906 info() << "Lecture des familles";
907
908 // Récupère le nombre de familles
909 med_int nb_family = MEDnFamily(fid, meshname);
910 if (nb_family < 0)
911 ARCANE_FATAL("Impossible de lire le nombre de familles (erreur={0})", nb_family);
912
913 info() << "MED: nb_family= " << nb_family;
914 for (med_int i = 0; i < nb_family; i++) {
915 info() << "MED: Lecture de la famille i=" << i;
916
917 med_int nb_group = MEDnFamilyGroup(fid, meshname, i + 1);
918 if (nb_group < 0)
919 ARCANE_FATAL("Impossible de lire le nombre de groupes pour l'indice de famille={0}", i);
920 info() << "MED: indice de famille=" << i << " nb_group=" << nb_group;
921
922 // Lit les groupes de la famille
923 // Même s'il n'y a pas de groupes associés à la famille on continue
924 // le traitement car les entités peuvent référencer des familles sans groupe.
925
926 // Dans MED, les groupes ont une taille fixe maximale MED_LNAME_SIZE
927 UniqueArray<char> all_group_names(MED_LNAME_SIZE * nb_group + 1);
928 med_int family_number = 0;
929 if (MEDfamilyInfo(fid, meshname, i + 1, familyname.data(), &family_number, all_group_names.data()) < 0)
930 ARCANE_FATAL("Impossible de lire les noms de groupes à partir de l'indice de famille={0}", i);
931
932 MEDFamilyInfo med_family(family_number);
933 Int32 group_index = m_med_groups.size();
934 med_family.m_index = group_index;
935 MEDGroupInfo med_group(group_index);
936
937 // Récupère les noms des groupes de la famille
938 for (Int32 z = 0; z < nb_group; ++z) {
939 //info() << " groupname=" << group_names << " number=" << familynumber;
940 SmallSpan<char> med_group_name = all_group_names.smallSpan().subSpan(MED_LNAME_SIZE * z, MED_LNAME_SIZE);
941 // Les groupes dans MED peuvent contenir des caractères non supportés par Arcane.
942 // On les enlève.
943 SmallArray<Byte, MED_LNAME_SIZE + 1> valid_name;
944 Int32 pos = 0;
945 for (; pos < MED_LNAME_SIZE; ++pos) {
946 char c = med_group_name[pos];
947 if (c == '\0')
948 break;
949 if (c == ' ' || c == '_')
950 continue;
951 valid_name.add(static_cast<Byte>(c));
952 }
953 String name(valid_name.view());
954 med_group.m_names.add(name);
955 info() << "ID de famille=" << family_number << " groupe='" << name << "'";
956 }
957
958 m_med_families_map.insert(std::make_pair(family_number, med_family));
959 m_med_groups.add(med_group);
960 }
961}
962
963/*---------------------------------------------------------------------------*/
964/*---------------------------------------------------------------------------*/
965/*!
966 * \brief Broadcast les groupes de \a group_names pour la famille \a family.
967 *
968 * La liste des groupes \a group_names est seulement utilisée pour le rang 0.
969 */
970void MEDMeshReader::
971_broadcastGroups(ConstArrayView<String> group_names, IItemFamily* family)
972{
973 IParallelMng* pm = m_mesh->parallelMng();
974
975 Int32 rank = pm->commRank();
976 // S'assure que tous les rangs connaissent les groupes
977 if (rank == 0) {
978 Int32 nb_group = group_names.size();
979 pm->broadcast(ArrayView<Int32>(1, &nb_group), 0);
980 for (String name : group_names)
981 pm->broadcastString(name, 0);
982 }
983 else {
984 Int32 nb_group = 0;
985 pm->broadcast(ArrayView<Int32>(1, &nb_group), 0);
986 String current_group_name;
987 for (Int32 i = 0; i < nb_group; ++i) {
988 pm->broadcastString(current_group_name, 0);
989 CellGroup cell_group = family->findGroup(current_group_name, true);
990 }
991 }
992}
993
994/*---------------------------------------------------------------------------*/
995/*---------------------------------------------------------------------------*/
996
997/*---------------------------------------------------------------------------*/
998/*---------------------------------------------------------------------------*/
999/*!
1000 * \brief Service de lecture d'un maillage au format MED.
1001 */
1002class MEDMeshReaderService
1003: public BasicService
1004, public IMeshReader
1005{
1006 public:
1007
1008 explicit MEDMeshReaderService(const ServiceBuildInfo& sbi)
1009 : BasicService(sbi)
1010 {}
1011
1012 public:
1013
1014 void build() override {}
1015 bool allowExtension(const String& str) override
1016 {
1017 return str == "med";
1018 }
1020 [[maybe_unused]] const XmlNode& mesh_element,
1021 const String& file_name,
1022 const String& dir_name,
1023 [[maybe_unused]] bool use_internal_partition) override
1024 {
1025 ARCANE_UNUSED(dir_name);
1026 MEDMeshReader reader(traceMng());
1027 return reader.readMesh(mesh, file_name);
1028 }
1029};
1030
1031/*---------------------------------------------------------------------------*/
1032/*---------------------------------------------------------------------------*/
1033
1034ARCANE_REGISTER_SERVICE(MEDMeshReaderService,
1035 ServiceProperty("MEDMeshReader", ST_SubDomain),
1036 ARCANE_SERVICE_INTERFACE(IMeshReader));
1037
1038/*---------------------------------------------------------------------------*/
1039/*---------------------------------------------------------------------------*/
1040
1041/*---------------------------------------------------------------------------*/
1042/*---------------------------------------------------------------------------*/
1043/*!
1044 * \brief Service de lecture d'un maillage au format MED depuis le jeu de données.
1045 */
1046class MEDCaseMeshReader
1047: public AbstractService
1048, public ICaseMeshReader
1049{
1050 public:
1051
1052 class Builder
1053 : public IMeshBuilder
1054 {
1055 public:
1056
1057 explicit Builder(ITraceMng* tm, const CaseMeshReaderReadInfo& read_info)
1058 : m_trace_mng(tm)
1059 , m_read_info(read_info)
1060 {}
1061
1062 public:
1063
1064 void fillMeshBuildInfo(MeshBuildInfo& build_info) override
1065 {
1066 ARCANE_UNUSED(build_info);
1067 }
1069 {
1070 MEDMeshReader reader(m_trace_mng);
1071 String fname = m_read_info.fileName();
1072 m_trace_mng->info() << "Lecteur MED (ICaseMeshReader) file_name=" << fname;
1073 IMeshReader::eReturnType ret = reader.readMesh(pm, fname);
1074 if (ret != IMeshReader::RTOk)
1075 ARCANE_FATAL("Impossible de lire le fichier MED");
1076 }
1077
1078 private:
1079
1080 ITraceMng* m_trace_mng;
1081 CaseMeshReaderReadInfo m_read_info;
1082 };
1083
1084 public:
1085
1086 explicit MEDCaseMeshReader(const ServiceBuildInfo& sbi)
1087 : AbstractService(sbi)
1088 {}
1089
1090 public:
1091
1093 {
1094 IMeshBuilder* builder = nullptr;
1095 if (read_info.format() == "med")
1096 builder = new Builder(traceMng(), read_info);
1097 return makeRef(builder);
1098 }
1099};
1100
1101/*---------------------------------------------------------------------------*/
1102/*---------------------------------------------------------------------------*/
1103
1104ARCANE_REGISTER_SERVICE(MEDCaseMeshReader,
1105 ServiceProperty("MEDCaseMeshReader", ST_SubDomain),
1106 ARCANE_SERVICE_INTERFACE(ICaseMeshReader));
1107
1108/*---------------------------------------------------------------------------*/
1109/*---------------------------------------------------------------------------*/
1110
1111} // namespace Arcane
1112
1113/*---------------------------------------------------------------------------*/
1114/*---------------------------------------------------------------------------*/
#define ARCANE_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ENUMERATE_NODE(name, group)
Enumérateur générique d'un groupe de noeuds.
Fonctions utilitaires sur le maillage.
Ce fichier contient les différentes fabriques de services et macro pour enregistrer les services.
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro pour déclarer une interface lors de l'enregistrement d'un service.
Classe de base d'un service.
AbstractService(const ServiceBuildInfo &)
Constructeur à partir d'un ServiceBuildInfo.
Classe de base des vecteurs 1D de données.
Informations nécessaires pour la lecture d'un fichier de maillage.
Vue constante d'un tableau de type T.
static std::optional< Int32 > tryParseFromEnvironment(StringView s, bool throw_if_invalid)
Interface du service de lecture du maillage à partir du jeu de données.
Interface d'une famille d'entités.
Definition IItemFamily.h:84
Interface d'un service de création/lecture du maillage.
Interface du service gérant la lecture d'un maillage.
Definition IMeshReader.h:32
eReturnType
Types des codes de retour d'une lecture ou écriture.
Definition IMeshReader.h:37
@ RTError
Erreur lors de l'opération.
Definition IMeshReader.h:39
@ RTOk
Opération effectuée avec succès.
Definition IMeshReader.h:38
Interface du gestionnaire de traces.
void addItems(Int32ConstArrayView items_local_id, bool check_if_present=true)
Ajoute des entités.
Definition ItemGroup.cc:446
Type d'une entité (Item).
Definition ItemTypeId.h:32
void allocateMeshItems(IPrimaryMesh *pm) override
Alloue les entités du maillage géré par ce service.
void fillMeshBuildInfo(MeshBuildInfo &build_info) override
Remplit build_info avec les informations nécessaires pour créer le maillage.
Service de lecture d'un maillage au format MED depuis le jeu de données.
Ref< IMeshBuilder > createBuilder(const CaseMeshReaderReadInfo &read_info) const override
Retourne un builder pour créer et lire le maillage dont les informations sont spécifiées dans read_in...
bool allowExtension(const String &str) override
Vérifie si le service supporte les fichiers avec l'extension str.
void build() override
Construction de niveau build du service.
eReturnType readMeshFromFile(IPrimaryMesh *mesh, const XmlNode &mesh_element, const String &file_name, const String &dir_name, bool use_internal_partition) override
Lit un maillage à partir d'un fichier.
Information sur une famille d'entité MED.
Int32 m_family_id
Id de la famille pour MED.
Int32 m_index
Index dans la liste des groupes Arcane.
Liste des groupes et des entités leur appartenant.
Int32 m_index
Index du groupe dans la liste des groupes.
UniqueArray< Int64 > m_unique_ids
Liste des uniqueId() des entités du groupe.
UniqueArray< String > m_names
Nom des groupes associés.
UniqueArray< Int32 > m_local_ids
Liste des localId() des entités du groupe.
Informations pour passer des types MED aux types Arcane pour les entités.
Lecteur de maillages au format MED.
Paramètres nécessaires à la construction d'un maillage.
Référence à une instance.
Structure contenant les informations pour créer un service.
Chaîne de caractères unicode.
TraceAccessor(ITraceMng *m)
Construit un accesseur via le gestionnaire de trace m.
TraceMessage info() const
Flot pour un message d'information.
TraceMessage error() const
Flot pour un message d'erreur.
ITraceMng * traceMng() const
Gestionnaire de trace.
Vecteur 1D de données avec sémantique par valeur (style STL).
Noeud d'un arbre DOM.
Definition XmlNode.h:51
ItemGroupT< Cell > CellGroup
Groupe de mailles.
Definition ItemTypes.h:183
ItemGroupT< Face > FaceGroup
Groupe de faces.
Definition ItemTypes.h:178
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro pour enregistrer un service.
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Grandeur au noeud de type coordonnées.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
@ ST_SubDomain
Le service s'utilise au niveau du sous-domaine.
std::int16_t Int16
Type entier signé sur 16 bits.
unsigned char Byte
Type d'un octet.
Definition BaseTypes.h:42
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Créé une référence sur un pointeur.
std::int32_t Int32
Type entier signé sur 32 bits.