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