Arcane  4.2.3.0
Documentation développeur
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/*---------------------------------------------------------------------------*/
54class MEDMeshReader
55: public TraceAccessor
56{
57 public:
58
65 class MEDToArcaneItemInfo
66 {
67 public:
68
69 MEDToArcaneItemInfo(int dimension, int nb_node, med_int med_type,
70 ItemTypeId arcane_type, const Int32* indirection)
71 : m_dimension(dimension)
72 , m_nb_node(nb_node)
73 , m_med_type(med_type)
74 , m_arcane_type(arcane_type)
75 , m_indirection(indirection)
76 {}
77
78 public:
79
80 int dimension() const { return m_dimension; }
81 int nbNode() const { return m_nb_node; }
82 med_int medType() const { return m_med_type; }
83 Int16 arcaneType() const { return m_arcane_type; }
84 const Int32* indirection() const { return m_indirection; }
85
86 private:
87
88 int m_dimension = -1;
89 int m_nb_node = -1;
90 med_int m_med_type = {};
91 ItemTypeId m_arcane_type = ITI_NullType;
92 const Int32* m_indirection = nullptr;
93 };
94
96 class MEDFamilyInfo
97 {
98 public:
99
100 explicit MEDFamilyInfo(Int32 family_id)
101 : m_family_id(family_id)
102 {}
103
104 public:
105
110 };
111
120 class MEDGroupInfo
121 {
122 public:
123
124 explicit MEDGroupInfo(Int32 index)
125 : m_index(index)
126 {}
127
128 public:
129
138 };
139
140 public:
141
142 explicit MEDMeshReader(ITraceMng* tm)
143 : TraceAccessor(tm)
144 {
145 _initMEDToArcaneTypes();
146 }
147
148 public:
149
150 [[nodiscard]] IMeshReader::eReturnType
151 readMesh(IPrimaryMesh* mesh, const String& file_name);
152
153 private:
154
155 IMeshReader::eReturnType _readMesh(IPrimaryMesh* mesh, const String& filename);
156
157 private:
158
159 // Structure 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
179 std::unordered_map<med_int, Int32> m_med_geotype_to_arcane_type_index;
181 std::unordered_map<Int32, MEDFamilyInfo> m_med_families_map;
186
187 private:
188
189 Int32 _readItems(IPrimaryMesh* mesh, med_idt fid, const char* meshnane, const MEDToArcaneItemInfo& iinfo,
190 Array<Int16>& poly_nb_nodes, Array<Int16>& poly_types, Array<med_int>& connectivity, Array<med_int>& family_values);
191 void _initMEDToArcaneTypes();
192 void _addTypeInfo(int dimension, int nb_node, med_int med_type, ItemTypeId arcane_type)
193 {
194 _addTypeInfo(dimension, nb_node, med_type, arcane_type, nullptr);
195 }
196 void _addTypeInfo(int dimension, int nb_node, med_int med_type, ItemTypeId arcane_type,
197 const Int32* indirection)
198 {
199 MEDToArcaneItemInfo t(dimension, nb_node, med_type, arcane_type, indirection);
200 Int32 index = m_med_to_arcane_types.size();
202 m_med_geotype_to_arcane_type_index.insert(std::make_pair(med_type, index));
203 }
204 void _readAndCreateCells(IPrimaryMesh* mesh, Int32 mesh_dimension, med_idt fid, const char* meshname);
205 void _readFaces(IPrimaryMesh* mesh, Int32 mesh_dimension, med_idt fid, const char* meshname);
206
207 [[nodiscard]] IMeshReader::eReturnType
208 _readNodesCoordinates(IPrimaryMesh* mesh, Int64 nb_node, Int32 spacedim,
209 med_idt fid, const char* meshname);
210 void _readFamilies(med_idt fid, const char* meshname);
211 void _readAvailableTypes(med_idt fid, const char* meshname);
212 void _clearItemsInGroups()
213 {
214 for (MEDGroupInfo& g : m_med_groups) {
215 g.m_unique_ids.clear();
216 g.m_local_ids.clear();
217 }
218 }
219 void _broadcastGroups(ConstArrayView<String> names, IItemFamily* family);
220 med_int _readPolyhedrons(IPrimaryMesh* mesh, med_idt fid, const char* meshname,
221 Array<Int16>& poly_nb_nodes,
222 Array<Int16>& poly_types_id,
223 Array<med_int>& connectivity);
224};
225
226/*---------------------------------------------------------------------------*/
227/*---------------------------------------------------------------------------*/
228
229namespace
230{
231 // 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/*---------------------------------------------------------------------------*/
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;
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/*---------------------------------------------------------------------------*/
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/*---------------------------------------------------------------------------*/
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/*---------------------------------------------------------------------------*/
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/*---------------------------------------------------------------------------*/
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/*---------------------------------------------------------------------------*/
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.
Face getFaceFromNodesUniqueId(Node node, Int64ConstArrayView face_nodes_unique_id)
Recherche une entité face à partir des numéros uniques de ces noeuds.
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.
Integer size() const
Nombre d'éléments du vecteur.
Classe de base d'un service.
AbstractService(const ServiceBuildInfo &)
Constructeur à partir d'un ServiceBuildInfo.
Vue modifiable d'un tableau d'un type T.
Tableau d'items de types quelconques.
void clear()
Supprime les éléments du tableau.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
void reserve(Int64 new_capacity)
Réserve le mémoire pour new_capacity éléments.
const T * data() const
Accès à la racine du tableau hors toute protection.
Span< const T > span() const
Vue immutable sur ce tableau.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
Informations nécessaires pour la lecture d'un fichier de maillage.
Vue constante d'un tableau de type T.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
static std::optional< Int32 > tryParseFromEnvironment(StringView s, bool throw_if_invalid)
Face d'une maille.
Definition Item.h:964
Interface du service de lecture du maillage à partir du jeu de données.
Interface d'une famille d'entités.
Definition IItemFamily.h:86
virtual ItemGroup findGroup(const String &name) const =0
Recherche un groupe.
virtual NodeGroup allNodes()=0
Groupe de tous les noeuds.
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 parallélisme pour un sous-domaine.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual VariableNodeReal3 & nodesCoordinates()=0
Coordonnées des noeuds.
virtual void allocateCells(Integer nb_cell, Int64ConstArrayView cells_infos, bool one_alloc=true)=0
Allocation d'un maillage.
Interface du gestionnaire de traces.
void addItems(Int32ConstArrayView items_local_id, bool check_if_present=true)
Ajoute des entités.
Definition ItemGroup.cc:446
Classe utilitaire pour imprimer les infos sur une entité.
Definition ItemPrinter.h:34
Type d'une entité (Item).
Definition ItemTypeId.h:32
Infos sur un type d'entité du maillage.
String typeName() const
Nom du type.
Gestionnaire des types d'entités d'un maillage.
Definition ItemTypeMng.h:64
ItemTypeId getPolygonType(Int16 nb_node) const
Retourne le type pour un polygone ayant nb_node.
ItemTypeInfo * typeFromId(Integer id) const
Type correspondant au numéro id.
constexpr Int32 localId() const
Identifiant local de l'entité dans le sous-domaine du processeur.
Definition Item.h:219
constexpr bool null() const
true si l'entité est nul (i.e. non connecté au maillage)
Definition Item.h:216
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.
void _broadcastGroups(ConstArrayView< String > names, IItemFamily *family)
Broadcast les groupes de group_names pour la famille family.
UniqueArray< MEDToArcaneItemInfo > m_med_to_arcane_types
Tableau de conversion entre les types MED et Arcane.
void _readAvailableTypes(med_idt fid, const char *meshname)
Récupère la liste des types géométriques présents dans le maillage.
IPrimaryMesh * m_mesh
Maillage en cours de lecture.
UniqueArray< MEDGroupInfo > m_med_groups
Liste des informations sur les groupes.
std::unordered_map< Int32, MEDFamilyInfo > m_med_families_map
Liste des familles.
std::unordered_map< med_int, Int32 > m_med_geotype_to_arcane_type_index
Table des index dans m_med_to_arcane_type de chaque geotype.
UniqueArray< med_int > m_med_geotypes_in_mesh
Liste des 'geotype' présents dans le maillage.
Int32 _readItems(IPrimaryMesh *mesh, med_idt fid, const char *meshnane, const MEDToArcaneItemInfo &iinfo, Array< Int16 > &poly_nb_nodes, Array< Int16 > &poly_types, Array< med_int > &connectivity, Array< med_int > &family_values)
Lit les informations des entités d'un type donné.
void _readFaces(IPrimaryMesh *mesh, Int32 mesh_dimension, med_idt fid, const char *meshname)
Lit les faces.
Paramètres nécessaires à la construction d'un maillage.
Vue sur les informations des noeuds.
Noeud d'un maillage.
Definition Item.h:582
FaceConnectedListViewType faces() const
Liste des faces du noeud.
Definition Item.h:689
Classe utilitaire pour réordonner les noeuds d'une entité.
Exception lorsqu'une fonction n'est pas implémentée.
Référence à une instance.
Structure contenant les informations pour créer un service.
Tableau 1D de données avec buffer pré-alloué sur la pile.
Vue d'un tableau d'éléments de type T.
Definition Span.h:633
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.