Arcane  v3.15.0.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
168 {
169 public:
170
171 Int32 m_entity_dim = -1;
172 Int32 m_entity_tag = -1;
173 Int32 m_entity_tag_master = -1;
174 UniqueArray<double> m_affine_values;
175 Int32 m_nb_corresponding_node = 0;
176 UniqueArray<Int64> m_corresponding_nodes;
177 };
178
181 {
182 public:
183
184 UniqueArray<PeriodicOneInfo> m_periodic_list;
185 };
186
189 {
190 public:
191
192 void findEntities(Int32 dimension, Int64 tag, Array<MeshV4EntitiesWithNodes>& entities)
193 {
194 entities.clear();
195 for (auto& x : entities_with_nodes_list[dimension - 1])
196 if (x.tag == tag)
197 entities.add(x);
198 }
199
200 MeshV4EntitiesNodes* findNodeEntities(Int64 tag)
201 {
202 for (auto& x : entities_nodes_list)
203 if (x.tag == tag)
204 return &x;
205 return nullptr;
206 }
207
208 public:
209
210 UniqueArray<Int32> cells_nb_node;
211 UniqueArray<Int32> cells_type;
212 UniqueArray<Int64> cells_uid;
213 UniqueArray<Int64> cells_connectivity;
214
220 std::unordered_map<Int64, Int32> nodes_rank_map;
221 Real3 m_node_min_bounding_box;
222 Real3 m_node_max_bounding_box;
223 MeshPhysicalNameList physical_name_list;
224 UniqueArray<MeshV4EntitiesNodes> entities_nodes_list;
225 FixedArray<UniqueArray<MeshV4EntitiesWithNodes>, 3> entities_with_nodes_list;
227 PeriodicInfo m_periodic_info;
228 };
229
230 public:
231
234 {}
235
236 eReturnType readMeshFromMshFile(IMesh* mesh, const String& file_name) override;
237
238 private:
239
240 IMesh* m_mesh = nullptr;
241 IParallelMng* m_parallel_mng = nullptr;
242 Int32 m_master_io_rank = A_NULL_RANK;
243 bool m_is_parallel = false;
244 Ref<IosFile> m_ios_file; // nullptr sauf pour le rang maitre.
245 MeshInfo m_mesh_info;
247 Int32 m_nb_part = 4;
251 bool m_is_binary = false;
252
253 private:
254
255 void _readNodesFromFile();
256 void _readNodesOneEntity(Int32 entity_index);
257 Integer _readElementsFromFile();
258 void _readMeshFromFile();
260 void _allocateCells();
261 void _allocateGroups();
263 void _addFaceGroupOnePart(ConstArrayView<Int64> connectivities, Int32 item_nb_node,
264 const String& group_name, Int32 block_index);
266 void _addCellOrNodeGroupOnePart(ConstArrayView<Int64> uids, const String& group_name,
267 Int32 block_index, IItemFamily* family);
268 Int32 _switchMshType(Int64, Int32&) const;
269 void _readPhysicalNames();
270 void _readEntities();
271 void _readPeriodic();
272 void _readOneEntity(Int32 entity_dim);
275 Int32 _getIntegerAndBroadcast();
276 Int64 _getInt64AndBroadcast();
277 void _getInt64ArrayAndBroadcast(ArrayView<Int64> values);
278 void _getInt32ArrayAndBroadcast(ArrayView<Int32> values);
279 void _getDoubleArrayAndBroadcast(ArrayView<double> values);
282 void _computeOwnCells(MeshV4ElementsBlock& block);
283 Real3 _getReal3();
284 Int32 _getInt32();
285 Int64 _getInt64();
286 void _goToNextLine();
288};
289
290/*---------------------------------------------------------------------------*/
291/*---------------------------------------------------------------------------*/
292
293namespace
294{
301 inline std::pair<Int64, Int64>
302 _interval(Int32 index, Int32 nb_interval, Int64 size)
303 {
304 Int64 isize = size / nb_interval;
305 Int64 ibegin = index * isize;
306 // Pour le dernier interval, prend les elements restants
307 if ((index + 1) == nb_interval)
308 isize = size - ibegin;
309 return { ibegin, isize };
310 }
311} // namespace
312
313/*---------------------------------------------------------------------------*/
314/*---------------------------------------------------------------------------*/
320{
321 IosFile* f = m_ios_file.get();
322 String s;
323 if (f) {
324 s = f->getNextLine();
325 }
326 if (m_is_parallel) {
327 if (f)
328 info() << "BroadcastNextLine: " << s;
329 m_parallel_mng->broadcastString(s, m_master_io_rank);
330 }
331 info() << "GetNextLine: " << s;
332 return s;
333}
334
335/*---------------------------------------------------------------------------*/
336/*---------------------------------------------------------------------------*/
342{
343 IosFile* f = m_ios_file.get();
344 Int32 is_end_int = 0;
345 if (f) {
346 is_end_int = f->isEnd() ? 1 : 0;
347 info() << "IsEndOfFile_Master: " << is_end_int;
348 }
349 if (m_is_parallel) {
350 if (f)
351 info() << "IsEndOfFile: " << is_end_int;
352 m_parallel_mng->broadcast(ArrayView<Int32>(1, &is_end_int), m_master_io_rank);
353 }
354 bool is_end = (is_end_int != 0);
355 info() << "IsEnd: " << is_end;
356 return is_end;
357}
358
359/*---------------------------------------------------------------------------*/
360/*---------------------------------------------------------------------------*/
361
362Int32 MshParallelMeshReader::
363_getIntegerAndBroadcast()
364{
365 IosFile* f = m_ios_file.get();
367 if (f)
368 v[0] = f->getInteger();
369 if (m_is_parallel) {
370 m_parallel_mng->broadcast(v.view(), m_master_io_rank);
371 }
372 return v[0];
373}
374
375/*---------------------------------------------------------------------------*/
376/*---------------------------------------------------------------------------*/
377
378Int64 MshParallelMeshReader::
379_getInt64AndBroadcast()
380{
381 IosFile* f = m_ios_file.get();
382 FixedArray<Int64, 1> v;
383 if (f)
384 v[0] = _getInt64();
385 if (m_is_parallel) {
386 m_parallel_mng->broadcast(v.view(), m_master_io_rank);
387 }
388 return v[0];
389}
390
391/*---------------------------------------------------------------------------*/
392/*---------------------------------------------------------------------------*/
393
394void MshParallelMeshReader::
395_getInt64ArrayAndBroadcast(ArrayView<Int64> values)
396{
397 IosFile* f = m_ios_file.get();
398 if (f) {
399 if (m_is_binary) {
400 f->binaryRead(values);
401 }
402 else {
403 for (Int64& v : values)
404 v = f->getInt64();
405 }
406 }
407 if (m_is_parallel)
408 m_parallel_mng->broadcast(values, m_master_io_rank);
409}
410
411/*---------------------------------------------------------------------------*/
412/*---------------------------------------------------------------------------*/
413
414void MshParallelMeshReader::
415_getInt32ArrayAndBroadcast(ArrayView<Int32> values)
416{
417 IosFile* f = m_ios_file.get();
418 if (f) {
419 if (m_is_binary) {
420 f->binaryRead(values);
421 }
422 else {
423 for (Int32& v : values)
424 v = f->getInteger();
425 }
426 }
427 if (m_is_parallel)
428 m_parallel_mng->broadcast(values, m_master_io_rank);
429}
430
431/*---------------------------------------------------------------------------*/
432/*---------------------------------------------------------------------------*/
433
434void MshParallelMeshReader::
435_getDoubleArrayAndBroadcast(ArrayView<double> values)
436{
437 IosFile* f = m_ios_file.get();
438 if (f) {
439 if (m_is_binary) {
440 f->binaryRead(values);
441 }
442 else {
443 for (double& v : values)
444 v = f->getReal();
445 }
446 }
447 if (m_is_parallel)
448 m_parallel_mng->broadcast(values, m_master_io_rank);
449}
450
451/*---------------------------------------------------------------------------*/
452/*---------------------------------------------------------------------------*/
453
454Real3 MshParallelMeshReader::
455_getReal3()
456{
457 IosFile* f = m_ios_file.get();
459 Real3 v;
460 if (m_is_binary) {
461 f->binaryRead(SmallSpan<Real3>(&v, 1));
462 }
463 else {
464 Real x = f->getReal();
465 Real y = f->getReal();
466 Real z = f->getReal();
467 v = Real3(x, y, z);
468 }
469 return v;
470}
471
472/*---------------------------------------------------------------------------*/
473/*---------------------------------------------------------------------------*/
474
475Int32 MshParallelMeshReader::
476_getInt32()
477{
478 IosFile* f = m_ios_file.get();
480 Int32 v = 0;
481 if (m_is_binary)
482 f->binaryRead(SmallSpan<Int32>(&v, 1));
483 else
484 v = f->getInteger();
485 return v;
486}
487
488/*---------------------------------------------------------------------------*/
489/*---------------------------------------------------------------------------*/
490
491Int64 MshParallelMeshReader::
492_getInt64()
493{
494 IosFile* f = m_ios_file.get();
496 Int64 v = 0;
497 if (m_is_binary)
498 f->binaryRead(SmallSpan<Int64>(&v, 1));
499 else
500 v = f->getInt64();
501 return v;
502}
503
504/*---------------------------------------------------------------------------*/
505/*---------------------------------------------------------------------------*/
506
507void MshParallelMeshReader::
508_goToNextLine()
509{
510 if (m_ios_file.get())
511 m_ios_file->getNextLine();
512}
513
514/*---------------------------------------------------------------------------*/
515/*---------------------------------------------------------------------------*/
516
517Int32 MshParallelMeshReader::
518_switchMshType(Int64 mshElemType, Int32& nNodes) const
519{
520 switch (mshElemType) {
521 case IT_NullType: // used to decode IT_NullType: IT_HemiHexa7|IT_Line9
522 switch (nNodes) {
523 case 7:
524 return IT_HemiHexa7;
525 default:
526 info() << "Could not decode IT_NullType with nNodes=" << nNodes;
527 throw IOException("_switchMshType", "Could not decode IT_NullType with nNodes");
528 }
529 break;
530 case MSH_PNT:
531 nNodes = 1;
532 return IT_Vertex;
533 case MSH_LIN_2:
534 nNodes = 2;
535 return IT_Line2;
536 case MSH_TRI_3:
537 nNodes = 3;
538 return IT_Triangle3;
539 case MSH_QUA_4:
540 nNodes = 4;
541 return IT_Quad4;
542 case MSH_TET_4:
543 nNodes = 4;
544 return IT_Tetraedron4;
545 case MSH_HEX_8:
546 nNodes = 8;
547 return IT_Hexaedron8;
548 case MSH_PRI_6:
549 nNodes = 6;
550 return IT_Pentaedron6;
551 case MSH_PYR_5:
552 nNodes = 5;
553 return IT_Pyramid5;
554 case MSH_TRI_10:
555 nNodes = 10;
556 return IT_Heptaedron10;
557 case MSH_TRI_12:
558 nNodes = 12;
559 return IT_Octaedron12;
560 case MSH_TRI_6:
561 nNodes = 6;
562 return IT_Triangle6;
563 case MSH_TET_10:
564 nNodes = 10;
565 return IT_Tetraedron10;
566 case MSH_QUA_9:
567 case MSH_HEX_27:
568 case MSH_PRI_18:
569 case MSH_PYR_14:
570 case MSH_QUA_8:
571 case MSH_HEX_20:
572 case MSH_PRI_15:
573 case MSH_PYR_13:
574 case MSH_TRI_9:
575 case MSH_TRI_15:
576 case MSH_TRI_15I:
577 case MSH_TRI_21:
578 default:
579 ARCANE_THROW(NotSupportedException, "Unknown GMSH element type '{0}'", mshElemType);
580 }
581 return IT_NullType;
582}
583
584/*---------------------------------------------------------------------------*/
585/*---------------------------------------------------------------------------*/
586
589{
590 // Détermine la bounding box de la maille
591 Real max_value = FloatInfo<Real>::maxValue();
592 Real min_value = -max_value;
593 Real3 min_box(max_value, max_value, max_value);
594 Real3 max_box(min_value, min_value, min_value);
595 const Int64 nb_node = m_mesh_info.nodes_coordinates.largeSize();
596 for (Real3 pos : m_mesh_info.nodes_coordinates) {
599 }
600 m_mesh_info.m_node_min_bounding_box = min_box;
601 m_mesh_info.m_node_max_bounding_box = max_box;
602
605
606 // Pour la partition, on ne prend en compte que la coordonnée X.
607 // On est sur qu'elle est valable pour toutes les dimensions du maillage.
608 // On partitionne avec des intervalles de même longueur.
609 // NOTE: Cela fonctionne bien si l'ensemble des noeuds est bien réparti.
610 // Si ce n'est pas le cas on pourrait utiliser une bisection en coupant
611 // à chaque fois sur la moyenne.
612 Real min_x = min_box.x;
613 Real max_x = max_box.x;
614 IParallelMng* pm = m_parallel_mng;
615 Real global_min_x = pm->reduce(Parallel::ReduceMin, min_x);
616 Real global_max_x = pm->reduce(Parallel::ReduceMax, max_x);
617 info() << "MIN_MAX_X=" << global_min_x << " " << global_max_x;
618
619 Real diff_v = (global_max_x - global_min_x) / static_cast<Real>(m_nb_part);
620 // Ne devrait pas arriver mais c'est nécessaire pour éviter d'éventuelles
621 // divisions par zéro.
623 for (Int64 i = 0; i < nb_node; ++i) {
624 Int32 part = static_cast<Int32>((m_mesh_info.nodes_coordinates[i].x - global_min_x) / diff_v);
625 part = std::clamp(part, 0, m_nb_part - 1);
626 nodes_part[i] = part;
627 }
628 }
630 // Construit la table de hashage des rangs
631 for (Int64 i = 0; i < nb_node; ++i) {
632 Int32 rank = m_parts_rank[nodes_part[i]];
633 Int64 uid = m_mesh_info.nodes_unique_id[i];
634 ++nb_node_per_rank[rank];
635 m_mesh_info.nodes_rank_map.insert(std::make_pair(uid, rank));
636 }
637 pm->reduce(Parallel::ReduceSum, nb_node_per_rank);
638 info() << "NB_NODE_PER_RANK=" << nb_node_per_rank;
639}
640
641/*---------------------------------------------------------------------------*/
642/*---------------------------------------------------------------------------*/
669{
671 _getInt64ArrayAndBroadcast(nodes_info.view());
672
673 Int64 nb_entity = nodes_info[0];
674 Int64 total_nb_node = nodes_info[1];
675 Int64 min_node_tag = nodes_info[2];
676 Int64 max_node_tag = nodes_info[3];
677
678 if (!m_is_binary)
679 _goToNextLine();
680
681 if (total_nb_node < 0)
682 ARCANE_THROW(IOException, "Invalid number of nodes : '{0}'", total_nb_node);
683
684 info() << "[Nodes] nb_entity=" << nb_entity
685 << " total_nb_node=" << total_nb_node
686 << " min_tag=" << min_node_tag
687 << " max_tag=" << max_node_tag
688 << " read_nb_part=" << m_nb_part
689 << " nb_rank=" << m_parallel_mng->commSize();
690
691 for (Integer i_entity = 0; i_entity < nb_entity; ++i_entity) {
692 _readNodesOneEntity(i_entity);
693 }
694
696
697 if (m_is_binary)
698 _goToNextLine();
699}
700
701/*---------------------------------------------------------------------------*/
702/*---------------------------------------------------------------------------*/
703
704void MshParallelMeshReader::
705_readNodesOneEntity(Int32 entity_index)
706{
707 IosFile* ios_file = m_ios_file.get();
708 IParallelMng* pm = m_parallel_mng;
709 const Int32 my_rank = pm->commRank();
710
712 UniqueArray<Real3> nodes_coordinates;
713
715 _getInt32ArrayAndBroadcast(entity_infos.view());
716 Int64 nb_node2 = _getInt64AndBroadcast();
717
718 if (!m_is_binary)
719 _goToNextLine();
720
721 // Dimension de l'entité (pas utile)
722 [[maybe_unused]] Int32 entity_dim = entity_infos[0];
723 // Tag de l'entité (pas utile)
724 [[maybe_unused]] Int32 entity_tag = entity_infos[1];
726 //Int64 nb_node2 = entity_infos[3];
727
728 info() << "[Nodes] index=" << entity_index << " entity_dim=" << entity_dim << " entity_tag=" << entity_tag
729 << " parametric=" << parametric_coordinates
730 << " nb_node2=" << nb_node2;
731
732 if (parametric_coordinates != 0)
733 ARCANE_THROW(NotSupportedException, "Only 'parametric coordinates' value of '0' is supported (current={0})", parametric_coordinates);
734
735 // Il est possible que le nombre de noeuds soit 0.
736 // Dans ce cas, il faut directement passer à la ligne suivante
737 if (nb_node2 == 0)
738 return;
739
740 // Partitionne la lecture en \a m_nb_part
741 // Pour chaque i_entity , on a d'abord la liste des identifiants puis la liste des coordonnées
742
743 for (Int32 i_part = 0; i_part < m_nb_part; ++i_part) {
744 Int64 nb_to_read = _interval(i_part, m_nb_part, nb_node2).second;
746 info() << "Reading UIDS part i=" << i_part << " dest_rank=" << dest_rank << " nb_to_read=" << nb_to_read;
747 if (my_rank == dest_rank || my_rank == m_master_io_rank) {
748 nodes_uids.resize(nb_to_read);
749 }
750
751 // Le rang maitre lit les informations des noeuds pour la partie concernée
752 // et les transfère au rang destination
753 if (ios_file) {
754 if (m_is_binary) {
755 ios_file->binaryRead(nodes_uids.view());
756 }
757 else {
758 for (Integer i = 0; i < nb_to_read; ++i) {
759 // Conserve le uniqueId() du noeuds.
760 nodes_uids[i] = ios_file->getInt64();
761 //info() << "I=" << i << " ID=" << nodes_uids[i];
762 }
763 }
764 if (dest_rank != m_master_io_rank) {
765 pm->send(nodes_uids, dest_rank);
766 }
767 }
768 else if (my_rank == dest_rank) {
769 pm->recv(nodes_uids, m_master_io_rank);
770 }
771
772 // Conserve les informations de ma partie
773 if (my_rank == dest_rank) {
774 m_mesh_info.nodes_unique_id.addRange(nodes_uids);
775 }
776 }
777
778 // Lecture par partie des coordonnées
779 for (Int32 i_part = 0; i_part < m_nb_part; ++i_part) {
780 Int64 nb_to_read = _interval(i_part, m_nb_part, nb_node2).second;
781 Int32 dest_rank = m_parts_rank[i_part];
782 info() << "Reading COORDS part i=" << i_part << " dest_rank=" << dest_rank << " nb_to_read=" << nb_to_read;
783 if (my_rank == dest_rank || my_rank == m_master_io_rank) {
784 nodes_coordinates.resize(nb_to_read);
785 }
786
787 // Le rang maitre lit les informations des noeuds pour la partie concernée
788 // et les transfère au rang destination
789 if (ios_file) {
790 if (m_is_binary) {
791 ios_file->binaryRead(nodes_coordinates.view());
792 }
793 else {
794 for (Integer i = 0; i < nb_to_read; ++i) {
795 nodes_coordinates[i] = _getReal3();
796 //info() << "I=" << i << " ID=" << nodes_uids[i] << " COORD=" << Real3(nx, ny, nz);
797 }
798 }
799 if (dest_rank != m_master_io_rank) {
800 pm->send(nodes_coordinates, dest_rank);
801 }
802 }
803 else if (my_rank == dest_rank) {
804 pm->recv(nodes_coordinates, m_master_io_rank);
805 }
806
807 // Conserve les informations de ma partie
808 if (my_rank == dest_rank) {
809 m_mesh_info.nodes_coordinates.addRange(nodes_coordinates);
810 }
811 }
812
813 if (!m_is_binary)
814 _goToNextLine();
815}
816
817/*---------------------------------------------------------------------------*/
818/*---------------------------------------------------------------------------*/
824{
825 IosFile* ios_file = m_ios_file.get();
826 IParallelMng* pm = m_parallel_mng;
827 const Int32 my_rank = pm->commRank();
828 const Int64 nb_entity_in_block = block.nb_entity;
829 const Int32 item_nb_node = block.item_nb_node;
830
831 info() << "Reading block nb_entity=" << nb_entity_in_block << " item_nb_node=" << item_nb_node;
832
834 UniqueArray<Int64> connectivities;
835
837
838 for (Int32 i_part = 0; i_part < m_nb_part; ++i_part) {
840 const Int32 dest_rank = m_parts_rank[i_part];
841
842 info() << "Reading block part i_part=" << i_part
843 << " nb_to_read=" << nb_to_read << " dest_rank=" << dest_rank;
844
845 const Int64 nb_uid = nb_to_read;
846 const Int64 nb_connectivity = nb_uid * item_nb_node;
847 if (my_rank == dest_rank || my_rank == m_master_io_rank) {
848 uids.resize(nb_uid);
849 connectivities.resize(nb_connectivity);
850 }
851 if (ios_file) {
852 if (m_is_binary) {
853 Int64 nb_to_read = nb_uid * (item_nb_node + 1);
855 ios_file->binaryRead(tmp_uid_and_connectivities.view());
856 Int64 index = 0;
857 for (Int64 i = 0; i < nb_uid; ++i) {
859 ++index;
860 uids[i] = item_unique_id;
861 for (Int32 j = 0; j < item_nb_node; ++j) {
862 connectivities[(i * item_nb_node) + j] = tmp_uid_and_connectivities[index];
863 ++index;
864 }
865 }
866 }
867 else {
868 // Utilise des Int64 pour garantir qu'on ne déborde pas.
869 for (Int64 i = 0; i < nb_uid; ++i) {
870 Int64 item_unique_id = ios_file->getInt64();
871 uids[i] = item_unique_id;
872 for (Int32 j = 0; j < item_nb_node; ++j)
873 connectivities[(i * item_nb_node) + j] = ios_file->getInt64();
874 }
875 }
876 if (dest_rank != m_master_io_rank) {
877 pm->send(uids, dest_rank);
878 pm->send(connectivities, dest_rank);
879 }
880 }
881 else if (my_rank == dest_rank) {
882 pm->recv(uids, m_master_io_rank);
883 pm->recv(connectivities, m_master_io_rank);
884 }
885 if (my_rank == dest_rank) {
886 block.uids.addRange(uids);
887 block.connectivities.addRange(connectivities);
888 }
889 }
890}
891
892/*---------------------------------------------------------------------------*/
893/*---------------------------------------------------------------------------*/
924{
925 IosFile* ios_file = m_ios_file.get();
926 IParallelMng* pm = m_parallel_mng;
927
929 _getInt64ArrayAndBroadcast(elements_info.view());
930
931 Int64 nb_block = elements_info[0];
935
936 if (!m_is_binary)
937 _goToNextLine();
938
939 info() << "[Elements] nb_block=" << nb_block
940 << " nb_elements=" << number_of_elements
941 << " min_element_tag=" << min_element_tag
942 << " max_element_tag=" << max_element_tag;
943
944 if (number_of_elements < 0)
945 ARCANE_THROW(IOException, "Invalid number of elements: {0}", number_of_elements);
946
947 UniqueArray<MeshV4ElementsBlock>& blocks = m_mesh_info.blocks;
948 blocks.resize(nb_block);
949
950 {
951 // Numérote les blocs (pour le débug)
952 Integer index = 0;
953 for (MeshV4ElementsBlock& block : blocks) {
954 block.index = index;
955 ++index;
956 }
957 }
958
959 for (MeshV4ElementsBlock& block : blocks) {
960
962 _getInt32ArrayAndBroadcast(block_info.view());
963
964 Int32 entity_dim = block_info[0];
965 Int32 entity_tag = block_info[1];
966 Int32 entity_type = block_info[2];
967 Int64 nb_entity_in_block = _getInt64AndBroadcast();
968
969 Integer item_nb_node = 0;
970 Integer item_type = _switchMshType(entity_type, item_nb_node);
971
972 info() << "[Elements] index=" << block.index << " entity_dim=" << entity_dim
973 << " entity_tag=" << entity_tag
974 << " entity_type=" << entity_type << " nb_in_block=" << nb_entity_in_block
975 << " item_type=" << item_type << " item_nb_node=" << item_nb_node;
976
977 block.nb_entity = nb_entity_in_block;
978 block.item_type = item_type;
979 block.item_nb_node = item_nb_node;
980 block.dimension = entity_dim;
981 block.entity_tag = entity_tag;
982
983 if (entity_type == MSH_PNT) {
984 // Si le type est un point, le traitement semble un peu particulier.
985 // Il y a dans ce cas deux entiers dans la ligne suivante:
986 // - un entier qui ne semble pas être utilisé
987 // - le numéro unique du noeud qui nous intéresse
988 Int64 item_unique_id = NULL_ITEM_UNIQUE_ID;
989 if (ios_file) {
990 [[maybe_unused]] Int64 unused_id = _getInt64();
991 item_unique_id = _getInt64();
992 info() << "Adding unique node uid=" << item_unique_id;
993 }
994 if (m_is_parallel)
995 pm->broadcast(ArrayView<Int64>(1, &item_unique_id), m_master_io_rank);
996 block.uids.add(item_unique_id);
997 }
998 else {
1000 }
1001 if (!m_is_binary)
1002 _goToNextLine();
1003 }
1004
1005 if (m_is_binary)
1006 _goToNextLine();
1007
1008 // Maintenant qu'on a tout les blocs, la dimension du maillage est
1009 // la plus grande dimension des blocs
1010 Integer mesh_dimension = -1;
1011 for (const MeshV4ElementsBlock& block : blocks)
1012 mesh_dimension = math::max(mesh_dimension, block.dimension);
1013 if (mesh_dimension < 0)
1014 ARCANE_FATAL("Invalid computed mesh dimension '{0}'", mesh_dimension);
1015 if (mesh_dimension != 2 && mesh_dimension != 3)
1016 ARCANE_THROW(NotSupportedException, "mesh dimension '{0}'. Only 2D or 3D meshes are supported", mesh_dimension);
1017 info() << "Computed mesh dimension = " << mesh_dimension;
1018
1019 for (MeshV4ElementsBlock& block : blocks) {
1020 if (block.dimension == mesh_dimension)
1021 _computeOwnCells(block);
1022 }
1023
1024 return mesh_dimension;
1025}
1026
1027/*---------------------------------------------------------------------------*/
1028/*---------------------------------------------------------------------------*/
1029
1030namespace
1031{
1032 template <typename DataType> inline ArrayView<DataType>
1034 UniqueArray<DataType>& work_values, Int32 dest_rank, Int64 size)
1035 {
1036 const Int32 my_rank = pm->commRank();
1037 ArrayView<DataType> view = values.view();
1038 if (my_rank != dest_rank) {
1039 work_values.resize(size);
1040 view = work_values.view();
1041 }
1042 pm->broadcast(view, dest_rank);
1043 return view;
1044 }
1052 template <typename DataType> inline ArrayView<DataType>
1053 _broadcastArray(IParallelMng* pm, UniqueArray<DataType>& values,
1054 UniqueArray<DataType>& work_values, Int32 dest_rank)
1055 {
1056 const Int32 my_rank = pm->commRank();
1057 Int64 size = 0;
1058 // Envoie la taille
1059 if (dest_rank == my_rank)
1060 size = values.size();
1061 pm->broadcast(ArrayView<Int64>(1, &size), dest_rank);
1062 return _broadcastArrayWithSize(pm, values, work_values, dest_rank, size);
1063 }
1064
1065} // namespace
1066
1067void MshParallelMeshReader::
1068_computeOwnCells(MeshV4ElementsBlock& block)
1069{
1070 // On ne conserve que les mailles dont le premier noeud appartient à notre rang.
1071
1072 IParallelMng* pm = m_parallel_mng;
1073 const Int32 my_rank = pm->commRank();
1074
1075 const Int32 item_type = block.item_type;
1076 const Int32 item_nb_node = block.item_nb_node;
1077
1078 UniqueArray<Int64> connectivities;
1079 UniqueArray<Int64> uids;
1080 UniqueArray<Int32> nodes_rank;
1081
1082 const Int32 nb_part = m_parts_rank.size();
1083 for (Int32 i_part = 0; i_part < nb_part; ++i_part) {
1084 const Int32 dest_rank = m_parts_rank[i_part];
1085 // Broadcast la i_part-ème partie des uids et connectivités des mailles
1086 ArrayView<Int64> connectivities_view = _broadcastArray(pm, block.connectivities, connectivities, dest_rank);
1087 ArrayView<Int64> uids_view = _broadcastArray(pm, block.uids, uids, dest_rank);
1088
1089 Int32 nb_item = uids_view.size();
1090 nodes_rank.resize(nb_item);
1091 nodes_rank.fill(-1);
1092
1093 // Parcours les mailles. Chaque maille appartiendra au rang
1094 // de son premier noeud. Si cette partie correspond à mon rang, alors
1095 // on conserve la maille.
1096 for (Int32 i = 0; i < nb_item; ++i) {
1097 Int64 first_node_uid = connectivities_view[i * item_nb_node];
1098 auto x = m_mesh_info.nodes_rank_map.find(first_node_uid);
1099 if (x == m_mesh_info.nodes_rank_map.end())
1100 // Le noeud n'est pas dans ma liste
1101 continue;
1102 Int32 rank = x->second;
1103 nodes_rank[i] = rank;
1104 }
1105 pm->reduce(Parallel::ReduceMax, nodes_rank);
1106 for (Int32 i = 0; i < nb_item; ++i) {
1107 const Int32 rank = nodes_rank[i];
1108 if (rank != my_rank)
1109 // Le noeud n'est pas dans ma partie
1110 continue;
1111 // Le noeud est chez moi, j'ajoute ma maille à la liste des
1112 // mailles que je vais créer.
1113 m_mesh_info.cells_type.add(item_type);
1114 m_mesh_info.cells_nb_node.add(item_nb_node);
1115 m_mesh_info.cells_uid.add(uids_view[i]);
1116 auto v = connectivities_view.subView(i * item_nb_node, item_nb_node);
1117 m_mesh_info.cells_connectivity.addRange(v);
1118 }
1119 }
1120}
1121
1122/*---------------------------------------------------------------------------*/
1123/*---------------------------------------------------------------------------*/
1140{
1144
1145 IParallelMng* pm = m_parallel_mng;
1146
1147 const IItemFamily* node_family = m_mesh->nodeFamily();
1149
1150 for (Int32 dest_rank : m_parts_rank) {
1153
1154 Int32 nb_item = uids.size();
1155 local_ids.resize(nb_item);
1156
1157 // Converti les uniqueId() en localId(). S'ils sont non nuls
1158 // c'est que l'entité est dans mon sous-domaine et donc on peut
1159 // positionner sa coordonnée
1160 node_family->itemsUniqueIdToLocalId(local_ids, uids, false);
1161 for (Int32 i = 0; i < nb_item; ++i) {
1163 if (!nid.isNull())
1164 nodes_coord_var[nid] = coords[i];
1165 }
1166 }
1167}
1168
1169/*---------------------------------------------------------------------------*/
1170/*---------------------------------------------------------------------------*/
1171
1172void MshParallelMeshReader::
1173_allocateCells()
1174{
1175 // TODO: Allouer par bloc de 100000 mailles pour éviter de faire
1176 // une trop grosse allocation
1177 IMesh* mesh = m_mesh;
1178 Integer nb_elements = m_mesh_info.cells_type.size();
1179 info() << "nb_of_elements=cells_type.size()=" << nb_elements;
1180 Integer nb_cell_node = m_mesh_info.cells_connectivity.size();
1181 info() << "nb_cell_node=cells_connectivity.size()=" << nb_cell_node;
1182
1183 // Création des mailles
1184 info() << "Building cells, nb_cell=" << nb_elements << " nb_cell_node=" << nb_cell_node;
1185 // Infos pour la création des mailles
1186 // par maille: 1 pour son unique id,
1187 // 1 pour son type,
1188 // 1 pour chaque noeud
1190 Int32 connectivity_index = 0;
1192 for (Integer i = 0; i < nb_elements; ++i) {
1193 Integer current_cell_nb_node = m_mesh_info.cells_nb_node[i];
1194 Integer cell_type = m_mesh_info.cells_type[i];
1195 Int64 cell_uid = m_mesh_info.cells_uid[i];
1197 cells_infos.add(cell_uid); //cell_unique_id
1198
1199 ArrayView<Int64> local_info(current_cell_nb_node, &m_mesh_info.cells_connectivity[connectivity_index]);
1200 cells_infos.addRange(local_info);
1202 }
1203
1204 IPrimaryMesh* pmesh = mesh->toPrimaryMesh();
1205 info() << "## Allocating ##";
1206 pmesh->allocateCells(nb_elements, cells_infos, false);
1207 info() << "## Ending ##";
1208 pmesh->endAllocate();
1209 info() << "## Done ##";
1210
1211 // Positionne les coordonnées des noeuds
1213}
1214
1215/*---------------------------------------------------------------------------*/
1216/*---------------------------------------------------------------------------*/
1217
1218void MshParallelMeshReader::
1219_allocateGroups()
1220{
1221 IMesh* mesh = m_mesh;
1222 Int32 mesh_dim = mesh->dimension();
1223 Int32 face_dim = mesh_dim - 1;
1224 UniqueArray<MeshV4EntitiesWithNodes> entity_list;
1225 UniqueArray<MeshPhysicalName> physical_name_list;
1226 for (MeshV4ElementsBlock& block : m_mesh_info.blocks) {
1227 entity_list.clear();
1228 physical_name_list.clear();
1229 Int32 block_index = block.index;
1230 Int32 block_dim = block.dimension;
1231 // On alloue un groupe s'il a un nom physique associé.
1232 // Pour cela, il faut déjà qu'il soit associé à une entité.
1233 Int64 block_entity_tag = block.entity_tag;
1234 if (block_entity_tag < 0) {
1235 info(5) << "[Groups] Skipping block index=" << block_index << " because it has no entity";
1236 continue;
1237 }
1238 if (block_dim == 0) {
1239 const MeshV4EntitiesNodes* entity = m_mesh_info.findNodeEntities(block_entity_tag);
1240 if (!entity) {
1241 info(5) << "[Groups] Skipping block index=" << block_index
1242 << " because entity tag is invalid";
1243 continue;
1244 }
1245 Int64 entity_physical_tag = entity->physical_tag;
1246 MeshPhysicalName physical_name = m_mesh_info.physical_name_list.find(block_dim, entity_physical_tag);
1247 physical_name_list.add(physical_name);
1248 }
1249 else {
1250 m_mesh_info.findEntities(block_dim, block_entity_tag, entity_list);
1251 for (const MeshV4EntitiesWithNodes& x : entity_list) {
1252 Int64 entity_physical_tag = x.physical_tag;
1253 MeshPhysicalName physical_name = m_mesh_info.physical_name_list.find(block_dim, entity_physical_tag);
1254 physical_name_list.add(physical_name);
1255 }
1256 }
1257 for (const MeshPhysicalName& physical_name : physical_name_list) {
1258 if (physical_name.isNull()) {
1259 info(5) << "[Groups] Skipping block index=" << block_index
1260 << " because entity physical tag is invalid";
1261 continue;
1262 }
1263 info(4) << "[Groups] Block index=" << block_index << " dim=" << block_dim
1264 << " name='" << physical_name.name << "'";
1265 if (block_dim == mesh_dim) {
1266 _addCellOrNodeGroup(block, physical_name.name, mesh->cellFamily());
1267 }
1268 else if (block_dim == face_dim) {
1269 _addFaceGroup(block, physical_name.name);
1270 }
1271 else {
1272 _addCellOrNodeGroup(block, physical_name.name, mesh->nodeFamily());
1273 }
1274 }
1275 }
1276}
1277
1278/*---------------------------------------------------------------------------*/
1279/*---------------------------------------------------------------------------*/
1285{
1286 IParallelMng* pm = m_parallel_mng;
1287 const Int32 item_nb_node = block.item_nb_node;
1288
1289 UniqueArray<Int64> connectivities;
1290 for (Int32 dest_rank : m_parts_rank) {
1292 _addFaceGroupOnePart(connectivities_view, item_nb_node, group_name, block.index);
1293 }
1294}
1295
1296/*---------------------------------------------------------------------------*/
1297/*---------------------------------------------------------------------------*/
1298
1299void MshParallelMeshReader::
1300_addFaceGroupOnePart(ConstArrayView<Int64> connectivities, Int32 item_nb_node,
1301 const String& group_name, Int32 block_index)
1302{
1303 IMesh* mesh = m_mesh;
1304 const Int32 nb_entity = connectivities.size() / item_nb_node;
1305
1306 // Il peut y avoir plusieurs blocs pour le même groupe.
1307 // On récupère le groupe s'il existe déjà.
1308 FaceGroup face_group = mesh->faceFamily()->findGroup(group_name, true);
1309
1310 UniqueArray<Int32> faces_id; // Numéro de la face dans le maillage \a mesh
1311 faces_id.reserve(nb_entity);
1312
1313 const Int32 face_nb_node = nb_entity * item_nb_node;
1314
1318 Integer faces_nodes_unique_id_index = 0;
1319
1320 UniqueArray<Int64> orig_nodes_id(item_nb_node);
1322
1325
1326 // Réordonne les identifiants des faces retrouver la face dans le maillage
1327 for (Integer i_face = 0; i_face < nb_entity; ++i_face) {
1328 for (Integer z = 0; z < item_nb_node; ++z)
1329 orig_nodes_id[z] = connectivities[faces_nodes_unique_id_index + z];
1330
1331 MeshUtils::reorderNodesOfFace2(orig_nodes_id, face_nodes_index);
1332 for (Integer z = 0; z < item_nb_node; ++z)
1335 faces_nodes_unique_id_index += item_nb_node;
1336 }
1337
1338 node_family->itemsUniqueIdToLocalId(faces_first_node_local_id, faces_first_node_unique_id, false);
1339
1340 faces_nodes_unique_id_index = 0;
1341 for (Integer i_face = 0; i_face < nb_entity; ++i_face) {
1342 const Integer n = item_nb_node;
1343 Int32 face_first_node_lid = faces_first_node_local_id[i_face];
1344 if (face_first_node_lid != NULL_ITEM_LOCAL_ID) {
1345 Int64ConstArrayView face_nodes_id(item_nb_node, &faces_nodes_unique_id[faces_nodes_unique_id_index]);
1346 Node current_node(mesh_nodes[faces_first_node_local_id[i_face]]);
1347 Face face = MeshUtils::getFaceFromNodesUnique(current_node, face_nodes_id);
1348
1349 // En parallèle, il est possible que la face ne soit pas dans notre sous-domaine
1350 // même si un de ses noeuds l'est
1351 if (face.null()) {
1352 if (!m_is_parallel) {
1353 OStringStream ostr;
1354 ostr() << "(Nodes:";
1355 for (Integer z = 0; z < n; ++z)
1356 ostr() << ' ' << face_nodes_id[z];
1357 ostr() << " - " << current_node.localId() << ")";
1358 ARCANE_FATAL("INTERNAL: MeshMeshReader face index={0} with nodes '{1}' is not in node/face connectivity",
1359 i_face, ostr.str());
1360 }
1361 }
1362 else
1363 faces_id.add(face.localId());
1364 }
1365
1366 faces_nodes_unique_id_index += n;
1367 }
1368 info(4) << "Adding " << faces_id.size() << " faces from block index=" << block_index
1369 << " to group '" << face_group.name() << "'";
1370 face_group.addItems(faces_id);
1371}
1372
1373/*---------------------------------------------------------------------------*/
1374/*---------------------------------------------------------------------------*/
1380{
1381 IParallelMng* pm = m_parallel_mng;
1382
1383 UniqueArray<Int64> uids;
1384 for (Int32 dest_rank : m_parts_rank) {
1385 ArrayView<Int64> uids_view = _broadcastArray(pm, block.uids, uids, dest_rank);
1386 _addCellOrNodeGroupOnePart(uids_view, group_name, block.index, family);
1387 }
1388}
1389
1390/*---------------------------------------------------------------------------*/
1391/*---------------------------------------------------------------------------*/
1392
1393void MshParallelMeshReader::
1394_addCellOrNodeGroupOnePart(ConstArrayView<Int64> uids, const String& group_name,
1395 Int32 block_index, IItemFamily* family)
1396{
1397 const Int32 nb_entity = uids.size();
1398
1399 // Il peut y avoir plusieurs blocs pour le même groupe.
1400 // On récupère le groupe s'il existe déjà.
1401 ItemGroup group = family->findGroup(group_name, true);
1402
1403 UniqueArray<Int32> items_lid(nb_entity);
1404
1405 family->itemsUniqueIdToLocalId(items_lid, uids, false);
1406
1407 // En parallèle, il est possible que certaines entités du groupe ne soient
1408 // pas dans notre sous-domaine. Il faut les filtrer.
1409 if (m_is_parallel) {
1410 auto items_begin = items_lid.begin();
1411 Int64 new_size = std::remove(items_begin, items_lid.end(), NULL_ITEM_LOCAL_ID) - items_begin;
1412 items_lid.resize(new_size);
1413 }
1414
1415 info() << "Adding " << items_lid.size() << " items from block index=" << block_index
1416 << " to group '" << group_name << "' for family=" << family->name();
1417
1418 group.addItems(items_lid);
1419}
1420
1421/*---------------------------------------------------------------------------*/
1422/*---------------------------------------------------------------------------*/
1423/*
1424 * $PhysicalNames // same as MSH version 2
1425 * numPhysicalNames(ASCII int)
1426 * dimension(ASCII int) physicalTag(ASCII int) "name"(127 characters max)
1427 * ...
1428 * $EndPhysicalNames
1429 */
1430void MshParallelMeshReader::
1431_readPhysicalNames()
1432{
1433 // NOTE: même en binaire, la partie $PhysicalNames est écrite en ASCII.
1434 String quote_mark = "\"";
1435 Int32 nb_name = _getIntegerAndBroadcast();
1436 info() << "nb_physical_name=" << nb_name;
1437
1438 _goToNextLine();
1439
1440 for (Int32 i = 0; i < nb_name; ++i) {
1441 Int32 dim = _getIntegerAndBroadcast();
1442 Int32 tag = _getIntegerAndBroadcast();
1443 String s = _getNextLineAndBroadcast();
1444 if (dim < 0 || dim > 3)
1445 ARCANE_FATAL("Invalid value for physical name dimension dim={0}", dim);
1446 // Les noms des groupes peuvent commencer par des espaces et contiennent
1447 // des guillemets qu'il faut supprimer.
1449 if (s.startsWith(quote_mark))
1450 s = s.substring(1);
1451 if (s.endsWith(quote_mark))
1452 s = s.substring(0, s.length() - 1);
1453 m_mesh_info.physical_name_list.add(dim, tag, s);
1454 info(4) << "[PhysicalName] index=" << i << " dim=" << dim << " tag=" << tag << " name='" << s << "'";
1455 }
1456
1457 String s = _getNextLineAndBroadcast();
1458 if (s != "$EndPhysicalNames")
1459 ARCANE_FATAL("found '{0}' and expected '$EndPhysicalNames'", s);
1460}
1461
1462/*---------------------------------------------------------------------------*/
1463/*---------------------------------------------------------------------------*/
1496{
1497 IosFile* ios_file = m_ios_file.get();
1498
1500 _getInt64ArrayAndBroadcast(nb_dim_item.view());
1501
1502 info(4) << "[Entities] nb_0d=" << nb_dim_item[0] << " nb_1d=" << nb_dim_item[1]
1503 << " nb_2d=" << nb_dim_item[2] << " nb_3d=" << nb_dim_item[3];
1504 // Après le format, on peut avoir les entités mais cela est optionnel
1505 // Si elles sont présentes, on lit le fichier jusqu'à la fin de cette section.
1506 if (!m_is_binary)
1507 _goToNextLine();
1508
1509 for (Int64 i = 0; i < nb_dim_item[0]; ++i) {
1511 info() << "Reading entity index=" << i;
1512 if (ios_file) {
1513 Int32 tag = _getInt32();
1514 Real3 xyz = _getReal3();
1515 Int64 num_physical_tag = _getInt64();
1516 if (num_physical_tag > 1)
1517 ARCANE_FATAL("NotImplemented numPhysicalTag>1 (n={0}, index={1} xyz={2})",
1518 num_physical_tag, i, xyz);
1519
1520 Int32 physical_tag = -1;
1521 if (num_physical_tag == 1)
1522 physical_tag = _getInt32();
1523 info(4) << "[Entities] point tag=" << tag << " pos=" << xyz << " phys_tag=" << physical_tag;
1524
1525 tag_info[0] = tag;
1526 tag_info[1] = physical_tag;
1527 }
1528 m_parallel_mng->broadcast(tag_info.view(), m_master_io_rank);
1529 m_mesh_info.entities_nodes_list.add(MeshV4EntitiesNodes(tag_info[0], tag_info[1]));
1530 if (!m_is_binary)
1531 _goToNextLine();
1532 }
1533
1534 for (Int32 i_dim = 1; i_dim <= 3; ++i_dim)
1535 for (Int32 i = 0; i < nb_dim_item[i_dim]; ++i)
1536 _readOneEntity(i_dim);
1537
1538 // En binaire, il faut aller au début de la ligne suivante.
1539 if (m_is_binary)
1540 _goToNextLine();
1541 _readAndCheck("$EndEntities");
1542}
1543
1544/*---------------------------------------------------------------------------*/
1545/*---------------------------------------------------------------------------*/
1546
1547void MshParallelMeshReader::
1548_readOneEntity(Int32 entity_dim)
1549{
1550 IosFile* ios_file = m_ios_file.get();
1551
1552 // Infos pour les tags
1553 // [0] entity_dim
1554 // [1] tag
1555 // [2] nb_physical_tag
1556 // [3] physical_tag1
1557 // [4] physical_tag2
1558 // [5] ...
1561 if (ios_file) {
1562 Int32 tag = _getInt32();
1563 dim_and_tag_info[1] = tag;
1564 Real3 min_pos = _getReal3();
1565 Real3 max_pos = _getReal3();
1566 Int64 nb_physical_tag = _getInt64();
1567 if (nb_physical_tag >= 124)
1568 ARCANE_FATAL("NotImplemented numPhysicalTag>=124 (n={0})", nb_physical_tag);
1570 for (Int32 z = 0; z < nb_physical_tag; ++z) {
1571 Int32 physical_tag = _getInt32();
1572 dim_and_tag_info[3 + z] = physical_tag;
1573 info(4) << "[Entities] z=" << z << " physical_tag=" << physical_tag;
1574 }
1575 // TODO: Lire les informations numBounding...
1576 Int64 num_bounding_group = _getInt64();
1577 for (Int64 k = 0; k < num_bounding_group; ++k) {
1578 [[maybe_unused]] Int32 group_tag = _getInt32();
1579 }
1580 info(4) << "[Entities] dim=" << entity_dim << " tag=" << tag
1581 << " min_pos=" << min_pos << " max_pos=" << max_pos
1582 << " nb_phys_tag=" << nb_physical_tag;
1583 }
1584
1585 m_parallel_mng->broadcast(dim_and_tag_info.view(), m_master_io_rank);
1586
1587 {
1588 Int32 dim = CheckedConvert::toInt32(dim_and_tag_info[0]);
1589 Int64 tag = dim_and_tag_info[1];
1590 Int64 nb_physical_tag = dim_and_tag_info[2];
1591 for (Int32 z = 0; z < nb_physical_tag; ++z) {
1592 Int64 physical_tag = dim_and_tag_info[3 + z];
1593 info(4) << "[Entities] adding info dim=" << entity_dim << " tag=" << tag
1594 << " physical_tag=" << physical_tag;
1595 m_mesh_info.entities_with_nodes_list[dim - 1].add(MeshV4EntitiesWithNodes(dim, tag, physical_tag));
1596 }
1597 }
1598
1599 if (!m_is_binary)
1600 _goToNextLine();
1601}
1602
1603/*---------------------------------------------------------------------------*/
1604/*---------------------------------------------------------------------------*/
1624{
1625 Int64 nb_link = _getInt64AndBroadcast();
1626 info() << "[Periodic] nb_link=" << nb_link;
1627
1628 // TODO: pour l'instant, tous les rangs conservent les
1629 // données car on suppose qu'il n'y en a pas beaucoup.
1630 // A terme, il faudra aussi distribuer ces informations.
1631 PeriodicInfo& periodic_info = m_mesh_info.m_periodic_info;
1632 periodic_info.m_periodic_list.resize(nb_link);
1633 for (Int64 ilink = 0; ilink < nb_link; ++ilink) {
1634 PeriodicOneInfo& one_info = periodic_info.m_periodic_list[ilink];
1636 _getInt32ArrayAndBroadcast(entity_info.view());
1637
1638 info() << "[Periodic] dim=" << entity_info[0] << " tag=" << entity_info[1]
1639 << " tag_master=" << entity_info[2];
1640 one_info.m_entity_dim = entity_info[0];
1641 one_info.m_entity_tag = entity_info[1];
1642 one_info.m_entity_tag_master = entity_info[2];
1643
1644 Int64 num_affine = _getInt64AndBroadcast();
1645 info() << "[Periodic] num_affine=" << num_affine;
1646 one_info.m_affine_values.resize(num_affine);
1647 _getDoubleArrayAndBroadcast(one_info.m_affine_values);
1648 one_info.m_nb_corresponding_node = CheckedConvert::toInt32(_getInt64AndBroadcast());
1649 info() << "[Periodic] nb_corresponding_node=" << one_info.m_nb_corresponding_node;
1650 one_info.m_corresponding_nodes.resize(one_info.m_nb_corresponding_node * 2);
1651 _getInt64ArrayAndBroadcast(one_info.m_corresponding_nodes);
1652 //info() << "[Periodic] corresponding_nodes=" << corresponding_nodes;
1653 }
1654
1655 _goToNextLine();
1656
1658 if (s != "$EndPeriodic")
1659 ARCANE_FATAL("found '{0}' and expected '$EndPeriodic'", s);
1660}
1661
1662/*---------------------------------------------------------------------------*/
1663/*---------------------------------------------------------------------------*/
1669{
1670 String s;
1671 if (m_is_binary) {
1672 constexpr Int32 MAX_SIZE = 128;
1676 SmallSpan<Byte> bytes_to_read = buf_bytes.span().subSpan(0, read_size);
1677 if (read_size >= MAX_SIZE)
1678 ARCANE_FATAL("local buffer is too small (size={0} max={1})", read_size, MAX_SIZE);
1679 IosFile* f = m_ios_file.get();
1680 if (f) {
1681 f->binaryRead(bytes_to_read);
1682 s = String(bytes_to_read);
1683 info() << "S=" << s;
1684 if (m_is_parallel) {
1685 m_parallel_mng->broadcastString(s, m_master_io_rank);
1686 }
1687 }
1688 _goToNextLine();
1689 }
1690 else {
1692 }
1693 if (s != expected_value)
1694 ARCANE_FATAL("found '{0}' and expected '{1}'", s, expected_value);
1695}
1696
1697/*---------------------------------------------------------------------------*/
1698/*---------------------------------------------------------------------------*/
1701void MshParallelMeshReader::
1702_readMeshFromFile()
1703{
1704 IosFile* ios_file = m_ios_file.get();
1705 IMesh* mesh = m_mesh;
1706 info() << "Reading 'msh' file in parallel";
1707
1708 const int MSH_BINARY_TYPE = 1;
1709
1710 if (ios_file) {
1711 Real version = ios_file->getReal();
1712 if (version != 4.1)
1713 ARCANE_THROW(IOException, "Wrong msh file version '{0}'. Only version '4.1' is supported in parallel", version);
1714 Integer file_type = ios_file->getInteger(); // is an integer equal to 0 in the ASCII file format, equal to 1 for the binary format
1715 if (file_type == MSH_BINARY_TYPE)
1716 m_is_binary = true;
1717 info() << "IsBinary?=" << m_is_binary;
1718 if (m_is_binary)
1719 pwarning() << "MSH reader for binary format is experimental";
1720 Int32 data_size = ios_file->getInteger(); // is an integer equal to the size of the floating point numbers used in the file
1721 ARCANE_UNUSED(data_size);
1722 if (data_size != 8)
1723 ARCANE_FATAL("Only 'size_t' of size '8' is allowed (current size is '{0}')", data_size);
1724 // En binaire, il a un entier à lire qui vaut 1 et qui permet de savoir si on n'est en big/little endian.
1725 if (m_is_binary) {
1726 // Il faut lire jusqu'à la fin de la ligne pour le binaire.
1727 _goToNextLine();
1728 Int32 int_value_one = 0;
1729 ios_file->binaryRead(SmallSpan<Int32>(&int_value_one, 1));
1730 if (int_value_one != 1)
1731 ARCANE_FATAL("Bad endianess for file. Read int as value '{0}' (expected=1)", int_value_one);
1732 }
1733
1734 ios_file->getNextLine(); // Skip current \n\r
1735
1736 // $EndMeshFormat
1737 if (!ios_file->lookForString("$EndMeshFormat"))
1738 ARCANE_THROW(IOException, "$EndMeshFormat not found");
1739 }
1740
1741 // TODO: Les différentes sections ($Nodes, $Entitites, ...) peuvent
1742 // être dans n'importe quel ordre (à part $Nodes qui doit être avant $Elements)
1743 // Faire un méthode qui gère cela.
1744
1745 String next_line = _getNextLineAndBroadcast();
1746 // Noms des groupes
1747 if (next_line == "$PhysicalNames") {
1748 _readPhysicalNames();
1749 next_line = _getNextLineAndBroadcast();
1750 }
1751
1752 // Après le format, on peut avoir les entités mais cela est optionnel
1753 // Si elles sont présentes, on lit le fichier jusqu'à la fin de cette section.
1754 if (next_line == "$Entities") {
1755 _readEntities();
1756 next_line = _getNextLineAndBroadcast();
1757 }
1758 // $Nodes
1759 if (next_line != "$Nodes")
1760 ARCANE_THROW(IOException, "Unexpected string '{0}'. Valid values are '$Nodes'", next_line);
1761
1762 // Fetch nodes number and the coordinates
1764
1765 // $EndNodes
1766 if (ios_file && !ios_file->lookForString("$EndNodes"))
1767 ARCANE_THROW(IOException, "$EndNodes not found");
1768
1769 // $Elements
1770 if (ios_file && !ios_file->lookForString("$Elements"))
1771 ARCANE_THROW(IOException, "$Elements not found");
1772
1773 Int32 mesh_dimension = _readElementsFromFile();
1774
1775 // $EndElements
1776 if (ios_file && !ios_file->lookForString("$EndElements"))
1777 ARCANE_THROW(IOException, "$EndElements not found");
1778
1779 info() << "Computed mesh dimension = " << mesh_dimension;
1780
1781 IPrimaryMesh* pmesh = mesh->toPrimaryMesh();
1782 pmesh->setDimension(mesh_dimension);
1783
1784 info() << "NextLine=" << next_line;
1785
1786 bool is_end = _getIsEndOfFileAndBroadcast();
1787 if (!is_end) {
1788 next_line = _getNextLineAndBroadcast();
1789 // $Periodic
1790 if (next_line == "$Periodic") {
1791 _readPeriodic();
1792 }
1793 }
1794
1795 _allocateCells();
1796 _allocateGroups();
1797}
1798
1799/*---------------------------------------------------------------------------*/
1800/*---------------------------------------------------------------------------*/
1805readMeshFromMshFile(IMesh* mesh, const String& filename)
1806{
1807 info() << "Trying to read in parallel 'msh' file '" << filename;
1808 m_mesh = mesh;
1809 IParallelMng* pm = mesh->parallelMng();
1810 m_parallel_mng = pm;
1811 const Int32 nb_rank = pm->commSize();
1812
1813 // Détermine les rangs qui vont conserver les données
1814 // Il n'est pas obligatoire que tous les rangs participent
1815 // à la conservation des données. L'idéal avec un
1816 // grand nombre de rangs serait qu'un rang sur 2 ou 4 participent.
1817 // Cependant, cela génère alors des partitions vides (pour
1818 // les rangs qui ne participent pas) et cela peut
1819 // faire planter certains partitionneurs (comme ParMetis)
1820 // lorsqu'il y a des partitions vides. Il faudrait d'abord
1821 // corriger ce problème.
1822 m_nb_part = nb_rank;
1824 for (Int32 i = 0; i < m_nb_part; ++i) {
1825 m_parts_rank[i] = i % nb_rank;
1826 }
1827
1828 bool is_master_io = pm->isMasterIO();
1829 Int32 master_io_rank = pm->masterIORank();
1830 m_is_parallel = pm->isParallel();
1831 m_master_io_rank = master_io_rank;
1833 // Seul le rang maître va lire le fichier.
1834 // On vérifie d'abord qu'il est lisible
1835 if (is_master_io) {
1836 bool is_readable = platform::isFileReadable(filename);
1837 info() << "Is file readable ?=" << is_readable;
1838 file_readable[0] = is_readable ? 1 : 0;
1839 if (!is_readable)
1840 error() << "Unable to read file '" << filename << "'";
1841 }
1842 pm->broadcast(file_readable.view(), master_io_rank);
1843 if (file_readable[0] == 0) {
1844 return IMeshReader::RTError;
1845 }
1846
1847 std::ifstream ifile;
1849 if (is_master_io) {
1850 ifile.open(filename.localstr());
1852 }
1853 m_ios_file = ios_file;
1855 if (IosFile::isEqualString(mesh_format_str, "$MeshFormat")) {
1856 _readMeshFromFile();
1857 return IMeshReader::RTOk;
1858 }
1859
1860 info() << "The file does not begin with '$MeshFormat' returning RTError";
1861 return IMeshReader::RTError;
1862}
1863
1864/*---------------------------------------------------------------------------*/
1865/*---------------------------------------------------------------------------*/
1866
1867extern "C++" Ref<IMshMeshReader>
1868createMshParallelMeshReader(ITraceMng* tm)
1869{
1871}
1872
1873/*---------------------------------------------------------------------------*/
1874/*---------------------------------------------------------------------------*/
1875
1876} // End namespace Arcane
1877
1878/*---------------------------------------------------------------------------*/
1879/*---------------------------------------------------------------------------*/
#define ARCANE_CHECK_POINTER(ptr)
Macro retournant le pointeur ptr s'il est non nul ou lancant une exception s'il est nul.
#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:33
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:149
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.
bool _getIsEndOfFileAndBroadcast()
Retourne true si on est à la fin du fichier.
void _readPeriodic()
Lecture des informations périodiques.
void _addFaceGroup(MeshV4ElementsBlock &block, const String &group_name)
Ajoute des faces au groupe group_name.
Integer _readElementsFromFile()
Lecture des éléments (mailles,faces,...)
void _readAndCheck(const String &expected_value)
Tente de lire la valeur value.
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 _readNodesFromFile()
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.
bool m_is_binary
Vrai si le format est binaire.
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 pwarning() const
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:691
Infos d'un bloc pour $Elements pour la version 4.
UniqueArray< Int64 > connectivities
< Liste des uniqueId() du bloc