Arcane  v3.14.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
MshParallelMeshReader.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2024 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/* MshParallelMeshReader.cc (C) 2000-2024 */
9/* */
10/* Lecture parallèle d'un fichier au format MSH. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/TraceAccessor.h"
15#include "arcane/utils/Array.h"
16#include "arcane/utils/IOException.h"
17#include "arcane/utils/FatalErrorException.h"
18#include "arcane/utils/Ref.h"
19#include "arcane/utils/NotSupportedException.h"
20#include "arcane/utils/Real3.h"
21#include "arcane/utils/OStringStream.h"
22#include "arcane/utils/FixedArray.h"
23#include "arcane/utils/PlatformUtils.h"
24#include "arcane/utils/CheckedConvert.h"
25
26#include "arcane/core/IMeshReader.h"
27#include "arcane/core/IPrimaryMesh.h"
28#include "arcane/core/IItemFamily.h"
29#include "arcane/core/ItemGroup.h"
30#include "arcane/core/VariableTypes.h"
31#include "arcane/core/IParallelMng.h"
33
34// Element types in .msh file format, found in gmsh-2.0.4/Common/GmshDefines.h
35#include "arcane/std/internal/IosFile.h"
36#include "arcane/std/internal/IosGmsh.h"
37
38/*---------------------------------------------------------------------------*/
39/*---------------------------------------------------------------------------*/
40
41/*
42 * NOTES:
43 * - La bibliothèque `gmsh` fournit un script 'open.py' dans le répertoire
44 * 'demos/api' qui permet de générer un fichier '.msh' à partir d'un '.geo'.
45 * - Il est aussi possible d'utiliser directement l'exécutable 'gmsh' avec
46 * l'option '-save-all' pour sauver un fichier '.msh' à partir d'un '.geo'
47 *
48 * TODO:
49 * - supporter les partitions
50 * - pouvoir utiliser la bibliothèque 'gmsh' directement.
51 */
52
53/*---------------------------------------------------------------------------*/
54/*---------------------------------------------------------------------------*/
55
56namespace Arcane
57{
58
59/*---------------------------------------------------------------------------*/
60/*---------------------------------------------------------------------------*/
76: public TraceAccessor
77, public IMshMeshReader
78{
79 public:
80
81 using eReturnType = typename IMeshReader::eReturnType;
82
93 {
94 Int32 index = 0;
95 Int64 nb_entity = 0;
96 Integer item_type = -1;
97 Int32 dimension = -1;
98 Int32 item_nb_node = 0;
99 Int64 entity_tag = -1;
100 UniqueArray<Int64> uids;
102 };
103
108 {
109 MeshPhysicalName(Int32 _dimension, Int64 _tag, const String& _name)
110 : dimension(_dimension)
111 , tag(_tag)
112 , name(_name)
113 {}
114 MeshPhysicalName() = default;
115 bool isNull() const { return dimension == (-1); }
116 Int32 dimension = -1;
117 Int64 tag = -1;
118 String name;
119 };
120
125 {
126 void add(Int32 dimension, Int64 tag, String name)
127 {
128 m_physical_names[dimension].add(MeshPhysicalName{ dimension, tag, name });
129 }
130 MeshPhysicalName find(Int32 dimension, Int64 tag) const
131 {
132 for (auto& x : m_physical_names[dimension])
133 if (x.tag == tag)
134 return x;
135 return {};
136 }
137
138 private:
139
141 };
142
145 {
146 MeshV4EntitiesNodes(Int64 _tag, Int64 _physical_tag)
147 : tag(_tag)
148 , physical_tag(_physical_tag)
149 {}
150 Int64 tag;
151 Int64 physical_tag;
152 };
153
156 {
157 MeshV4EntitiesWithNodes(Int32 _dim, Int64 _tag, Int64 _physical_tag)
158 : dimension(_dim)
159 , tag(_tag)
160 , physical_tag(_physical_tag)
161 {}
162 Int32 dimension;
163 Int64 tag;
164 Int64 physical_tag;
165 };
166
169 {
170 public:
171
172 void findEntities(Int32 dimension, Int64 tag,Array<MeshV4EntitiesWithNodes>& entities)
173 {
174 entities.clear();
175 for (auto& x : entities_with_nodes_list[dimension - 1])
176 if (x.tag == tag)
177 entities.add(x);
178 }
179
180 MeshV4EntitiesNodes* findNodeEntities(Int64 tag)
181 {
182 for (auto& x : entities_nodes_list)
183 if (x.tag == tag)
184 return &x;
185 return nullptr;
186 }
187
188 public:
189
190 UniqueArray<Int32> cells_nb_node;
191 UniqueArray<Int32> cells_type;
192 UniqueArray<Int64> cells_uid;
193 UniqueArray<Int64> cells_connectivity;
194
200 std::unordered_map<Int64, Int32> nodes_rank_map;
201 Real3 m_node_min_bounding_box;
202 Real3 m_node_max_bounding_box;
203 MeshPhysicalNameList physical_name_list;
204 UniqueArray<MeshV4EntitiesNodes> entities_nodes_list;
205 FixedArray<UniqueArray<MeshV4EntitiesWithNodes>,3> entities_with_nodes_list;
207 };
208
209 public:
210
213 {}
214
215 eReturnType readMeshFromMshFile(IMesh* mesh, const String& file_name) override;
216
217 private:
218
219 IMesh* m_mesh = nullptr;
220 IParallelMng* m_parallel_mng = nullptr;
221 Int32 m_master_io_rank = A_NULL_RANK;
222 bool m_is_parallel = false;
223 Ref<IosFile> m_ios_file; // nullptr sauf pour le rang maitre.
224 MeshInfo m_mesh_info;
226 Int32 m_nb_part = 4;
229
230 private:
231
233 void _readNodesOneEntity(Int32 entity_index);
235 void _readMeshFromFile();
237 void _allocateCells();
238 void _allocateGroups();
240 void _addFaceGroupOnePart(ConstArrayView<Int64> connectivities, Int32 item_nb_node,
241 const String& group_name, Int32 block_index);
243 void _addCellOrNodeGroupOnePart(ConstArrayView<Int64> uids, const String& group_name,
244 Int32 block_index, IItemFamily* family);
245 Int32 _switchMshType(Int64, Int32&) const;
246 void _readPhysicalNames();
247 void _readEntities();
248 void _readOneEntity(Int32 entity_dim);
250 Int32 _getIntegerAndBroadcast();
251 void _getInt64ArrayAndBroadcast(ArrayView<Int64> values);
254 void _computeOwnCells(MeshV4ElementsBlock& block);
255 Real3 _getReal3();
256 void _goToNextLine();
257};
258
259/*---------------------------------------------------------------------------*/
260/*---------------------------------------------------------------------------*/
261
262namespace
263{
270 inline std::pair<Int64, Int64>
271 _interval(Int32 index, Int32 nb_interval, Int64 size)
272 {
273 Int64 isize = size / nb_interval;
274 Int64 ibegin = index * isize;
275 // Pour le dernier interval, prend les elements restants
276 if ((index + 1) == nb_interval)
277 isize = size - ibegin;
278 return { ibegin, isize };
279 }
280} // namespace
281
282/*---------------------------------------------------------------------------*/
283/*---------------------------------------------------------------------------*/
289{
290 IosFile* f = m_ios_file.get();
291 String s;
292 if (f)
293 s = f->getNextLine();
294 if (m_is_parallel) {
295 if (f)
296 info() << "BroadcastNextLine: " << s;
297 m_parallel_mng->broadcastString(s, m_master_io_rank);
298 }
299 info() << "GetNextLine: " << s;
300 return s;
301}
302
303/*---------------------------------------------------------------------------*/
304/*---------------------------------------------------------------------------*/
305
306Int32 MshParallelMeshReader::
307_getIntegerAndBroadcast()
308{
309 IosFile* f = m_ios_file.get();
311 if (f)
312 v[0] = f->getInteger();
313 if (m_is_parallel) {
314 m_parallel_mng->broadcast(v.view(), m_master_io_rank);
315 }
316 return v[0];
317}
318
319/*---------------------------------------------------------------------------*/
320/*---------------------------------------------------------------------------*/
321
322void MshParallelMeshReader::
323_getInt64ArrayAndBroadcast(ArrayView<Int64> values)
324{
325 IosFile* f = m_ios_file.get();
326 if (f)
327 for (Int64& v : values)
328 v = f->getInt64();
329 if (m_is_parallel)
330 m_parallel_mng->broadcast(values, m_master_io_rank);
331}
332
333/*---------------------------------------------------------------------------*/
334/*---------------------------------------------------------------------------*/
335
336Real3 MshParallelMeshReader::
337_getReal3()
338{
339 IosFile* f = m_ios_file.get();
340 Real x = f->getReal();
341 Real y = f->getReal();
342 Real z = f->getReal();
343 return Real3(x,y,z);
344}
345
346/*---------------------------------------------------------------------------*/
347/*---------------------------------------------------------------------------*/
348
349void MshParallelMeshReader::
350_goToNextLine()
351{
352 if (m_ios_file.get())
353 m_ios_file->getNextLine();
354}
355
356/*---------------------------------------------------------------------------*/
357/*---------------------------------------------------------------------------*/
358
359Int32 MshParallelMeshReader::
360_switchMshType(Int64 mshElemType, Int32& nNodes) const
361{
362 switch (mshElemType) {
363 case IT_NullType: // used to decode IT_NullType: IT_HemiHexa7|IT_Line9
364 switch (nNodes) {
365 case 7:
366 return IT_HemiHexa7;
367 default:
368 info() << "Could not decode IT_NullType with nNodes=" << nNodes;
369 throw IOException("_switchMshType", "Could not decode IT_NullType with nNodes");
370 }
371 break;
372 case MSH_PNT:
373 nNodes = 1;
374 return IT_Vertex;
375 case MSH_LIN_2:
376 nNodes = 2;
377 return IT_Line2;
378 case MSH_TRI_3:
379 nNodes = 3;
380 return IT_Triangle3;
381 case MSH_QUA_4:
382 nNodes = 4;
383 return IT_Quad4;
384 case MSH_TET_4:
385 nNodes = 4;
386 return IT_Tetraedron4;
387 case MSH_HEX_8:
388 nNodes = 8;
389 return IT_Hexaedron8;
390 case MSH_PRI_6:
391 nNodes = 6;
392 return IT_Pentaedron6;
393 case MSH_PYR_5:
394 nNodes = 5;
395 return IT_Pyramid5;
396 case MSH_TRI_10:
397 nNodes = 10;
398 return IT_Heptaedron10;
399 case MSH_TRI_12:
400 nNodes = 12;
401 return IT_Octaedron12;
402
403 case MSH_TRI_6:
404 case MSH_QUA_9:
405 case MSH_HEX_27:
406 case MSH_PRI_18:
407 case MSH_PYR_14:
408 case MSH_QUA_8:
409 case MSH_HEX_20:
410 case MSH_PRI_15:
411 case MSH_PYR_13:
412 case MSH_TRI_9:
413 case MSH_TRI_15:
414 case MSH_TRI_15I:
415 case MSH_TRI_21:
416 default:
417 ARCANE_THROW(NotSupportedException, "Unknown GMSH element type '{0}'", mshElemType);
418 }
419 return IT_NullType;
420}
421
422/*---------------------------------------------------------------------------*/
423/*---------------------------------------------------------------------------*/
424
427{
428 // Détermine la bounding box de la maille
429 Real max_value = FloatInfo<Real>::maxValue();
430 Real min_value = -max_value;
431 Real3 min_box(max_value, max_value, max_value);
432 Real3 max_box(min_value, min_value, min_value);
433 const Int64 nb_node = m_mesh_info.nodes_coordinates.largeSize();
434 for (Real3 pos : m_mesh_info.nodes_coordinates) {
437 }
438 m_mesh_info.m_node_min_bounding_box = min_box;
439 m_mesh_info.m_node_max_bounding_box = max_box;
440
443
444 // Pour la partition, on ne prend en compte que la coordonnée X.
445 // On est sur qu'elle est valable pour toutes les dimensions du maillage.
446 // On partitionne avec des intervalles de même longueur.
447 // NOTE: Cela fonctionne bien si l'ensemble des noeuds est bien réparti.
448 // Si ce n'est pas le cas on pourrait utiliser une bisection en coupant
449 // à chaque fois sur la moyenne.
450 Real min_x = min_box.x;
451 Real max_x = max_box.x;
452 IParallelMng* pm = m_parallel_mng;
453 Real global_min_x = pm->reduce(Parallel::ReduceMin, min_x);
454 Real global_max_x = pm->reduce(Parallel::ReduceMax, max_x);
455 info() << "MIN_MAX_X=" << global_min_x << " " << global_max_x;
456
457 Real diff_v = (global_max_x - global_min_x) / static_cast<Real>(m_nb_part);
458 // Ne devrait pas arriver mais c'est nécessaire pour éviter d'éventuelles
459 // divisions par zéro.
461 for (Int64 i = 0; i < nb_node; ++i) {
462 Int32 part = static_cast<Int32>((m_mesh_info.nodes_coordinates[i].x - global_min_x) / diff_v);
463 part = std::clamp(part, 0, m_nb_part - 1);
464 nodes_part[i] = part;
465 }
466 }
468 // Construit la table de hashage des rangs
469 for (Int64 i = 0; i < nb_node; ++i) {
470 Int32 rank = m_parts_rank[nodes_part[i]];
471 Int64 uid = m_mesh_info.nodes_unique_id[i];
472 ++nb_node_per_rank[rank];
473 m_mesh_info.nodes_rank_map.insert(std::make_pair(uid, rank));
474 }
475 pm->reduce(Parallel::ReduceSum, nb_node_per_rank);
476 info() << "NB_NODE_PER_RANK=" << nb_node_per_rank;
477}
478
479/*---------------------------------------------------------------------------*/
480/*---------------------------------------------------------------------------*/
507{
509 _getInt64ArrayAndBroadcast(nodes_info.view());
510
511 Int64 nb_entity = nodes_info[0];
512 Int64 total_nb_node = nodes_info[1];
513 Int64 min_node_tag = nodes_info[2];
514 Int64 max_node_tag = nodes_info[3];
515
516 _goToNextLine();
517
518 if (total_nb_node < 0)
519 ARCANE_THROW(IOException, "Invalid number of nodes : '{0}'", total_nb_node);
520
521 info() << "[Nodes] nb_entity=" << nb_entity
522 << " total_nb_node=" << total_nb_node
523 << " min_tag=" << min_node_tag
524 << " max_tag=" << max_node_tag
525 << " read_nb_part=" << m_nb_part
526 << " nb_rank=" << m_parallel_mng->commSize();
527
528 for (Integer i_entity = 0; i_entity < nb_entity; ++i_entity) {
529 _readNodesOneEntity(i_entity);
530 }
531
533}
534
535/*---------------------------------------------------------------------------*/
536/*---------------------------------------------------------------------------*/
537
538void MshParallelMeshReader::
539_readNodesOneEntity(Int32 entity_index)
540{
541 IosFile* ios_file = m_ios_file.get();
542 IParallelMng* pm = m_parallel_mng;
543 const Int32 my_rank = pm->commRank();
544
546 UniqueArray<Real3> nodes_coordinates;
547
549 _getInt64ArrayAndBroadcast(entity_infos.view());
550
551 _goToNextLine();
552
553 // Dimension de l'entité (pas utile)
554 [[maybe_unused]] Int64 entity_dim = entity_infos[0];
555 // Tag de l'entité (pas utile)
556 [[maybe_unused]] Int64 entity_tag = entity_infos[1];
558 Int64 nb_node2 = entity_infos[3];
559
560 info() << "[Nodes] index=" << entity_index << " entity_dim=" << entity_dim << " entity_tag=" << entity_tag
561 << " parametric=" << parametric_coordinates
562 << " nb_node2=" << nb_node2;
563
564 if (parametric_coordinates != 0)
565 ARCANE_THROW(NotSupportedException, "Only 'parametric coordinates' value of '0' is supported (current={0})", parametric_coordinates);
566
567 // Il est possible que le nombre de noeuds soit 0.
568 // Dans ce cas, il faut directement passer à la ligne suivante
569 if (nb_node2 == 0)
570 return;
571
572 // Partitionne la lecture en \a m_nb_part
573 // Pour chaque i_entity , on a d'abord la liste des identifiants puis la liste des coordonnées
574
575 for (Int32 i_part = 0; i_part < m_nb_part; ++i_part) {
576 Int64 nb_to_read = _interval(i_part, m_nb_part, nb_node2).second;
578 info() << "Reading UIDS part i=" << i_part << " dest_rank=" << dest_rank << " nb_to_read=" << nb_to_read;
579 if (my_rank == dest_rank || my_rank == m_master_io_rank) {
580 nodes_uids.resize(nb_to_read);
581 }
582
583 // Le rang maitre lit les informations des noeuds pour la partie concernée
584 // et les transfère au rang destination
585 if (ios_file) {
586 for (Integer i = 0; i < nb_to_read; ++i) {
587 // Conserve le uniqueId() du noeuds.
588 nodes_uids[i] = ios_file->getInt64();
589 //info() << "I=" << i << " ID=" << nodes_uids[i];
590 }
591 if (dest_rank != m_master_io_rank) {
592 pm->send(nodes_uids, dest_rank);
593 }
594 }
595 else if (my_rank == dest_rank) {
596 pm->recv(nodes_uids, m_master_io_rank);
597 }
598
599 // Conserve les informations de ma partie
600 if (my_rank == dest_rank) {
601 m_mesh_info.nodes_unique_id.addRange(nodes_uids);
602 }
603 }
604
605 // Lecture par partie des coordonnées
606 for (Int32 i_part = 0; i_part < m_nb_part; ++i_part) {
607 Int64 nb_to_read = _interval(i_part, m_nb_part, nb_node2).second;
608 Int32 dest_rank = m_parts_rank[i_part];
609 info() << "Reading COORDS part i=" << i_part << " dest_rank=" << dest_rank << " nb_to_read=" << nb_to_read;
610 if (my_rank == dest_rank || my_rank == m_master_io_rank) {
611 nodes_coordinates.resize(nb_to_read);
612 }
613
614 // Le rang maitre lit les informations des noeuds pour la partie concernée
615 // et les transfère au rang destination
616 if (ios_file) {
617 for (Integer i = 0; i < nb_to_read; ++i) {
618 nodes_coordinates[i] = _getReal3();
619 //info() << "I=" << i << " ID=" << nodes_uids[i] << " COORD=" << Real3(nx, ny, nz);
620 }
621 if (dest_rank != m_master_io_rank) {
622 pm->send(nodes_coordinates, dest_rank);
623 }
624 }
625 else if (my_rank == dest_rank) {
626 pm->recv(nodes_coordinates, m_master_io_rank);
627 }
628
629 // Conserve les informations de ma partie
630 if (my_rank == dest_rank) {
631 m_mesh_info.nodes_coordinates.addRange(nodes_coordinates);
632 }
633 }
634
635 _goToNextLine();
636}
637
638/*---------------------------------------------------------------------------*/
639/*---------------------------------------------------------------------------*/
645{
646 IosFile* ios_file = m_ios_file.get();
647 IParallelMng* pm = m_parallel_mng;
648 const Int32 my_rank = pm->commRank();
649 const Int64 nb_entity_in_block = block.nb_entity;
650 const Int32 item_nb_node = block.item_nb_node;
651
652 info() << "Reading block nb_entity=" << nb_entity_in_block << " item_nb_node=" << item_nb_node;
653
655 UniqueArray<Int64> connectivities;
656
657 for (Int32 i_part = 0; i_part < m_nb_part; ++i_part) {
659 const Int32 dest_rank = m_parts_rank[i_part];
660
661 info() << "Reading block part i_part=" << i_part
662 << " nb_to_read=" << nb_to_read << " dest_rank=" << dest_rank;
663
664 const Int64 nb_uid = nb_to_read;
665 const Int64 nb_connectivity = nb_uid * item_nb_node;
666 if (my_rank == dest_rank || my_rank == m_master_io_rank) {
667 uids.resize(nb_uid);
668 connectivities.resize(nb_connectivity);
669 }
670 if (ios_file) {
671 // Utilise des Int64 pour garantir qu'on ne déborde pas.
672 for (Int64 i = 0; i < nb_uid; ++i) {
673 Int64 item_unique_id = ios_file->getInt64();
674 uids[i] = item_unique_id;
675 for (Int32 j = 0; j < item_nb_node; ++j)
676 connectivities[(i * item_nb_node) + j] = ios_file->getInt64();
677 }
678 if (dest_rank != m_master_io_rank) {
679 pm->send(uids, dest_rank);
680 pm->send(connectivities, dest_rank);
681 }
682 }
683 else if (my_rank == dest_rank) {
684 pm->recv(uids, m_master_io_rank);
685 pm->recv(connectivities, m_master_io_rank);
686 }
687 if (my_rank == dest_rank) {
688 block.uids.addRange(uids);
689 block.connectivities.addRange(connectivities);
690 }
691 }
692}
693
694/*---------------------------------------------------------------------------*/
695/*---------------------------------------------------------------------------*/
726{
727 IosFile* ios_file = m_ios_file.get();
728 IParallelMng* pm = m_parallel_mng;
729
731 _getInt64ArrayAndBroadcast(elements_info.view());
732
733 Int64 nb_block = elements_info[0];
737
738 _goToNextLine();
739
740 info() << "[Elements] nb_block=" << nb_block
741 << " nb_elements=" << number_of_elements
742 << " min_element_tag=" << min_element_tag
743 << " max_element_tag=" << max_element_tag;
744
745 if (number_of_elements < 0)
746 ARCANE_THROW(IOException, "Invalid number of elements: {0}", number_of_elements);
747
748 UniqueArray<MeshV4ElementsBlock>& blocks = m_mesh_info.blocks;
749 blocks.resize(nb_block);
750
751 {
752 // Numérote les blocs (pour le débug)
753 Integer index = 0;
754 for (MeshV4ElementsBlock& block : blocks) {
755 block.index = index;
756 ++index;
757 }
758 }
759
760 for (MeshV4ElementsBlock& block : blocks) {
761
763 _getInt64ArrayAndBroadcast(block_info.view());
764
766 Int64 entity_tag = block_info[1];
767 Int64 entity_type = block_info[2];
769
770 Integer item_nb_node = 0;
771 Integer item_type = _switchMshType(entity_type, item_nb_node);
772
773 info() << "[Elements] index=" << block.index << " entity_dim=" << entity_dim
774 << " entity_tag=" << entity_tag
775 << " entity_type=" << entity_type << " nb_in_block=" << nb_entity_in_block
776 << " item_type=" << item_type << " item_nb_node=" << item_nb_node;
777
778 block.nb_entity = nb_entity_in_block;
779 block.item_type = item_type;
780 block.item_nb_node = item_nb_node;
781 block.dimension = entity_dim;
782 block.entity_tag = entity_tag;
783
784 if (entity_type == MSH_PNT) {
785 // Si le type est un point, le traitement semble un peu particulier.
786 // Il y a dans ce cas deux entiers dans la ligne suivante:
787 // - un entier qui ne semble pas être utilisé
788 // - le numéro unique du noeud qui nous intéresse
789 Int64 item_unique_id = NULL_ITEM_UNIQUE_ID;
790 if (ios_file) {
791 [[maybe_unused]] Int64 unused_id = ios_file->getInt64();
792 item_unique_id = ios_file->getInt64();
793 info() << "Adding unique node uid=" << item_unique_id;
794 }
795 if (m_is_parallel)
796 pm->broadcast(ArrayView<Int64>(1, &item_unique_id), m_master_io_rank);
797 block.uids.add(item_unique_id);
798 }
799 else {
801 }
802 _goToNextLine();
803 }
804
805 // Maintenant qu'on a tout les blocs, la dimension du maillage est
806 // la plus grande dimension des blocs
807 Integer mesh_dimension = -1;
808 for (const MeshV4ElementsBlock& block : blocks)
809 mesh_dimension = math::max(mesh_dimension, block.dimension);
810 if (mesh_dimension < 0)
811 ARCANE_FATAL("Invalid computed mesh dimension '{0}'", mesh_dimension);
812 if (mesh_dimension != 2 && mesh_dimension != 3)
813 ARCANE_THROW(NotSupportedException, "mesh dimension '{0}'. Only 2D or 3D meshes are supported", mesh_dimension);
814 info() << "Computed mesh dimension = " << mesh_dimension;
815
816 for (MeshV4ElementsBlock& block : blocks) {
817 if (block.dimension == mesh_dimension)
818 _computeOwnCells(block);
819 }
820
821 return mesh_dimension;
822}
823
824/*---------------------------------------------------------------------------*/
825/*---------------------------------------------------------------------------*/
826
827namespace
828{
829 template <typename DataType> inline ArrayView<DataType>
831 UniqueArray<DataType>& work_values, Int32 dest_rank, Int64 size)
832 {
833 const Int32 my_rank = pm->commRank();
834 ArrayView<DataType> view = values.view();
835 if (my_rank != dest_rank) {
836 work_values.resize(size);
837 view = work_values.view();
838 }
839 pm->broadcast(view, dest_rank);
840 return view;
841 }
849 template <typename DataType> inline ArrayView<DataType>
850 _broadcastArray(IParallelMng* pm, UniqueArray<DataType>& values,
851 UniqueArray<DataType>& work_values, Int32 dest_rank)
852 {
853 const Int32 my_rank = pm->commRank();
854 Int64 size = 0;
855 // Envoie la taille
856 if (dest_rank == my_rank)
857 size = values.size();
858 pm->broadcast(ArrayView<Int64>(1, &size), dest_rank);
859 return _broadcastArrayWithSize(pm, values, work_values, dest_rank, size);
860 }
861
862} // namespace
863
864void MshParallelMeshReader::
865_computeOwnCells(MeshV4ElementsBlock& block)
866{
867 // On ne conserve que les mailles dont le premier noeud appartient à notre rang.
868
869 IParallelMng* pm = m_parallel_mng;
870 const Int32 my_rank = pm->commRank();
871
872 const Int32 item_type = block.item_type;
873 const Int32 item_nb_node = block.item_nb_node;
874
875 UniqueArray<Int64> connectivities;
876 UniqueArray<Int64> uids;
877 UniqueArray<Int32> nodes_rank;
878
879 const Int32 nb_part = m_parts_rank.size();
880 for (Int32 i_part = 0; i_part < nb_part; ++i_part) {
881 const Int32 dest_rank = m_parts_rank[i_part];
882 // Broadcast la i_part-ème partie des uids et connectivités des mailles
883 ArrayView<Int64> connectivities_view = _broadcastArray(pm, block.connectivities, connectivities, dest_rank);
884 ArrayView<Int64> uids_view = _broadcastArray(pm, block.uids, uids, dest_rank);
885
886 Int32 nb_item = uids_view.size();
887 nodes_rank.resize(nb_item);
888 nodes_rank.fill(-1);
889
890 // Parcours les mailles. Chaque maille appartiendra au rang
891 // de son premier noeud. Si cette partie correspond à mon rang, alors
892 // on conserve la maille.
893 for (Int32 i = 0; i < nb_item; ++i) {
894 Int64 first_node_uid = connectivities_view[i * item_nb_node];
895 auto x = m_mesh_info.nodes_rank_map.find(first_node_uid);
896 if (x == m_mesh_info.nodes_rank_map.end())
897 // Le noeud n'est pas dans ma liste
898 continue;
899 Int32 rank = x->second;
900 nodes_rank[i] = rank;
901 }
902 pm->reduce(Parallel::ReduceMax, nodes_rank);
903 for (Int32 i = 0; i < nb_item; ++i) {
904 const Int32 rank = nodes_rank[i];
905 if (rank != my_rank)
906 // Le noeud n'est pas dans ma partie
907 continue;
908 // Le noeud est chez moi, j'ajoute ma maille à la liste des
909 // mailles que je vais créer.
910 m_mesh_info.cells_type.add(item_type);
911 m_mesh_info.cells_nb_node.add(item_nb_node);
912 m_mesh_info.cells_uid.add(uids_view[i]);
913 auto v = connectivities_view.subView(i * item_nb_node, item_nb_node);
914 m_mesh_info.cells_connectivity.addRange(v);
915 }
916 }
917}
918
919/*---------------------------------------------------------------------------*/
920/*---------------------------------------------------------------------------*/
937{
941
942 IParallelMng* pm = m_parallel_mng;
943
944 const IItemFamily* node_family = m_mesh->nodeFamily();
946
947 for (Int32 dest_rank : m_parts_rank) {
950
951 Int32 nb_item = uids.size();
952 local_ids.resize(nb_item);
953
954 // Converti les uniqueId() en localId(). S'ils sont non nuls
955 // c'est que l'entité est dans mon sous-domaine et donc on peut
956 // positionner sa coordonnée
957 node_family->itemsUniqueIdToLocalId(local_ids, uids, false);
958 for (Int32 i = 0; i < nb_item; ++i) {
960 if (!nid.isNull())
961 nodes_coord_var[nid] = coords[i];
962 }
963 }
964}
965
966/*---------------------------------------------------------------------------*/
967/*---------------------------------------------------------------------------*/
968
969void MshParallelMeshReader::
970_allocateCells()
971{
972 // TODO: Allouer par bloc de 100000 mailles pour éviter de faire
973 // une trop grosse allocation
974 IMesh* mesh = m_mesh;
975 Integer nb_elements = m_mesh_info.cells_type.size();
976 info() << "nb_of_elements=cells_type.size()=" << nb_elements;
977 Integer nb_cell_node = m_mesh_info.cells_connectivity.size();
978 info() << "nb_cell_node=cells_connectivity.size()=" << nb_cell_node;
979
980 // Création des mailles
981 info() << "Building cells, nb_cell=" << nb_elements << " nb_cell_node=" << nb_cell_node;
982 // Infos pour la création des mailles
983 // par maille: 1 pour son unique id,
984 // 1 pour son type,
985 // 1 pour chaque noeud
987 Int32 connectivity_index = 0;
989 for (Integer i = 0; i < nb_elements; ++i) {
990 Integer current_cell_nb_node = m_mesh_info.cells_nb_node[i];
991 Integer cell_type = m_mesh_info.cells_type[i];
992 Int64 cell_uid = m_mesh_info.cells_uid[i];
994 cells_infos.add(cell_uid); //cell_unique_id
995
996 ArrayView<Int64> local_info(current_cell_nb_node, &m_mesh_info.cells_connectivity[connectivity_index]);
997 cells_infos.addRange(local_info);
999 }
1000
1001 IPrimaryMesh* pmesh = mesh->toPrimaryMesh();
1002 info() << "## Allocating ##";
1003 pmesh->allocateCells(nb_elements, cells_infos, false);
1004 info() << "## Ending ##";
1005 pmesh->endAllocate();
1006 info() << "## Done ##";
1007
1008 // Positionne les coordonnées des noeuds
1010}
1011
1012/*---------------------------------------------------------------------------*/
1013/*---------------------------------------------------------------------------*/
1014
1015void MshParallelMeshReader::
1016_allocateGroups()
1017{
1018 IMesh* mesh = m_mesh;
1019 Int32 mesh_dim = mesh->dimension();
1020 Int32 face_dim = mesh_dim - 1;
1021 UniqueArray<MeshV4EntitiesWithNodes> entity_list;
1022 UniqueArray<MeshPhysicalName> physical_name_list;
1023 for (MeshV4ElementsBlock& block : m_mesh_info.blocks) {
1024 entity_list.clear();
1025 physical_name_list.clear();
1026 Int32 block_index = block.index;
1027 Int32 block_dim = block.dimension;
1028 // On alloue un groupe s'il a un nom physique associé.
1029 // Pour cela, il faut déjà qu'il soit associé à une entité.
1030 Int64 block_entity_tag = block.entity_tag;
1031 if (block_entity_tag < 0) {
1032 info(5) << "[Groups] Skipping block index=" << block_index << " because it has no entity";
1033 continue;
1034 }
1035 if (block_dim == 0) {
1036 const MeshV4EntitiesNodes* entity = m_mesh_info.findNodeEntities(block_entity_tag);
1037 if (!entity) {
1038 info(5) << "[Groups] Skipping block index=" << block_index
1039 << " because entity tag is invalid";
1040 continue;
1041 }
1042 Int64 entity_physical_tag = entity->physical_tag;
1043 MeshPhysicalName physical_name = m_mesh_info.physical_name_list.find(block_dim, entity_physical_tag);
1044 physical_name_list.add(physical_name);
1045 }
1046 else {
1047 m_mesh_info.findEntities(block_dim, block_entity_tag, entity_list);
1048 for (const MeshV4EntitiesWithNodes& x : entity_list) {
1049 Int64 entity_physical_tag = x.physical_tag;
1050 MeshPhysicalName physical_name = m_mesh_info.physical_name_list.find(block_dim, entity_physical_tag);
1051 physical_name_list.add(physical_name);
1052 }
1053 }
1054 for (const MeshPhysicalName& physical_name : physical_name_list) {
1055 if (physical_name.isNull()) {
1056 info(5) << "[Groups] Skipping block index=" << block_index
1057 << " because entity physical tag is invalid";
1058 continue;
1059 }
1060 info(4) << "[Groups] Block index=" << block_index << " dim=" << block_dim
1061 << " name='" << physical_name.name << "'";
1062 if (block_dim == mesh_dim) {
1063 _addCellOrNodeGroup(block, physical_name.name, mesh->cellFamily());
1064 }
1065 else if (block_dim == face_dim) {
1066 _addFaceGroup(block, physical_name.name);
1067 }
1068 else {
1069 _addCellOrNodeGroup(block, physical_name.name, mesh->nodeFamily());
1070 }
1071 }
1072 }
1073}
1074
1075/*---------------------------------------------------------------------------*/
1076/*---------------------------------------------------------------------------*/
1082{
1083 IParallelMng* pm = m_parallel_mng;
1084 const Int32 item_nb_node = block.item_nb_node;
1085
1086 UniqueArray<Int64> connectivities;
1087 for (Int32 dest_rank : m_parts_rank) {
1089 _addFaceGroupOnePart(connectivities_view, item_nb_node, group_name, block.index);
1090 }
1091}
1092
1093/*---------------------------------------------------------------------------*/
1094/*---------------------------------------------------------------------------*/
1095
1096void MshParallelMeshReader::
1097_addFaceGroupOnePart(ConstArrayView<Int64> connectivities, Int32 item_nb_node,
1098 const String& group_name, Int32 block_index)
1099{
1100 IMesh* mesh = m_mesh;
1101 const Int32 nb_entity = connectivities.size() / item_nb_node;
1102
1103 // Il peut y avoir plusieurs blocs pour le même groupe.
1104 // On récupère le groupe s'il existe déjà.
1105 FaceGroup face_group = mesh->faceFamily()->findGroup(group_name, true);
1106
1107 UniqueArray<Int32> faces_id; // Numéro de la face dans le maillage \a mesh
1108 faces_id.reserve(nb_entity);
1109
1110 const Int32 face_nb_node = nb_entity * item_nb_node;
1111
1115 Integer faces_nodes_unique_id_index = 0;
1116
1117 UniqueArray<Int64> orig_nodes_id(item_nb_node);
1119
1122
1123 // Réordonne les identifiants des faces retrouver la face dans le maillage
1124 for (Integer i_face = 0; i_face < nb_entity; ++i_face) {
1125 for (Integer z = 0; z < item_nb_node; ++z)
1126 orig_nodes_id[z] = connectivities[faces_nodes_unique_id_index + z];
1127
1128 MeshUtils::reorderNodesOfFace2(orig_nodes_id, face_nodes_index);
1129 for (Integer z = 0; z < item_nb_node; ++z)
1132 faces_nodes_unique_id_index += item_nb_node;
1133 }
1134
1135 node_family->itemsUniqueIdToLocalId(faces_first_node_local_id, faces_first_node_unique_id, false);
1136
1137 faces_nodes_unique_id_index = 0;
1138 for (Integer i_face = 0; i_face < nb_entity; ++i_face) {
1139 const Integer n = item_nb_node;
1140 Int32 face_first_node_lid = faces_first_node_local_id[i_face];
1141 if (face_first_node_lid != NULL_ITEM_LOCAL_ID) {
1142 Int64ConstArrayView face_nodes_id(item_nb_node, &faces_nodes_unique_id[faces_nodes_unique_id_index]);
1143 Node current_node(mesh_nodes[faces_first_node_local_id[i_face]]);
1144 Face face = MeshUtils::getFaceFromNodesUnique(current_node, face_nodes_id);
1145
1146 // En parallèle, il est possible que la face ne soit pas dans notre sous-domaine
1147 // même si un de ses noeuds l'est
1148 if (face.null()) {
1149 if (!m_is_parallel) {
1150 OStringStream ostr;
1151 ostr() << "(Nodes:";
1152 for (Integer z = 0; z < n; ++z)
1153 ostr() << ' ' << face_nodes_id[z];
1154 ostr() << " - " << current_node.localId() << ")";
1155 ARCANE_FATAL("INTERNAL: MeshMeshReader face index={0} with nodes '{1}' is not in node/face connectivity",
1156 i_face, ostr.str());
1157 }
1158 }
1159 else
1160 faces_id.add(face.localId());
1161 }
1162
1163 faces_nodes_unique_id_index += n;
1164 }
1165 info(4) << "Adding " << faces_id.size() << " faces from block index=" << block_index
1166 << " to group '" << face_group.name() << "'";
1167 face_group.addItems(faces_id);
1168}
1169
1170/*---------------------------------------------------------------------------*/
1171/*---------------------------------------------------------------------------*/
1177{
1178 IParallelMng* pm = m_parallel_mng;
1179
1180 UniqueArray<Int64> uids;
1181 for (Int32 dest_rank : m_parts_rank) {
1182 ArrayView<Int64> uids_view = _broadcastArray(pm, block.uids, uids, dest_rank);
1183 _addCellOrNodeGroupOnePart(uids_view, group_name, block.index, family);
1184 }
1185}
1186
1187/*---------------------------------------------------------------------------*/
1188/*---------------------------------------------------------------------------*/
1189
1190void MshParallelMeshReader::
1191_addCellOrNodeGroupOnePart(ConstArrayView<Int64> uids, const String& group_name,
1192 Int32 block_index, IItemFamily* family)
1193{
1194 const Int32 nb_entity = uids.size();
1195
1196 // Il peut y avoir plusieurs blocs pour le même groupe.
1197 // On récupère le groupe s'il existe déjà.
1198 ItemGroup group = family->findGroup(group_name, true);
1199
1200 UniqueArray<Int32> items_lid(nb_entity);
1201
1202 family->itemsUniqueIdToLocalId(items_lid, uids, false);
1203
1204 // En parallèle, il est possible que certaines entités du groupe ne soient
1205 // pas dans notre sous-domaine. Il faut les filtrer.
1206 if (m_is_parallel) {
1207 auto items_begin = items_lid.begin();
1208 Int64 new_size = std::remove(items_begin, items_lid.end(), NULL_ITEM_LOCAL_ID) - items_begin;
1209 items_lid.resize(new_size);
1210 }
1211
1212 info() << "Adding " << items_lid.size() << " items from block index=" << block_index
1213 << " to group '" << group_name << "' for family=" << family->name();
1214
1215 group.addItems(items_lid);
1216}
1217
1218/*---------------------------------------------------------------------------*/
1219/*---------------------------------------------------------------------------*/
1220/*
1221 * $PhysicalNames // same as MSH version 2
1222 * numPhysicalNames(ASCII int)
1223 * dimension(ASCII int) physicalTag(ASCII int) "name"(127 characters max)
1224 * ...
1225 * $EndPhysicalNames
1226 */
1227void MshParallelMeshReader::
1228_readPhysicalNames()
1229{
1230 String quote_mark = "\"";
1231 Int32 nb_name = _getIntegerAndBroadcast();
1232 info() << "nb_physical_name=" << nb_name;
1233
1234 _goToNextLine();
1235
1236 for (Int32 i = 0; i < nb_name; ++i) {
1237 Int32 dim = _getIntegerAndBroadcast();
1238 Int32 tag = _getIntegerAndBroadcast();
1239 String s = _getNextLineAndBroadcast();
1240 if (dim < 0 || dim > 3)
1241 ARCANE_FATAL("Invalid value for physical name dimension dim={0}", dim);
1242 // Les noms des groupes peuvent commencer par des espaces et contiennent
1243 // des guillemets qu'il faut supprimer.
1245 if (s.startsWith(quote_mark))
1246 s = s.substring(1);
1247 if (s.endsWith(quote_mark))
1248 s = s.substring(0, s.length() - 1);
1249 m_mesh_info.physical_name_list.add(dim, tag, s);
1250 info(4) << "[PhysicalName] index=" << i << " dim=" << dim << " tag=" << tag << " name='" << s << "'";
1251 }
1252
1253 String s = _getNextLineAndBroadcast();
1254 if (s != "$EndPhysicalNames")
1255 ARCANE_FATAL("found '{0}' and expected '$EndPhysicalNames'", s);
1256}
1257
1258/*---------------------------------------------------------------------------*/
1259/*---------------------------------------------------------------------------*/
1260
1293{
1294 IosFile* ios_file = m_ios_file.get();
1295
1297 _getInt64ArrayAndBroadcast(nb_dim_item.view());
1298
1299 info(4) << "[Entities] nb_0d=" << nb_dim_item[0] << " nb_1d=" << nb_dim_item[1]
1300 << " nb_2d=" << nb_dim_item[2] << " nb_3d=" << nb_dim_item[3];
1301 // Après le format, on peut avoir les entités mais cela est optionnel
1302 // Si elles sont présentes, on lit le fichier jusqu'à la fin de cette section.
1303 _goToNextLine();
1304
1305 for (Int64 i = 0; i < nb_dim_item[0]; ++i) {
1307 if (ios_file) {
1308 Int64 tag = ios_file->getInt64();
1309 Real3 xyz = _getReal3();
1310 Int64 num_physical_tag = ios_file->getInt64();
1311 if (num_physical_tag > 1)
1312 ARCANE_FATAL("NotImplemented numPhysicalTag>1 (n={0}, index={1} xyz={2})",
1313 num_physical_tag, i, xyz);
1314
1315 Int32 physical_tag = -1;
1316 if (num_physical_tag == 1)
1317 physical_tag = ios_file->getInteger();
1318 info(4) << "[Entities] point tag=" << tag << " pos=" << xyz << " phys_tag=" << physical_tag;
1319
1320 tag_info[0] = tag;
1321 tag_info[1] = physical_tag;
1322 }
1323 m_parallel_mng->broadcast(tag_info.view(), m_master_io_rank);
1324 m_mesh_info.entities_nodes_list.add(MeshV4EntitiesNodes(tag_info[0], tag_info[1]));
1325 _goToNextLine();
1326 }
1327
1328 for (Int32 i_dim = 1; i_dim <= 3; ++i_dim)
1329 for (Int32 i = 0; i < nb_dim_item[i_dim]; ++i)
1330 _readOneEntity(i_dim);
1331
1333 if (s != "$EndEntities")
1334 ARCANE_FATAL("found '{0}' and expected '$EndEntities'", s);
1335}
1336
1337/*---------------------------------------------------------------------------*/
1338/*---------------------------------------------------------------------------*/
1339
1340void MshParallelMeshReader::
1341_readOneEntity(Int32 entity_dim)
1342{
1343 IosFile* ios_file = m_ios_file.get();
1344
1345 // Infos pour les tags
1346 // [0] entity_dim
1347 // [1] tag
1348 // [2] nb_physical_tag
1349 // [3] physical_tag1
1350 // [4] physical_tag2
1351 // [5] ...
1354 if (ios_file) {
1355 Int64 tag = ios_file->getInt64();
1356 dim_and_tag_info[1] = tag;
1357 Real3 min_pos = _getReal3();
1358 Real3 max_pos = _getReal3();
1359 Int64 nb_physical_tag = ios_file->getInt64();
1360 if (nb_physical_tag >= 124)
1361 ARCANE_FATAL("NotImplemented numPhysicalTag>=124 (n={0})", nb_physical_tag);
1363 for (Int32 z = 0; z < nb_physical_tag; ++z) {
1364 Int32 physical_tag = ios_file->getInteger();
1365 dim_and_tag_info[3 + z] = physical_tag;
1366 info(4) << "[Entities] z=" << z << " physical_tag=" << physical_tag;
1367 }
1368 // TODO: Lire les informations numBounding...
1369 Int32 num_bounding_group = ios_file->getInteger();
1370 for (Int32 k = 0; k < num_bounding_group; ++k) {
1371 [[maybe_unused]] Int32 group_tag = ios_file->getInteger();
1372 }
1373 info(4) << "[Entities] dim=" << entity_dim << " tag=" << tag
1374 << " min_pos=" << min_pos << " max_pos=" << max_pos
1375 << " nb_phys_tag=" << nb_physical_tag;
1376 }
1377
1378 m_parallel_mng->broadcast(dim_and_tag_info.view(), m_master_io_rank);
1379
1380 {
1381 Int32 dim = CheckedConvert::toInt32(dim_and_tag_info[0]);
1382 Int64 tag = dim_and_tag_info[1];
1383 Int64 nb_physical_tag = dim_and_tag_info[2];
1384 for (Int32 z = 0; z < nb_physical_tag; ++z) {
1385 Int64 physical_tag = dim_and_tag_info[3 + z];
1386 info(4) << "[Entities] adding info dim=" << entity_dim << " tag=" << tag
1387 << " physical_tag=" << physical_tag;
1388 m_mesh_info.entities_with_nodes_list[dim - 1].add(MeshV4EntitiesWithNodes(dim, tag, physical_tag));
1389 }
1390 }
1391
1392 _goToNextLine();
1393}
1394
1395/*---------------------------------------------------------------------------*/
1396/*---------------------------------------------------------------------------*/
1399void MshParallelMeshReader::
1400_readMeshFromFile()
1401{
1402 IosFile* ios_file = m_ios_file.get();
1403 IMesh* mesh = m_mesh;
1404 info() << "Reading 'msh' file in parallel";
1405 const int MSH_BINARY_TYPE = 1;
1406
1407 if (ios_file) {
1408 Real version = ios_file->getReal();
1409 if (version != 4.1)
1410 ARCANE_THROW(IOException, "Wrong msh file version '{0}'. Only version '4.1' is supported in parallel", version);
1411 Integer file_type = ios_file->getInteger(); // is an integer equal to 0 in the ASCII file format, equal to 1 for the binary format
1412 if (file_type == MSH_BINARY_TYPE)
1413 ARCANE_THROW(IOException, "Binary mode is not supported!");
1414
1415 Integer data_size = ios_file->getInteger(); // is an integer equal to the size of the floating point numbers used in the file
1416 ARCANE_UNUSED(data_size);
1417
1418 ios_file->getNextLine(); // Skip current \n\r
1419
1420 // $EndMeshFormat
1421 if (!ios_file->lookForString("$EndMeshFormat"))
1422 ARCANE_THROW(IOException, "$EndMeshFormat not found");
1423 }
1424
1425 // TODO: Les différentes sections ($Nodes, $Entitites, ...) peuvent
1426 // être dans n'importe quel ordre (à part $Nodes qui doit être avant $Elements)
1427 // Faire un méthode qui gère cela.
1428
1429 String next_line = _getNextLineAndBroadcast();
1430 // Noms des groupes
1431 if (next_line == "$PhysicalNames") {
1432 _readPhysicalNames();
1433 next_line = _getNextLineAndBroadcast();
1434 }
1435
1436 // Après le format, on peut avoir les entités mais cela est optionnel
1437 // Si elles sont présentes, on lit le fichier jusqu'à la fin de cette section.
1438 if (next_line == "$Entities") {
1439 _readEntities();
1440 next_line = _getNextLineAndBroadcast();
1441 }
1442 // $Nodes
1443 if (next_line != "$Nodes")
1444 ARCANE_THROW(IOException, "Unexpected string '{0}'. Valid values are '$Nodes'", next_line);
1445
1446 // Fetch nodes number and the coordinates
1448
1449 // $EndNodes
1450 if (ios_file && !ios_file->lookForString("$EndNodes"))
1451 ARCANE_THROW(IOException, "$EndNodes not found");
1452
1453 // $Elements
1454 if (ios_file && !ios_file->lookForString("$Elements"))
1455 ARCANE_THROW(IOException, "$Elements not found");
1456
1457 Int32 mesh_dimension = _readElementsFromFileAscii();
1458
1459 // $EndElements
1460 if (ios_file && !ios_file->lookForString("$EndElements"))
1461 ARCANE_THROW(IOException, "$EndElements not found");
1462
1463 info() << "Computed mesh dimension = " << mesh_dimension;
1464
1465 IPrimaryMesh* pmesh = mesh->toPrimaryMesh();
1466 pmesh->setDimension(mesh_dimension);
1467
1468 _allocateCells();
1469 _allocateGroups();
1470}
1471
1472/*---------------------------------------------------------------------------*/
1473/*---------------------------------------------------------------------------*/
1478readMeshFromMshFile(IMesh* mesh, const String& filename)
1479{
1480 info() << "Trying to read in parallel 'msh' file '" << filename;
1481 m_mesh = mesh;
1482 IParallelMng* pm = mesh->parallelMng();
1483 m_parallel_mng = pm;
1484 const Int32 nb_rank = pm->commSize();
1485
1486 // Détermine les rangs qui vont conserver les données
1487 m_nb_part = nb_rank;
1489 for (Int32 i = 0; i < m_nb_part; ++i) {
1490 m_parts_rank[i] = i % nb_rank;
1491 }
1492
1493 bool is_master_io = pm->isMasterIO();
1494 Int32 master_io_rank = pm->masterIORank();
1495 m_is_parallel = pm->isParallel();
1496 m_master_io_rank = master_io_rank;
1498 // Seul le rang maître va lire le fichier.
1499 // On vérifie d'abord qu'il est lisible
1500 if (is_master_io) {
1501 bool is_readable = platform::isFileReadable(filename);
1502 info() << "Is file readable ?=" << is_readable;
1503 file_readable[0] = is_readable ? 1 : 0;
1504 if (!is_readable)
1505 error() << "Unable to read file '" << filename << "'";
1506 }
1507 pm->broadcast(file_readable.view(), master_io_rank);
1508 if (file_readable[0] == 0) {
1509 return IMeshReader::RTError;
1510 }
1511
1512 std::ifstream ifile;
1514 if (is_master_io) {
1515 ifile.open(filename.localstr());
1517 }
1518 m_ios_file = ios_file;
1520 if (IosFile::isEqualString(mesh_format_str, "$MeshFormat")) {
1521 _readMeshFromFile();
1522 return IMeshReader::RTOk;
1523 }
1524
1525 info() << "The file does not begin with '$MeshFormat' returning RTError";
1526 return IMeshReader::RTError;
1527}
1528
1529/*---------------------------------------------------------------------------*/
1530/*---------------------------------------------------------------------------*/
1531
1532extern "C++" Ref<IMshMeshReader>
1533createMshParallelMeshReader(ITraceMng* tm)
1534{
1536}
1537
1538/*---------------------------------------------------------------------------*/
1539/*---------------------------------------------------------------------------*/
1540
1541} // End namespace Arcane
1542
1543/*---------------------------------------------------------------------------*/
1544/*---------------------------------------------------------------------------*/
#define ARCANE_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Fonctions utilitaires sur le maillage.
Informations sur le type flottant.
Definition Limits.h:48
Interface d'une famille d'entités.
virtual ItemGroup findGroup(const String &name) const =0
Recherche un groupe.
virtual String name() const =0
Nom de la famille.
virtual void itemsUniqueIdToLocalId(Int32ArrayView local_ids, Int64ConstArrayView unique_ids, bool do_fatal=true) const =0
Converti un tableau de numéros uniques en numéros locaux.
virtual IItemFamily * nodeFamily()=0
Retourne la famille des noeuds.
virtual IItemFamily * faceFamily()=0
Retourne la famille des faces.
eReturnType
Types des codes de retour d'une lecture ou écriture.
Definition IMeshReader.h:42
@ RTError
Erreur lors de l'opération.
Definition IMeshReader.h:44
@ RTOk
Opération effectuée avec succès.
Definition IMeshReader.h:43
virtual VariableNodeReal3 & nodesCoordinates()=0
Coordonnées des noeuds.
virtual IParallelMng * parallelMng()=0
Gestionnaire de parallèlisme.
virtual IPrimaryMesh * toPrimaryMesh()=0
Retourne l'instance sous la forme d'un IPrimaryMesh.
Exception lorsqu'une erreur d'entrée/sortie est détectée.
Definition IOException.h:32
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual void recv(ArrayView< char > values, Int32 rank)=0
virtual bool isMasterIO() const =0
true si l'instance est un gestionnaire maître des entrées/sorties.
virtual Int32 commSize() const =0
Nombre d'instance dans le communicateur.
virtual Integer masterIORank() const =0
Rang de l'instance gérant les entrées/sorties (pour laquelle isMasterIO() est vrai)
virtual bool isParallel() const =0
Retourne true si l'exécution est parallèle.
virtual char reduce(eReduceType rt, char v)=0
Effectue la réduction de type rt sur le réel v et retourne la valeur.
Routines des Lecture/Ecriture d'un fichier.
Definition IosFile.h:30
Groupe d'entités de maillage.
Definition ItemGroup.h:49
const String & name() const
Nom du groupe.
Definition ItemGroup.h:76
void addItems(Int32ConstArrayView items_local_id, bool check_if_present=true)
Ajoute des entités.
Definition ItemGroup.cc:445
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
Informations sur le maillage créé
std::unordered_map< Int64, Int32 > nodes_rank_map
Tableau associatif (uniqueId(),rang) auquel le noeud appartiendra.
UniqueArray< Int64 > nodes_unique_id
UniqueId() des noeuds de ma partie.
UniqueArray< Real3 > nodes_coordinates
Coordonnées des noeuds de ma partie.
Lecteur de fichiers de maillage au format msh.
void _addFaceGroup(MeshV4ElementsBlock &block, const String &group_name)
Ajoute des faces au groupe group_name.
Integer _readElementsFromFileAscii()
Lecture des éléments (mailles,faces,...)
UniqueArray< Int32 > m_parts_rank
Liste des rangs qui participent à la conservation des données.
void _readEntities()
Lecture des entités.
Int32 m_nb_part
Nombre de partitions pour la lecture des noeuds et blocs.
void _readOneElementBlock(MeshV4ElementsBlock &block)
Lit un bloc d'entité de type 'Element'.
void _readNodesFromFileAscii()
Lecture des noeuds du maillage.
void _setNodesCoordinates()
Positionne les coordonnées des noeuds.
eReturnType readMeshFromMshFile(IMesh *mesh, const String &file_name) override
Lit le maillage contenu dans le fichier filename et le construit dans mesh.
void _addCellOrNodeGroup(MeshV4ElementsBlock &block, const String &group_name, IItemFamily *family)
Ajoute des faces au groupe group_name.
String _getNextLineAndBroadcast()
Lis la valeur de la prochaine ligne et la broadcast aux autres rangs.
Vue sur les informations des noeuds.
Classe gérant un vecteur de réel de dimension 3.
Definition Real3.h:132
Integer size() const
Nombre d'éléments du vecteur.
Int64 largeSize() const
Nombre d'éléments du vecteur (en 64 bits)
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
void addRange(ConstReferenceType val, Int64 n)
Ajoute n élément de valeur val à la fin du tableau.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
Interface du gestionnaire de traces.
Exception lorsqu'une opération n'est pas supportée.
Chaîne de caractères unicode.
static String collapseWhiteSpace(const String &rhs)
Effectue une normalisation des caractères espaces.
Definition String.cc:452
const char * localstr() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:227
TraceMessage error() const
Flot pour un message d'erreur.
TraceMessage info() const
Flot pour un message d'information.
T max(const T &a, const T &b, const T &c)
Retourne le maximum de trois éléments.
Definition MathUtils.h:392
ARCCORE_HOST_DEVICE Real2 min(Real2 a, Real2 b)
Retourne le minimum de deux Real2.
Definition MathUtils.h:336
Int32 toInt32(Int64 v)
Converti un Int64 en un Int32.
constexpr ARCCORE_HOST_DEVICE bool isNearlyEqual(const _Type &a, const _Type &b)
Teste si deux valeurs sont à un peu près égales. Pour les types entiers, cette fonction est équivalen...
Definition Numeric.h:212
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
ConstArrayView< Int64 > Int64ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:638
Int32 Integer
Type représentant un entier.
Infos d'un bloc pour $Elements pour la version 4.
UniqueArray< Int64 > connectivities
< Liste des uniqueId() du bloc