Arcane  v3.16.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-2025 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-2025 */
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/SmallArray.h"
24#include "arcane/utils/PlatformUtils.h"
25#include "arcane/utils/CheckedConvert.h"
26
27#include "arcane/core/IMeshReader.h"
28#include "arcane/core/IPrimaryMesh.h"
29#include "arcane/core/IItemFamily.h"
30#include "arcane/core/ItemGroup.h"
31#include "arcane/core/VariableTypes.h"
32#include "arcane/core/IParallelMng.h"
34#include "arcane/core/IMeshModifier.h"
35#include "arcane/core/MeshKind.h"
36#include "arcane/core/NodesOfItemReorderer.h"
37#include "arcane/core/internal/MshMeshGenerationInfo.h"
38
39// Element types in .msh file format, found in gmsh-2.0.4/Common/GmshDefines.h
40#include "arcane/std/internal/IosFile.h"
41#include "arcane/std/internal/IosGmsh.h"
42
43/*---------------------------------------------------------------------------*/
44/*---------------------------------------------------------------------------*/
45
46/*
47 * NOTES:
48 * - La bibliothèque `gmsh` fournit un script 'open.py' dans le répertoire
49 * 'demos/api' qui permet de générer un fichier '.msh' à partir d'un '.geo'.
50 * - Il est aussi possible d'utiliser directement l'exécutable 'gmsh' avec
51 * l'option '-save-all' pour sauver un fichier '.msh' à partir d'un '.geo'
52 *
53 * TODO:
54 * - supporter les partitions
55 * - pouvoir utiliser la bibliothèque 'gmsh' directement.
56 */
57
58/*---------------------------------------------------------------------------*/
59/*---------------------------------------------------------------------------*/
60
61namespace Arcane
62{
63
64/*---------------------------------------------------------------------------*/
65/*---------------------------------------------------------------------------*/
82class MshParallelMeshReader
83: public TraceAccessor
84, public IMshMeshReader
85{
86 public:
87
89 using MshEntitiesNodes = impl::MshMeshGenerationInfo::MshEntitiesNodes;
90 using MshEntitiesWithNodes = impl::MshMeshGenerationInfo::MshEntitiesWithNodes;
91 using MshPeriodicOneInfo = impl::MshMeshGenerationInfo::MshPeriodicOneInfo;
93
94 public:
95
96 using eReturnType = typename IMeshReader::eReturnType;
97
98 public:
99
101 class MshToArcaneTypeInfo
102 {
103 public:
104
105 MshToArcaneTypeInfo() = default;
106 MshToArcaneTypeInfo(Int32 msh_type, ItemTypeInfo* iti, ConstArrayView<Int16> reorder_infos)
107 : m_msh_type(msh_type)
108 , m_arcane_type_info(iti)
109 , m_reorder_infos(reorder_infos)
110 {
111 }
112
113 public:
114
115 Int32 m_msh_type = -1;
116 ItemTypeInfo* m_arcane_type_info = nullptr;
117 UniqueArray<Int16> m_reorder_infos;
118 };
119
143
156
161 {
162 // TODO: Allouer la connectivité par bloc pour éviter de trop grosses allocations
163
164 public:
165
166 void addItem(Int16 type_id, Int64 unique_id, SmallSpan<const Int64> nodes_uid)
167 {
168 ++nb_item;
169 items_infos.add(type_id);
170 items_infos.add(unique_id);
171 items_infos.addRange(nodes_uid);
172 }
173
174 public:
175
176 Int32 nb_item = 0;
177 UniqueArray<Int64> items_infos;
178 };
179
182 {
183 public:
184
185 MshItemKindInfo cells_infos;
186
192 std::unordered_map<Int64, Int32> nodes_rank_map;
193 UniqueArray<MshElementBlock> element_blocks;
194 UniqueArray<MshNodeBlock> node_blocks;
195 };
196
197 public:
198
199 explicit MshParallelMeshReader(ITraceMng* tm);
200
201 public:
202
203 eReturnType readMeshFromMshFile(IMesh* mesh, const String& filename, bool use_internal_partition) override;
204
205 private:
206
207 IMesh* m_mesh = nullptr;
208 IParallelMng* m_parallel_mng = nullptr;
209 Int32 m_master_io_rank = A_NULL_RANK;
210 bool m_is_parallel = false;
211 Ref<IosFile> m_ios_file; // nullptr sauf pour le rang maitre.
212 impl::MshMeshGenerationInfo* m_mesh_info = nullptr;
213 MshMeshAllocateInfo m_mesh_allocate_info;
219 bool m_is_binary = false;
224
225 private:
226
227 void _readNodesFromFile();
228 void _readNodesOneEntity(MshNodeBlock& node_block);
230 void _readMeshFromFile();
232 void _allocateCells();
233 void _allocateGroups();
234 void _addFaceGroup(const MshElementBlock& block, const String& group_name);
235 void _addFaceGroupOnePart(const MshElementBlock& block, ConstArrayView<Int64> connectivities, const String& group_name);
236 void _addCellOrNodeGroup(ArrayView<Int64> block_uids, Int32 block_index,
237 const String& group_name, IItemFamily* family, bool filter_invalid);
238 void _addCellOrNodeGroupOnePart(ConstArrayView<Int64> uids, const String& group_name,
239 Int32 block_index, IItemFamily* family, bool filter_invalid);
240 void _readPhysicalNames();
241 void _readEntities();
242 void _readPeriodic();
243 void _readOneEntity(Int32 entity_dim, Int32 entity_index_in_dim);
246 Int32 _getIntegerAndBroadcast();
247 Int64 _getInt64AndBroadcast();
248 void _getInt64ArrayAndBroadcast(ArrayView<Int64> values);
249 void _getInt32ArrayAndBroadcast(ArrayView<Int32> values);
250 void _getDoubleArrayAndBroadcast(ArrayView<double> values);
253 void _computeOwnItems(MshElementBlock& block, MshItemKindInfo& item_kind_info, bool is_generate_uid);
254 Real3 _getReal3();
255 Int32 _getInt32();
256 Int64 _getInt64();
257 void _goToNextLine();
258 void _readAndCheck(const String& expected_value);
259 void _addMshTypeInfo(Int32 msh_type, ItemTypeId arcane_type, ConstArrayView<Int16> reorder_infos = {});
260 const MshToArcaneTypeInfo& mshToArcaneTypeInfo(Int32 msh_type) const;
261 void _initTypes();
262};
263
264/*---------------------------------------------------------------------------*/
265/*---------------------------------------------------------------------------*/
266
267namespace
268{
275 inline std::pair<Int64, Int64>
276 _interval(Int32 index, Int32 nb_interval, Int64 size)
277 {
278 Int64 isize = size / nb_interval;
279 Int64 ibegin = index * isize;
280 // Pour le dernier interval, prend les elements restants
281 if ((index + 1) == nb_interval)
282 isize = size - ibegin;
283 return { ibegin, isize };
284 }
285} // namespace
286
287/*---------------------------------------------------------------------------*/
288/*---------------------------------------------------------------------------*/
289
290/*---------------------------------------------------------------------------*/
291/*---------------------------------------------------------------------------*/
292
293MshParallelMeshReader::
294MshParallelMeshReader(ITraceMng* tm)
295: TraceAccessor(tm)
296{
297 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_GMSH_VERBOSITY_LEVEL", true)) {
298 m_verbosity_level = v.value();
299 }
300}
301
302/*---------------------------------------------------------------------------*/
303/*---------------------------------------------------------------------------*/
304
305/*---------------------------------------------------------------------------*/
306/*---------------------------------------------------------------------------*/
312{
313 IosFile* f = m_ios_file.get();
314 String s;
315 if (f) {
316 s = f->getNextLine();
317 }
318 if (m_is_parallel) {
319 if (f)
320 info(4) << "BroadcastNextLine: " << s;
321 m_parallel_mng->broadcastString(s, m_master_io_rank);
322 }
323 info(4) << "GetNextLine: " << s;
324 return s;
325}
326
327/*---------------------------------------------------------------------------*/
328/*---------------------------------------------------------------------------*/
334{
335 IosFile* f = m_ios_file.get();
336 Int32 is_end_int = 0;
337 if (f) {
338 is_end_int = f->isEnd() ? 1 : 0;
339 info(4) << "IsEndOfFile_Master: " << is_end_int;
340 }
341 if (m_is_parallel) {
342 if (f)
343 info(4) << "IsEndOfFile: " << is_end_int;
344 m_parallel_mng->broadcast(ArrayView<Int32>(1, &is_end_int), m_master_io_rank);
345 }
346 bool is_end = (is_end_int != 0);
347 info(4) << "IsEnd: " << is_end;
348 return is_end;
349}
350
351/*---------------------------------------------------------------------------*/
352/*---------------------------------------------------------------------------*/
353
355//_getASCIIIntegerAndBroadcast()
356_getIntegerAndBroadcast()
357{
358 IosFile* f = m_ios_file.get();
360 if (f)
361 v[0] = f->getInteger();
362 if (m_is_parallel) {
363 m_parallel_mng->broadcast(v.view(), m_master_io_rank);
364 }
365 return v[0];
366}
367
368/*---------------------------------------------------------------------------*/
369/*---------------------------------------------------------------------------*/
370
371Int64 MshParallelMeshReader::
372_getInt64AndBroadcast()
373{
374 IosFile* f = m_ios_file.get();
375 FixedArray<Int64, 1> v;
376 if (f)
377 v[0] = _getInt64();
378 if (m_is_parallel) {
379 m_parallel_mng->broadcast(v.view(), m_master_io_rank);
380 }
381 return v[0];
382}
383
384/*---------------------------------------------------------------------------*/
385/*---------------------------------------------------------------------------*/
386
387void MshParallelMeshReader::
388_getInt64ArrayAndBroadcast(ArrayView<Int64> values)
389{
390 IosFile* f = m_ios_file.get();
391 if (f) {
392 if (m_is_binary) {
393 f->binaryRead(values);
394 }
395 else {
396 for (Int64& v : values)
397 v = f->getInt64();
398 }
399 }
400 if (m_is_parallel)
401 m_parallel_mng->broadcast(values, m_master_io_rank);
402}
403
404/*---------------------------------------------------------------------------*/
405/*---------------------------------------------------------------------------*/
406
407void MshParallelMeshReader::
408_getInt32ArrayAndBroadcast(ArrayView<Int32> values)
409{
410 IosFile* f = m_ios_file.get();
411 if (f) {
412 if (m_is_binary) {
413 f->binaryRead(values);
414 }
415 else {
416 for (Int32& v : values)
417 v = f->getInteger();
418 }
419 }
420 if (m_is_parallel)
421 m_parallel_mng->broadcast(values, m_master_io_rank);
422}
423
424/*---------------------------------------------------------------------------*/
425/*---------------------------------------------------------------------------*/
426
427void MshParallelMeshReader::
428_getDoubleArrayAndBroadcast(ArrayView<double> values)
429{
430 IosFile* f = m_ios_file.get();
431 if (f) {
432 if (m_is_binary) {
433 f->binaryRead(values);
434 }
435 else {
436 for (double& v : values)
437 v = f->getReal();
438 }
439 }
440 if (m_is_parallel)
441 m_parallel_mng->broadcast(values, m_master_io_rank);
442}
443
444/*---------------------------------------------------------------------------*/
445/*---------------------------------------------------------------------------*/
446
447Real3 MshParallelMeshReader::
448_getReal3()
449{
450 IosFile* f = m_ios_file.get();
452 Real3 v;
453 if (m_is_binary) {
454 f->binaryRead(SmallSpan<Real3>(&v, 1));
455 }
456 else {
457 Real x = f->getReal();
458 Real y = f->getReal();
459 Real z = f->getReal();
460 v = Real3(x, y, z);
461 }
462 return v;
463}
464
465/*---------------------------------------------------------------------------*/
466/*---------------------------------------------------------------------------*/
467
468Int32 MshParallelMeshReader::
469_getInt32()
470{
471 IosFile* f = m_ios_file.get();
473 Int32 v = 0;
474 if (m_is_binary)
475 f->binaryRead(SmallSpan<Int32>(&v, 1));
476 else
477 v = f->getInteger();
478 return v;
479}
480
481/*---------------------------------------------------------------------------*/
482/*---------------------------------------------------------------------------*/
483
484Int64 MshParallelMeshReader::
485_getInt64()
486{
487 IosFile* f = m_ios_file.get();
489 Int64 v = 0;
490 if (m_is_binary)
491 f->binaryRead(SmallSpan<Int64>(&v, 1));
492 else
493 v = f->getInt64();
494 return v;
495}
496
497/*---------------------------------------------------------------------------*/
498/*---------------------------------------------------------------------------*/
499
500void MshParallelMeshReader::
501_goToNextLine()
502{
503 if (m_ios_file.get())
504 m_ios_file->goToEndOfLine();
505}
506
507/*---------------------------------------------------------------------------*/
508/*---------------------------------------------------------------------------*/
509
512{
513 // Détermine la bounding box de la maille
514 Real max_value = FloatInfo<Real>::maxValue();
515 Real min_value = -max_value;
516 Real3 min_box(max_value, max_value, max_value);
517 Real3 max_box(min_value, min_value, min_value);
518 const Int64 nb_node = m_mesh_allocate_info.nodes_coordinates.largeSize();
519 for (Real3 pos : m_mesh_allocate_info.nodes_coordinates) {
520 min_box = math::min(min_box, pos);
521 max_box = math::max(max_box, pos);
522 }
523
525 UniqueArray<Int32> nodes_part(nb_node, 0);
526
527 // Pour la partition, on ne prend en compte que la coordonnée X.
528 // On est sur qu'elle est valable pour toutes les dimensions du maillage.
529 // On partitionne avec des intervalles de même longueur.
530 // NOTE: Cela fonctionne bien si l'ensemble des noeuds est bien réparti.
531 // Si ce n'est pas le cas on pourrait utiliser une bisection en coupant
532 // à chaque fois sur la moyenne.
533 Real min_x = min_box.x;
534 Real max_x = max_box.x;
535 IParallelMng* pm = m_parallel_mng;
536 Real global_min_x = pm->reduce(Parallel::ReduceMin, min_x);
537 Real global_max_x = pm->reduce(Parallel::ReduceMax, max_x);
538 info() << "MIN_MAX_X=" << global_min_x << " " << global_max_x;
539
540 Real diff_v = (global_max_x - global_min_x) / static_cast<Real>(m_nb_part);
541 // Ne devrait pas arriver mais c'est nécessaire pour éviter d'éventuelles
542 // divisions par zéro.
543 if (!math::isNearlyEqual(global_min_x, global_max_x)) {
544 for (Int64 i = 0; i < nb_node; ++i) {
545 Int32 part = static_cast<Int32>((m_mesh_allocate_info.nodes_coordinates[i].x - global_min_x) / diff_v);
546 part = std::clamp(part, 0, m_nb_part - 1);
547 nodes_part[i] = part;
548 }
549 }
550 UniqueArray<Int32> nb_node_per_rank(m_nb_part, 0);
551 // Construit la table de hashage des rangs
552 for (Int64 i = 0; i < nb_node; ++i) {
553 Int32 rank = m_parts_rank[nodes_part[i]];
554 Int64 uid = m_mesh_allocate_info.nodes_unique_id[i];
555 ++nb_node_per_rank[rank];
556 m_mesh_allocate_info.nodes_rank_map.insert(std::make_pair(uid, rank));
557 }
558 pm->reduce(Parallel::ReduceSum, nb_node_per_rank);
559 info() << "NB_NODE_PER_RANK=" << nb_node_per_rank;
560}
561
562/*---------------------------------------------------------------------------*/
563/*---------------------------------------------------------------------------*/
590{
591 FixedArray<Int64, 4> nodes_info;
592 _getInt64ArrayAndBroadcast(nodes_info.view());
593
594 Int64 nb_node_block = static_cast<Int32>(nodes_info[0]);
595 Int64 total_nb_node = nodes_info[1];
596 Int64 min_node_tag = nodes_info[2];
597 Int64 max_node_tag = nodes_info[3];
598
599 if (!m_is_binary)
600 _goToNextLine();
601
602 if (total_nb_node < 0)
603 ARCANE_THROW(IOException, "Invalid number of nodes : '{0}'", total_nb_node);
604
605 info() << "[Nodes] nb_node_block=" << nb_node_block
606 << " total_nb_node=" << total_nb_node
607 << " min_tag=" << min_node_tag
608 << " max_tag=" << max_node_tag
609 << " read_nb_part=" << m_nb_part
610 << " nb_rank=" << m_parallel_mng->commSize();
611
612 UniqueArray<MshNodeBlock>& node_blocks = m_mesh_allocate_info.node_blocks;
613 node_blocks.resize(nb_node_block);
614
615 for (Int32 i = 0; i < nb_node_block; ++i) {
616 MshNodeBlock& node_block = node_blocks[i];
617 node_block.index = i;
618 _readNodesOneEntity(node_block);
619 }
620
622
623 if (m_is_binary)
624 _goToNextLine();
625}
626
627/*---------------------------------------------------------------------------*/
628/*---------------------------------------------------------------------------*/
629
630void MshParallelMeshReader::
631_readNodesOneEntity(MshNodeBlock& node_block)
632{
633 IosFile* ios_file = m_ios_file.get();
634 IParallelMng* pm = m_parallel_mng;
635 const Int32 my_rank = pm->commRank();
636
637 UniqueArray<Int64> nodes_uids;
638 UniqueArray<Real3> nodes_coordinates;
639
640 FixedArray<Int32, 3> entity_infos;
641 _getInt32ArrayAndBroadcast(entity_infos.view());
642 Int32 nb_node2 = CheckedConvert::toInt32(_getInt64AndBroadcast());
643
644 if (!m_is_binary)
645 _goToNextLine();
646
647 // Dimension de l'entité (pas utile)
648 Int32 entity_dim = entity_infos[0];
649 node_block.entity_dim = entity_dim;
650 // Tag de l'entité associée
651 Int32 entity_tag = entity_infos[1];
652 node_block.entity_tag = entity_tag;
653
654 node_block.index_in_allocation_info = m_mesh_allocate_info.nodes_coordinates.size();
655 node_block.nb_node = nb_node2;
656
657 Int32 parametric_coordinates = entity_infos[2];
658
659 info(4) << "[Nodes] index=" << node_block.index << " entity_dim=" << entity_dim << " entity_tag=" << entity_tag
660 << " parametric=" << parametric_coordinates
661 << " nb_node2=" << nb_node2;
662
663 if (parametric_coordinates != 0)
664 ARCANE_THROW(NotSupportedException, "Only 'parametric coordinates' value of '0' is supported (current={0})", parametric_coordinates);
665
666 // Il est possible que le nombre de noeuds soit 0.
667 // Dans ce cas, il faut directement passer à la ligne suivante
668 if (nb_node2 == 0)
669 return;
670
671 // Partitionne la lecture en \a m_nb_part
672 // Pour chaque i_entity, on a d'abord la liste des identifiants puis la liste des coordonnées
673
674 for (Int32 i_part = 0; i_part < m_nb_part; ++i_part) {
675 Int64 nb_to_read = _interval(i_part, m_nb_part, nb_node2).second;
676 Int32 dest_rank = m_parts_rank[i_part];
677 info(4) << "Reading UIDS part i=" << i_part << " dest_rank=" << dest_rank << " nb_to_read=" << nb_to_read;
678 if (my_rank == dest_rank || my_rank == m_master_io_rank) {
679 nodes_uids.resize(nb_to_read);
680 }
681
682 // Le rang maitre lit les informations des noeuds pour la partie concernée
683 // et les transfère au rang destination
684 if (ios_file) {
685 if (m_is_binary) {
686 ios_file->binaryRead(nodes_uids.view());
687 }
688 else {
689 for (Integer i = 0; i < nb_to_read; ++i) {
690 // Conserve le uniqueId() du noeuds.
691 nodes_uids[i] = ios_file->getInt64();
692 //info() << "I=" << i << " ID=" << nodes_uids[i];
693 }
694 }
695 if (dest_rank != m_master_io_rank) {
696 pm->send(nodes_uids, dest_rank);
697 }
698 }
699 else if (my_rank == dest_rank) {
700 pm->recv(nodes_uids, m_master_io_rank);
701 }
702
703 // Conserve les informations de ma partie
704 if (my_rank == dest_rank) {
705 m_mesh_allocate_info.nodes_unique_id.addRange(nodes_uids);
706 }
707 }
708
709 // Lecture par partie des coordonnées
710 for (Int32 i_part = 0; i_part < m_nb_part; ++i_part) {
711 Int64 nb_to_read = _interval(i_part, m_nb_part, nb_node2).second;
712 Int32 dest_rank = m_parts_rank[i_part];
713 info(4) << "Reading COORDS part i=" << i_part << " dest_rank=" << dest_rank << " nb_to_read=" << nb_to_read;
714 if (my_rank == dest_rank || my_rank == m_master_io_rank) {
715 nodes_coordinates.resize(nb_to_read);
716 }
717
718 // Le rang maitre lit les informations des noeuds pour la partie concernée
719 // et les transfère au rang destination
720 if (ios_file) {
721 if (m_is_binary) {
722 ios_file->binaryRead(nodes_coordinates.view());
723 }
724 else {
725 for (Integer i = 0; i < nb_to_read; ++i) {
726 nodes_coordinates[i] = _getReal3();
727 //info() << "I=" << i << " ID=" << nodes_uids[i] << " COORD=" << Real3(nx, ny, nz);
728 }
729 }
730 if (dest_rank != m_master_io_rank) {
731 pm->send(nodes_coordinates, dest_rank);
732 }
733 }
734 else if (my_rank == dest_rank) {
735 pm->recv(nodes_coordinates, m_master_io_rank);
736 }
737
738 // Conserve les informations de ma partie
739 if (my_rank == dest_rank) {
740 m_mesh_allocate_info.nodes_coordinates.addRange(nodes_coordinates);
741 }
742 }
743
744 if (!m_is_binary)
745 _goToNextLine();
746}
747
748/*---------------------------------------------------------------------------*/
749/*---------------------------------------------------------------------------*/
755{
756 IosFile* ios_file = m_ios_file.get();
757 IParallelMng* pm = m_parallel_mng;
758 const Int32 my_rank = pm->commRank();
759 const Int64 nb_entity_in_block = block.nb_entity;
760 const Int32 item_nb_node = block.item_nb_node;
761 const bool is_print_level1 = m_verbosity_level > 0;
762 const bool is_print_level2 = m_verbosity_level > 1;
763
764 if (is_print_level1)
765 info() << "Reading block nb_entity=" << nb_entity_in_block << " item_nb_node=" << item_nb_node;
766
768 UniqueArray<Int64> connectivities;
769
770 UniqueArray<Int64> tmp_uid_and_connectivities;
771
772 for (Int32 i_part = 0; i_part < m_nb_part; ++i_part) {
773 const Int64 nb_to_read = _interval(i_part, m_nb_part, nb_entity_in_block).second;
774 const Int32 dest_rank = m_parts_rank[i_part];
775
776 if (is_print_level2)
777 info(4) << "Reading block part i_part=" << i_part
778 << " nb_to_read=" << nb_to_read << " dest_rank=" << dest_rank;
779
780 const Int64 nb_uid = nb_to_read;
781 const Int64 nb_connectivity = nb_uid * item_nb_node;
782 if (my_rank == dest_rank || my_rank == m_master_io_rank) {
783 uids.resize(nb_uid);
784 connectivities.resize(nb_connectivity);
785 }
786 if (ios_file) {
787 if (m_is_binary) {
788 Int64 nb_to_read = nb_uid * (item_nb_node + 1);
789 tmp_uid_and_connectivities.resize(nb_to_read);
790 ios_file->binaryRead(tmp_uid_and_connectivities.view());
791 Int64 index = 0;
792 for (Int64 i = 0; i < nb_uid; ++i) {
793 Int64 item_unique_id = tmp_uid_and_connectivities[index];
794 ++index;
795 uids[i] = item_unique_id;
796 for (Int32 j = 0; j < item_nb_node; ++j) {
797 connectivities[(i * item_nb_node) + j] = tmp_uid_and_connectivities[index];
798 ++index;
799 }
800 }
801 }
802 else {
803 // Utilise des Int64 pour garantir qu'on ne déborde pas.
804 for (Int64 i = 0; i < nb_uid; ++i) {
805 Int64 item_unique_id = ios_file->getInt64();
806 uids[i] = item_unique_id;
807 for (Int32 j = 0; j < item_nb_node; ++j)
808 connectivities[(i * item_nb_node) + j] = ios_file->getInt64();
809 }
810 }
811 if (dest_rank != m_master_io_rank) {
812 pm->send(uids, dest_rank);
813 pm->send(connectivities, dest_rank);
814 }
815 }
816 else if (my_rank == dest_rank) {
817 pm->recv(uids, m_master_io_rank);
818 pm->recv(connectivities, m_master_io_rank);
819 }
820 if (my_rank == dest_rank) {
821 block.uids.addRange(uids);
822 block.connectivities.addRange(connectivities);
823 }
824 }
825}
826
827/*---------------------------------------------------------------------------*/
828/*---------------------------------------------------------------------------*/
859{
860 IosFile* ios_file = m_ios_file.get();
861 IParallelMng* pm = m_parallel_mng;
862
863 const bool is_print_level1 = m_verbosity_level > 0;
864
865 FixedArray<Int64, 4> elements_info;
866 _getInt64ArrayAndBroadcast(elements_info.view());
867
868 Int64 nb_block = elements_info[0];
869 Int64 number_of_elements = elements_info[1];
870 Int64 min_element_tag = elements_info[2];
871 Int64 max_element_tag = elements_info[3];
872
873 if (!m_is_binary)
874 _goToNextLine();
875
876 info() << "[Elements] nb_block=" << nb_block
877 << " nb_elements=" << number_of_elements
878 << " min_element_tag=" << min_element_tag
879 << " max_element_tag=" << max_element_tag;
880
881 if (number_of_elements < 0)
882 ARCANE_THROW(IOException, "Invalid number of elements: {0}", number_of_elements);
883
884 UniqueArray<MshElementBlock>& blocks = m_mesh_allocate_info.element_blocks;
885 blocks.resize(nb_block);
886
887 {
888 // Numérote les blocs (pour le débug)
889 Integer index = 0;
890 for (MshElementBlock& block : blocks) {
891 block.index = index;
892 ++index;
893 }
894 }
895
896 for (MshElementBlock& block : blocks) {
897
898 FixedArray<Int32, 3> block_info;
899 _getInt32ArrayAndBroadcast(block_info.view());
900
901 Int32 entity_dim = block_info[0];
902 Int32 entity_tag = block_info[1];
903 Int32 entity_type = block_info[2];
904 Int64 nb_entity_in_block = _getInt64AndBroadcast();
905
906 const MshToArcaneTypeInfo& msh_tinfo = mshToArcaneTypeInfo(entity_type);
907 ItemTypeInfo* tinfo = msh_tinfo.m_arcane_type_info;
908 Int32 item_nb_node = tinfo->nbLocalNode();
909 ItemTypeId item_type = tinfo->itemTypeId();
910
911 if (is_print_level1)
912 info() << "[Elements] index=" << block.index << " entity_dim=" << entity_dim
913 << " entity_tag=" << entity_tag
914 << " msh_entity_type=" << entity_type << " nb_in_block=" << nb_entity_in_block
915 << " arcane_item_type=" << item_type << " item_nb_node=" << item_nb_node;
916
917 block.nb_entity = nb_entity_in_block;
918 block.item_type = item_type;
919 block.item_nb_node = item_nb_node;
920 block.dimension = entity_dim;
921 block.entity_tag = entity_tag;
922 block.reorder_infos = msh_tinfo.m_reorder_infos;
923 if (entity_type == MSH_PNT) {
924 // Si le type est un point, le traitement semble un peu particulier.
925 // Il y a dans ce cas deux entiers dans la ligne suivante:
926 // - un entier qui ne semble pas être utilisé
927 // - le numéro unique du noeud qui nous intéresse
928 Int64 item_unique_id = NULL_ITEM_UNIQUE_ID;
929 if (ios_file) {
930 [[maybe_unused]] Int64 unused_id = _getInt64();
931 item_unique_id = _getInt64();
932 if (is_print_level1)
933 info() << "Adding unique node uid=" << item_unique_id;
934 }
935 if (m_is_parallel)
936 pm->broadcast(ArrayView<Int64>(1, &item_unique_id), m_master_io_rank);
937 block.uids.add(item_unique_id);
938 }
939 else {
941 }
942 if (!m_is_binary)
943 _goToNextLine();
944 }
945
946 if (m_is_binary)
947 _goToNextLine();
948
949 // Maintenant qu'on a tous les blocs, la dimension du maillage est
950 // la plus grande dimension des blocs
951 Integer mesh_dimension = -1;
952 for (const MshElementBlock& block : blocks)
953 mesh_dimension = math::max(mesh_dimension, block.dimension);
954 if (mesh_dimension < 0)
955 ARCANE_FATAL("Invalid computed mesh dimension '{0}'", mesh_dimension);
956 if (mesh_dimension != 2 && mesh_dimension != 3)
957 ARCANE_THROW(NotSupportedException, "mesh dimension '{0}'. Only 2D or 3D meshes are supported", mesh_dimension);
958 info() << "Computed mesh dimension = " << mesh_dimension;
959
960 bool allow_multi_dim_cell = m_mesh->meshKind().isNonManifold();
961 bool use_experimental_type_for_cell = false;
962 if (allow_multi_dim_cell) {
963 // Par défaut utilise les nouveaux types.
964 use_experimental_type_for_cell = true;
965 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_USE_EXPERIMENTAL_CELL_TYPE", true))
966 use_experimental_type_for_cell = (v.value() != 0);
967 }
968 info() << "Use experimental cell type?=" << use_experimental_type_for_cell;
969 ItemTypeMng* item_type_mng = m_mesh->itemTypeMng();
970 for (MshElementBlock& block : blocks) {
971 const Int32 block_dim = block.dimension;
972 String item_type_name = item_type_mng->typeFromId(block.item_type)->typeName();
973 if (is_print_level1)
974 info() << "Reading block dim=" << block_dim << " type_name=" << item_type_name;
975 if (block_dim == mesh_dimension)
976 _computeOwnItems(block, m_mesh_allocate_info.cells_infos, false);
977 else if (allow_multi_dim_cell) {
978 // Regarde si on peut créé des mailles de dimension inférieures à celles
979 // du maillage.
980 bool use_sub_dim_cell = false;
981 if (mesh_dimension == 3 && (block_dim == 2 || block_dim == 1))
982 // Maille 1D ou 2D dans un maillage 3D
983 use_sub_dim_cell = true;
984 else if (mesh_dimension == 2 && block_dim == 1)
985 // Maille 1D dans un maillage 2D
986 use_sub_dim_cell = true;
987 if (!use_experimental_type_for_cell)
988 use_sub_dim_cell = false;
989 if (use_sub_dim_cell) {
990 // Ici on va créer des mailles 2D dans un maillage 3D.
991 // On converti le type de base en un type équivalent pour les mailles.
992 if (mesh_dimension == 3) {
993 if (block.item_type == IT_Triangle3)
994 block.item_type = ItemTypeId(IT_Cell3D_Triangle3);
995 else if (block.item_type == IT_Triangle6)
996 block.item_type = ItemTypeId(ITI_Cell3D_Triangle6);
997 else if (block.item_type == IT_Quad4)
998 block.item_type = ItemTypeId(IT_Cell3D_Quad4);
999 else if (block.item_type == IT_Quad8)
1000 block.item_type = ItemTypeId(IT_Cell3D_Quad8);
1001 else if (block.item_type == IT_Quad9)
1002 block.item_type = ItemTypeId(IT_Cell3D_Quad9);
1003 else if (block.item_type == IT_Line2)
1004 block.item_type = ItemTypeId(IT_Cell3D_Line2);
1005 else if (block.item_type == IT_Line3)
1006 block.item_type = ItemTypeId(IT_Cell3D_Line3);
1007 else
1008 ARCANE_FATAL("Not supported sub dimension cell type={0} for 3D mesh", item_type_name);
1009 }
1010 else if (mesh_dimension == 2) {
1011 if (block.item_type == IT_Line2)
1012 block.item_type = ItemTypeId(IT_CellLine2);
1013 else
1014 ARCANE_FATAL("Not supported sub dimension cell type={0} for 2D mesh", item_type_name);
1015 }
1016 block.is_built_as_cells = true;
1017 _computeOwnItems(block, m_mesh_allocate_info.cells_infos, false);
1018 }
1019 }
1020 }
1021
1022 return mesh_dimension;
1023}
1024
1025/*---------------------------------------------------------------------------*/
1026/*---------------------------------------------------------------------------*/
1027
1028namespace
1029{
1030 template <typename DataType> inline ArrayView<DataType>
1031 _broadcastArrayWithSize(IParallelMng* pm, ArrayView<DataType> values,
1032 UniqueArray<DataType>& work_values, Int32 dest_rank, Int64 size)
1033 {
1034 const Int32 my_rank = pm->commRank();
1035 ArrayView<DataType> view = values;
1036 if (my_rank != dest_rank) {
1037 work_values.resize(size);
1038 view = work_values.view();
1039 }
1040 pm->broadcast(view, dest_rank);
1041 return view;
1042 }
1050 template <typename DataType> inline ArrayView<DataType>
1051 _broadcastArray(IParallelMng* pm, ArrayView<DataType> values,
1052 UniqueArray<DataType>& work_values, Int32 dest_rank)
1053 {
1054 const Int32 my_rank = pm->commRank();
1055 Int64 size = 0;
1056 // Envoie la taille
1057 if (dest_rank == my_rank)
1058 size = values.size();
1059 pm->broadcast(ArrayView<Int64>(1, &size), dest_rank);
1060 return _broadcastArrayWithSize(pm, values, work_values, dest_rank, size);
1061 }
1062
1063} // namespace
1064
1065/*---------------------------------------------------------------------------*/
1066/*---------------------------------------------------------------------------*/
1067
1068void MshParallelMeshReader::
1069_computeOwnItems(MshElementBlock& block, MshItemKindInfo& item_kind_info, bool is_generate_uid)
1070{
1071 // On ne conserve que les entités dont le premier noeud appartient à notre rang.
1072
1073 IParallelMng* pm = m_parallel_mng;
1074 const Int32 my_rank = pm->commRank();
1075 const bool is_print_level1 = m_verbosity_level > 0;
1076
1077 const ItemTypeId item_type = block.item_type;
1078 const Int32 item_nb_node = block.item_nb_node;
1079
1080 UniqueArray<Int64> connectivities;
1081 UniqueArray<Int64> uids;
1082 UniqueArray<Int32> nodes_rank;
1083
1084 SmallSpan<const Int16> reorder_infos = block.reorder_infos;
1085 bool has_reorder_info = !reorder_infos.empty();
1086 const Int32 nb_part = m_parts_rank.size();
1087 if (is_print_level1)
1088 info() << "Compute own items block_index=" << block.index << " nb_part=" << nb_part
1089 << " has_reorder?=" << has_reorder_info;
1090 // Liste des noeuds de l'élément avec la connectivité Arcane.
1091 SmallArray<Int64> arcane_reordered_uids;
1092 if (has_reorder_info)
1093 arcane_reordered_uids.resize(item_nb_node);
1094 for (Int32 i_part = 0; i_part < nb_part; ++i_part) {
1095 const Int32 dest_rank = m_parts_rank[i_part];
1096 // Broadcast la i_part-ème partie des uids et connectivités des mailles
1097 ArrayView<Int64> connectivities_view = _broadcastArray(pm, block.connectivities.view(), connectivities, dest_rank);
1098 ArrayView<Int64> uids_view = _broadcastArray(pm, block.uids.view(), uids, dest_rank);
1099
1100 Int32 nb_item = uids_view.size();
1101 nodes_rank.resize(nb_item);
1102 nodes_rank.fill(-1);
1103
1104 // Parcours les entités. Chaque entité appartiendra au rang
1105 // de son premier noeud. Si cette partie correspond à mon rang, alors
1106 // on conserve la maille.
1107 for (Int32 i = 0; i < nb_item; ++i) {
1108 Int64 first_node_uid = connectivities_view[i * item_nb_node];
1109 auto x = m_mesh_allocate_info.nodes_rank_map.find(first_node_uid);
1110 if (x == m_mesh_allocate_info.nodes_rank_map.end())
1111 // Le noeud n'est pas dans ma liste
1112 continue;
1113 Int32 rank = x->second;
1114 nodes_rank[i] = rank;
1115 }
1116 pm->reduce(Parallel::ReduceMax, nodes_rank);
1117 for (Int32 i = 0; i < nb_item; ++i) {
1118 const Int32 rank = nodes_rank[i];
1119 if (rank != my_rank)
1120 // Le noeud n'est pas dans ma partie
1121 continue;
1122 // Le noeud est chez moi, j'ajoute l'entité à la liste des
1123 // entités que je vais créer.
1124 ConstArrayView<Int64> v = connectivities_view.subView(i * item_nb_node, item_nb_node);
1125 Int64 uid = uids_view[i];
1126 if (is_generate_uid)
1127 // Le uniqueId() sera généré automatiquement
1128 uid = NULL_ITEM_UNIQUE_ID;
1129 if (has_reorder_info) {
1130 // Réordonne les noeuds si le type Arcane n'a pas la même numérotation
1131 // que le type MSH.
1132 for (Int32 zz = 0; zz < item_nb_node; ++zz)
1133 arcane_reordered_uids[zz] = v[reorder_infos[zz]];
1134 v = arcane_reordered_uids.view();
1135 }
1136 item_kind_info.addItem(item_type, uid, v);
1137 }
1138 }
1139}
1140
1141/*---------------------------------------------------------------------------*/
1142/*---------------------------------------------------------------------------*/
1159{
1160 UniqueArray<Int64> uids_storage;
1161 UniqueArray<Real3> coords_storage;
1162 UniqueArray<Int32> local_ids;
1163
1164 IParallelMng* pm = m_parallel_mng;
1165
1166 const IItemFamily* node_family = m_mesh->nodeFamily();
1167 VariableNodeReal3& nodes_coord_var(m_mesh->nodesCoordinates());
1168
1169 for (Int32 dest_rank : m_parts_rank) {
1170 ConstArrayView<Int64> uids = _broadcastArray(pm, m_mesh_allocate_info.nodes_unique_id.view(), uids_storage, dest_rank);
1171 ConstArrayView<Real3> coords = _broadcastArray(pm, m_mesh_allocate_info.nodes_coordinates.view(), coords_storage, dest_rank);
1172
1173 Int32 nb_item = uids.size();
1174 local_ids.resize(nb_item);
1175
1176 // Converti les uniqueId() en localId(). S'ils sont non nuls
1177 // c'est que l'entité est dans mon sous-domaine et donc on peut
1178 // positionner sa coordonnée
1179 node_family->itemsUniqueIdToLocalId(local_ids, uids, false);
1180 for (Int32 i = 0; i < nb_item; ++i) {
1181 NodeLocalId nid(local_ids[i]);
1182 if (!nid.isNull())
1183 nodes_coord_var[nid] = coords[i];
1184 }
1185 }
1186}
1187
1188/*---------------------------------------------------------------------------*/
1189/*---------------------------------------------------------------------------*/
1190
1191void MshParallelMeshReader::
1192_allocateCells()
1193{
1194 IMesh* mesh = m_mesh;
1195 Integer nb_elements = m_mesh_allocate_info.cells_infos.nb_item;
1196 info() << "nb_of_elements=cells_type.size()=" << nb_elements;
1197 Integer nb_cell_node = m_mesh_allocate_info.cells_infos.items_infos.size();
1198 info() << "nb_cell_node=cells_connectivity.size()=" << nb_cell_node;
1199
1200 // Création des mailles
1201 info() << "Building cells, nb_cell=" << nb_elements << " nb_cell_node=" << nb_cell_node;
1202 IPrimaryMesh* pmesh = mesh->toPrimaryMesh();
1203 info() << "## Allocating ##";
1204 pmesh->allocateCells(nb_elements, m_mesh_allocate_info.cells_infos.items_infos, false);
1205 info() << "## Ending ##";
1206 pmesh->endAllocate();
1207 info() << "## Done ##";
1208}
1209
1210/*---------------------------------------------------------------------------*/
1211/*---------------------------------------------------------------------------*/
1212
1213void MshParallelMeshReader::
1214_allocateGroups()
1215{
1216 IMesh* mesh = m_mesh;
1217 Int32 mesh_dim = mesh->dimension();
1218 Int32 face_dim = mesh_dim - 1;
1219 UniqueArray<MshEntitiesWithNodes> entity_list;
1220 UniqueArray<MshPhysicalName> physical_name_list;
1221 IItemFamily* node_family = mesh->nodeFamily();
1222
1223 for (MshElementBlock& block : m_mesh_allocate_info.element_blocks) {
1224 entity_list.clear();
1225 physical_name_list.clear();
1226 Int32 block_index = block.index;
1227 Int32 block_dim = block.dimension;
1228 // On alloue un groupe s'il a un nom physique associé.
1229 // Pour cela, il faut déjà qu'il soit associé à une entité.
1230 Int64 block_entity_tag = block.entity_tag;
1231 if (block_entity_tag < 0) {
1232 info(5) << "[Groups] Skipping block index=" << block_index << " because it has no entity";
1233 continue;
1234 }
1235 if (block_dim == 0) {
1236 const MshEntitiesNodes* entity = m_mesh_info->findNodeEntities(block_entity_tag);
1237 if (!entity) {
1238 info(5) << "[Groups] Skipping block index=" << block_index
1239 << " because entity tag is invalid";
1240 continue;
1241 }
1242 Int64 entity_physical_tag = entity->physicalTag();
1243 MshPhysicalName physical_name = m_mesh_info->findPhysicalName(block_dim, entity_physical_tag);
1244 physical_name_list.add(physical_name);
1245 }
1246 else {
1247 m_mesh_info->findEntities(block_dim, block_entity_tag, entity_list);
1248 for (const MshEntitiesWithNodes& x : entity_list) {
1249 Int64 entity_physical_tag = x.physicalTag();
1250 MshPhysicalName physical_name = m_mesh_info->findPhysicalName(block_dim, entity_physical_tag);
1251 physical_name_list.add(physical_name);
1252 }
1253 }
1254 for (const MshPhysicalName& physical_name : physical_name_list) {
1255 if (physical_name.isNull()) {
1256 info(5) << "[Groups] Skipping block index=" << block_index
1257 << " because entity physical tag is invalid";
1258 continue;
1259 }
1260 String group_name = physical_name.name();
1261 info(4) << "[Groups] Block index=" << block_index << " dim=" << block_dim
1262 << " name='" << group_name << "' built_as_cells=" << block.is_built_as_cells;
1263 if (block_dim == mesh_dim || block.is_built_as_cells) {
1264 _addCellOrNodeGroup(block.uids, block.index, group_name, mesh->cellFamily(), false);
1265 }
1266 else if (block_dim == face_dim) {
1267 _addFaceGroup(block, group_name);
1268 }
1269 else {
1270 // Il s'agit de noeuds
1271 _addCellOrNodeGroup(block.uids, block.index, group_name, node_family, false);
1272 }
1273 }
1274 }
1275
1276 // Crée les groupes de noeuds associés aux blocs de $Nodes
1277 {
1278 //bool has_periodic = m_mesh_info->m_periodic_info.hasValues();
1279 UniqueArray<Int64>& nodes_uids = m_mesh_allocate_info.nodes_unique_id;
1280 // Créé les groupes de noeuds issus des blocks dans $Nodes
1281 for (const MshNodeBlock& block : m_mesh_allocate_info.node_blocks) {
1282 ArrayView<Int64> block_uids = nodes_uids.subView(block.index_in_allocation_info, block.nb_node);
1283 MshPhysicalName physical_name = m_mesh_info->findPhysicalName(block.entity_dim, block.entity_tag);
1284 String group_name = physical_name.name();
1285 // Si on a des infos de périodicité, on crée toujours les groupes de noeuds correspondants
1286 // aux blocs, car ils peuvent être référencés par les infos de périodicité.
1287 // Dans ce cas, on génère un nom de groupe.
1288 // NOTE: désactive cela car cela peut générer un très grand nombre de nombre de groupes
1289 // lorsqu'il y a beaucoup d'informations de périodicité et en plus on n'utilise pas encore
1290 // cela lors de l'écriture des informations périodiques.
1291 //if (physical_name.isNull() && has_periodic)
1292 //group_name = String::format("ArcaneMshInternalNodesDim{0}Entity{1}", block.entity_dim, block.entity_tag);
1293 if (!group_name.null())
1294 _addCellOrNodeGroup(block_uids, block.index, group_name, node_family, true);
1295 }
1296 }
1297}
1298
1299/*---------------------------------------------------------------------------*/
1300/*---------------------------------------------------------------------------*/
1305_addFaceGroup(const MshElementBlock& block, const String& group_name)
1306{
1307 IParallelMng* pm = m_parallel_mng;
1308 const Int32 item_nb_node = block.item_nb_node;
1309
1310 UniqueArray<Int64> connectivities;
1311 for (Int32 dest_rank : m_parts_rank) {
1312 ArrayView<Int64> connectivities_view = _broadcastArray(pm, block.connectivities.view(), connectivities, dest_rank);
1313 _addFaceGroupOnePart(block, connectivities_view, group_name);
1314 }
1315}
1316
1317/*---------------------------------------------------------------------------*/
1318/*---------------------------------------------------------------------------*/
1319
1320void MshParallelMeshReader::
1321_addFaceGroupOnePart(const MshElementBlock& block, ConstArrayView<Int64> connectivities,
1322 const String& group_name)
1323{
1324 IMesh* mesh = m_mesh;
1325 const Int32 item_nb_node = block.item_nb_node;
1326 const Int32 block_index = block.index;
1327 const ItemTypeId type_id = block.item_type;
1328 const Int32 nb_entity = connectivities.size() / item_nb_node;
1329
1330 // Il peut y avoir plusieurs blocs pour le même groupe.
1331 // On récupère le groupe s'il existe déjà.
1332 FaceGroup face_group = mesh->faceFamily()->findGroup(group_name, true);
1333
1334 UniqueArray<Int32> faces_id; // Numéro de la face dans le maillage \a mesh
1335 faces_id.reserve(nb_entity);
1336
1337 const Int32 face_nb_node = nb_entity * item_nb_node;
1338
1339 UniqueArray<Int64> faces_first_node_unique_id(nb_entity);
1340 UniqueArray<Int32> faces_first_node_local_id(nb_entity);
1341 UniqueArray<Int64> faces_nodes_unique_id(face_nb_node);
1342 Integer faces_nodes_unique_id_index = 0;
1343
1344 UniqueArray<Int64> orig_nodes_id(item_nb_node);
1345 //UniqueArray<Integer> face_nodes_index(item_nb_node);
1346
1347 IItemFamily* node_family = mesh->nodeFamily();
1348 NodeInfoListView mesh_nodes(node_family);
1349 NodesOfItemReorderer m_nodes_reorderer(mesh->itemTypeMng());
1350
1351 // Réordonne les identifiants des faces retrouver la face dans le maillage.
1352 // Pour cela, on récupère le premier noeud de la face et on regarde s'il
1353 // se trouve dans notre sous-domaine. Si oui, la face sera ajoutée à notre
1354 // partie du maillage
1355 for (Integer i_face = 0; i_face < nb_entity; ++i_face) {
1356 for (Integer z = 0; z < item_nb_node; ++z)
1357 orig_nodes_id[z] = connectivities[faces_nodes_unique_id_index + z];
1358 m_nodes_reorderer.reorder(type_id, orig_nodes_id);
1359 ConstArrayView<Int64> sorted_nodes(m_nodes_reorderer.sortedNodes());
1360 for (Integer z = 0; z < item_nb_node; ++z)
1361 faces_nodes_unique_id[faces_nodes_unique_id_index + z] = sorted_nodes[z];
1362 faces_first_node_unique_id[i_face] = sorted_nodes[0];
1363 faces_nodes_unique_id_index += item_nb_node;
1364 }
1365
1366 node_family->itemsUniqueIdToLocalId(faces_first_node_local_id, faces_first_node_unique_id, false);
1367
1368 const bool is_non_manifold = m_mesh->meshKind().isNonManifold();
1369 faces_nodes_unique_id_index = 0;
1370 for (Integer i_face = 0; i_face < nb_entity; ++i_face) {
1371 const Integer n = item_nb_node;
1372 Int32 face_first_node_lid = faces_first_node_local_id[i_face];
1373 if (face_first_node_lid != NULL_ITEM_LOCAL_ID) {
1374 Int64ConstArrayView face_nodes_id(item_nb_node, &faces_nodes_unique_id[faces_nodes_unique_id_index]);
1375 Node current_node(mesh_nodes[faces_first_node_local_id[i_face]]);
1376 Face face = MeshUtils::getFaceFromNodesUniqueId(current_node, face_nodes_id);
1377
1378 // En parallèle, il est possible que la face ne soit pas dans notre sous-domaine
1379 // même si un de ses noeuds l'est
1380 if (face.null()) {
1381 if (!m_is_parallel) {
1382 OStringStream ostr;
1383 ostr() << "(Nodes:";
1384 for (Integer z = 0; z < n; ++z)
1385 ostr() << ' ' << face_nodes_id[z];
1386 ostr() << " - node_lid=" << current_node.localId() << ")";
1387 String error_string = "INTERNAL: MshMeshReader face index={0} with nodes '{1}' is not in node/face connectivity.";
1388 if (!is_non_manifold)
1389 error_string = error_string + "\n This errors may occur if the mesh is non-manifold."
1390 "\n See Arcane documentation to specify the mesh is a non manifold one.\n";
1391 ARCANE_FATAL(error_string, i_face, ostr.str());
1392 }
1393 }
1394 else
1395 faces_id.add(face.localId());
1396 }
1397
1398 faces_nodes_unique_id_index += n;
1399 }
1400 info(4) << "Adding " << faces_id.size() << " faces from block index=" << block_index
1401 << " to group '" << face_group.name() << "'";
1402 face_group.addItems(faces_id);
1403}
1404
1405/*---------------------------------------------------------------------------*/
1406/*---------------------------------------------------------------------------*/
1411_addCellOrNodeGroup(ArrayView<Int64> block_uids, Int32 block_index,
1412 const String& group_name, IItemFamily* family, bool filter_invalid)
1413{
1414 IParallelMng* pm = m_parallel_mng;
1415
1416 UniqueArray<Int64> uids;
1417 for (Int32 dest_rank : m_parts_rank) {
1418 ArrayView<Int64> uids_view = _broadcastArray(pm, block_uids, uids, dest_rank);
1419 _addCellOrNodeGroupOnePart(uids_view, group_name, block_index, family, filter_invalid);
1420 }
1421}
1422
1423/*---------------------------------------------------------------------------*/
1424/*---------------------------------------------------------------------------*/
1425
1426void MshParallelMeshReader::
1427_addCellOrNodeGroupOnePart(ConstArrayView<Int64> uids, const String& group_name,
1428 Int32 block_index, IItemFamily* family, bool filter_invalid)
1429{
1430 const Int32 nb_entity = uids.size();
1431
1432 // Il peut y avoir plusieurs blocs pour le même groupe.
1433 // On récupère le groupe s'il existe déjà.
1434 ItemGroup group = family->findGroup(group_name, true);
1435
1436 UniqueArray<Int32> items_lid(nb_entity);
1437
1438 family->itemsUniqueIdToLocalId(items_lid, uids, false);
1439
1440 // En parallèle, il est possible que certaines entités du groupe ne soient
1441 // pas dans notre sous-domaine. Il faut les filtrer.
1442 // De même, s'il s'agit d'un groupe issu d'une $Entity node, il est possible
1443 // que le noeud n'existe pas s'il n'est pas attaché à une maille
1444 // (TODO: à vérifier avec sod3d-misc.msh)
1445 if (m_is_parallel || filter_invalid) {
1446 auto items_begin = items_lid.begin();
1447 Int64 new_size = std::remove(items_begin, items_lid.end(), NULL_ITEM_LOCAL_ID) - items_begin;
1448 items_lid.resize(new_size);
1449 }
1450
1451 info() << "Adding " << items_lid.size() << " items from block index=" << block_index
1452 << " to group '" << group_name << "' for family=" << family->name();
1453
1454 group.addItems(items_lid);
1455}
1456
1457/*---------------------------------------------------------------------------*/
1458/*---------------------------------------------------------------------------*/
1459/*
1460 * $PhysicalNames // same as MSH version 2
1461 * numPhysicalNames(ASCII int)
1462 * dimension(ASCII int) physicalTag(ASCII int) "name"(127 characters max)
1463 * ...
1464 * $EndPhysicalNames
1465 */
1466void MshParallelMeshReader::
1467_readPhysicalNames()
1468{
1469 // NOTE: même en binaire, la partie $PhysicalNames est écrite en ASCII.
1470 String quote_mark = "\"";
1471 Int32 nb_name = _getIntegerAndBroadcast();
1472 info() << "nb_physical_name=" << nb_name;
1473
1474 _goToNextLine();
1475
1476 for (Int32 i = 0; i < nb_name; ++i) {
1477 Int32 dim = _getIntegerAndBroadcast();
1478 Int32 tag = _getIntegerAndBroadcast();
1479 String s = _getNextLineAndBroadcast();
1480 if (dim < 0 || dim > 3)
1481 ARCANE_FATAL("Invalid value for physical name dimension dim={0}", dim);
1482 // Les noms des groupes peuvent commencer par des espaces et contiennent
1483 // des guillemets qu'il faut supprimer.
1485 if (s.startsWith(quote_mark))
1486 s = s.substring(1);
1487 if (s.endsWith(quote_mark))
1488 s = s.substring(0, s.length() - 1);
1489 m_mesh_info->physical_name_list.add(dim, tag, s);
1490 info(4) << "[PhysicalName] index=" << i << " dim=" << dim << " tag=" << tag << " name='" << s << "'";
1491 }
1492
1493 String s = _getNextLineAndBroadcast();
1494 if (s != "$EndPhysicalNames")
1495 ARCANE_FATAL("found '{0}' and expected '$EndPhysicalNames'", s);
1496}
1497
1498/*---------------------------------------------------------------------------*/
1499/*---------------------------------------------------------------------------*/
1532{
1533 IosFile* ios_file = m_ios_file.get();
1534
1535 FixedArray<Int64, 4> nb_dim_item;
1536 _getInt64ArrayAndBroadcast(nb_dim_item.view());
1537
1538 const bool is_print_level1 = m_verbosity_level > 0;
1539
1540 info() << "[Entities] nb_0d=" << nb_dim_item[0] << " nb_1d=" << nb_dim_item[1]
1541 << " nb_2d=" << nb_dim_item[2] << " nb_3d=" << nb_dim_item[3];
1542 // Après le format, on peut avoir les entités mais cela est optionnel
1543 // Si elles sont présentes, on lit le fichier jusqu'à la fin de cette section.
1544 if (!m_is_binary)
1545 _goToNextLine();
1546
1547 // Lecture des entités associées à des points
1548 for (Int64 i = 0; i < nb_dim_item[0]; ++i) {
1549 FixedArray<Int64, 2> tag_info;
1550 if (ios_file) {
1551 Int32 tag = _getInt32();
1552 Real3 xyz = _getReal3();
1553 Int64 num_physical_tag = _getInt64();
1554 if (num_physical_tag > 1)
1555 ARCANE_FATAL("NotImplemented numPhysicalTag>1 (n={0}, index={1} xyz={2})",
1556 num_physical_tag, i, xyz);
1557
1558 Int32 physical_tag = -1;
1559 if (num_physical_tag == 1)
1560 physical_tag = _getInt32();
1561 if (is_print_level1)
1562 info() << "[Entities] point tag=" << tag << " pos=" << xyz << " phys_tag=" << physical_tag;
1563
1564 tag_info[0] = tag;
1565 tag_info[1] = physical_tag;
1566 }
1567 m_parallel_mng->broadcast(tag_info.view(), m_master_io_rank);
1568 m_mesh_info->entities_nodes_list.add(MshEntitiesNodes(tag_info[0], tag_info[1]));
1569 if (!m_is_binary)
1570 _goToNextLine();
1571 }
1572
1573 // Lecture des entités de dimensions 1, 2 et 3.
1574 for (Int32 i_dim = 1; i_dim <= 3; ++i_dim)
1575 for (Int32 i = 0; i < nb_dim_item[i_dim]; ++i)
1576 _readOneEntity(i_dim, i);
1577
1578 // En binaire, il faut aller au début de la ligne suivante.
1579 if (m_is_binary)
1580 _goToNextLine();
1581 _readAndCheck("$EndEntities");
1582}
1583
1584/*---------------------------------------------------------------------------*/
1585/*---------------------------------------------------------------------------*/
1586
1587void MshParallelMeshReader::
1588_readOneEntity(Int32 entity_dim, Int32 entity_index_in_dim)
1589{
1590 IosFile* ios_file = m_ios_file.get();
1591 const bool is_print_level1 = m_verbosity_level > 0;
1592 const bool is_print_level2 = m_verbosity_level > 1;
1593
1594 // Infos pour les tags
1595 // [0] entity_dim
1596 // [1] tag
1597 // [2] nb_physical_tag
1598 // [2+1] physical_tag1
1599 // [2+N] physical_tagN
1600 // ...
1601 // [3+nb_physical_tag] nb_boundary
1602 // [3+nb_physical_tag+1] boundary_tag1
1603 // [3+nb_physical_tag+n] boundary_tagN
1604 // ...
1605 if (is_print_level1)
1606 info() << "[Entities] Reading entity dim=" << entity_dim << " index_in_dim=" << entity_index_in_dim;
1607 SmallArray<Int64, 128> dim_and_tag_info;
1608 dim_and_tag_info.add(entity_dim);
1609 if (ios_file) {
1610 Int32 tag = _getInt32();
1611 dim_and_tag_info.add(tag);
1612 Real3 min_pos = _getReal3();
1613 Real3 max_pos = _getReal3();
1614 Int64 nb_physical_tag = _getInt64();
1615 dim_and_tag_info.add(nb_physical_tag);
1616 for (Int32 z = 0; z < nb_physical_tag; ++z) {
1617 Int32 physical_tag = _getInt32();
1618 dim_and_tag_info.add(physical_tag);
1619 if (is_print_level2)
1620 info(4) << "[Entities] z=" << z << " physical_tag=" << physical_tag;
1621 }
1622 // TODO: Lire les informations numBounding...
1623 Int64 nb_bounding_group = _getInt64();
1624 dim_and_tag_info.add(nb_bounding_group);
1625 for (Int64 z = 0; z < nb_bounding_group; ++z) {
1626 Int32 boundary_tag = _getInt32();
1627 if (is_print_level2)
1628 info(4) << "[Entities] z=" << z << " boundary_tag=" << boundary_tag;
1629 }
1630 if (is_print_level2)
1631 info(4) << "[Entities] dim=" << entity_dim << " tag=" << tag
1632 << " min_pos=" << min_pos << " max_pos=" << max_pos
1633 << " nb_phys_tag=" << nb_physical_tag
1634 << " nb_bounding=" << nb_bounding_group;
1635 }
1636 Int32 info_size = dim_and_tag_info.size();
1637 m_parallel_mng->broadcast(ArrayView<Int32>(1, &info_size), m_master_io_rank);
1638 dim_and_tag_info.resize(info_size);
1639 m_parallel_mng->broadcast(dim_and_tag_info.view(), m_master_io_rank);
1640
1641 {
1642 Int32 dim = CheckedConvert::toInt32(dim_and_tag_info[0]);
1643 Int64 tag = dim_and_tag_info[1];
1644 Int64 nb_physical_tag = dim_and_tag_info[2];
1645 for (Int32 z = 0; z < nb_physical_tag; ++z) {
1646 Int64 physical_tag = dim_and_tag_info[3 + z];
1647 if (is_print_level2)
1648 info(4) << "[Entities] adding info dim=" << entity_dim << " tag=" << tag
1649 << " physical_tag=" << physical_tag;
1650 m_mesh_info->entities_with_nodes_list[dim - 1].add(MshEntitiesWithNodes(dim, tag, physical_tag));
1651 }
1652 }
1653
1654 if (!m_is_binary)
1655 _goToNextLine();
1656}
1657
1658/*---------------------------------------------------------------------------*/
1659/*---------------------------------------------------------------------------*/
1679{
1680 Int64 nb_link = _getInt64AndBroadcast();
1681 info() << "[Periodic] nb_link=" << nb_link;
1682 const bool is_print_level1 = m_verbosity_level > 0;
1683 const bool is_print_level2 = m_verbosity_level > 1;
1684 // TODO: pour l'instant, tous les rangs conservent les
1685 // données car on suppose qu'il n'y en a pas beaucoup.
1686 // A terme, il faudra aussi distribuer ces informations.
1687 MshPeriodicInfo& periodic_info = m_mesh_info->m_periodic_info;
1688 periodic_info.m_periodic_list.resize(nb_link);
1689 for (Int64 ilink = 0; ilink < nb_link; ++ilink) {
1690 MshPeriodicOneInfo& one_info = periodic_info.m_periodic_list[ilink];
1691 FixedArray<Int32, 3> entity_info;
1692 _getInt32ArrayAndBroadcast(entity_info.view());
1693
1694 if (is_print_level1)
1695 info() << "[Periodic] link_index=" << ilink << " dim=" << entity_info[0] << " entity_tag=" << entity_info[1]
1696 << " entity_tag_master=" << entity_info[2];
1697 one_info.m_entity_dim = entity_info[0];
1698 one_info.m_entity_tag = entity_info[1];
1699 one_info.m_entity_tag_master = entity_info[2];
1700
1701 Int64 num_affine = _getInt64AndBroadcast();
1702 if (is_print_level2)
1703 info() << "[Periodic] num_affine=" << num_affine;
1704 one_info.m_affine_values.resize(num_affine);
1705 _getDoubleArrayAndBroadcast(one_info.m_affine_values);
1706 one_info.m_nb_corresponding_node = CheckedConvert::toInt32(_getInt64AndBroadcast());
1707 if (is_print_level1)
1708 info() << "[Periodic] nb_corresponding_node=" << one_info.m_nb_corresponding_node;
1709 one_info.m_corresponding_nodes.resize(one_info.m_nb_corresponding_node * 2);
1710 _getInt64ArrayAndBroadcast(one_info.m_corresponding_nodes);
1711 if (is_print_level2)
1712 info(4) << "[Periodic] corresponding_nodes=" << one_info.m_corresponding_nodes;
1713 }
1714
1715 _goToNextLine();
1716
1718 if (s != "$EndPeriodic")
1719 ARCANE_FATAL("found '{0}' and expected '$EndPeriodic'", s);
1720}
1721
1722/*---------------------------------------------------------------------------*/
1723/*---------------------------------------------------------------------------*/
1728_readAndCheck(const String& expected_value)
1729{
1730 String s;
1731 if (m_is_binary) {
1732 constexpr Int32 MAX_SIZE = 128;
1734 Span<const Byte> expected_bytes = expected_value.bytes();
1735 Int32 read_size = CheckedConvert::toInt32(expected_bytes.size());
1736 SmallSpan<Byte> bytes_to_read = buf_bytes.span().subSpan(0, read_size);
1737 if (read_size >= MAX_SIZE)
1738 ARCANE_FATAL("local buffer is too small (size={0} max={1})", read_size, MAX_SIZE);
1739 IosFile* f = m_ios_file.get();
1740 if (f) {
1741 f->binaryRead(bytes_to_read);
1742 s = String(bytes_to_read);
1743 info() << "S=" << s;
1744 if (m_is_parallel) {
1745 m_parallel_mng->broadcastString(s, m_master_io_rank);
1746 }
1747 }
1748 _goToNextLine();
1749 }
1750 else {
1752 }
1753 if (s != expected_value)
1754 ARCANE_FATAL("found '{0}' and expected '{1}'", s, expected_value);
1755}
1756
1757/*---------------------------------------------------------------------------*/
1758/*---------------------------------------------------------------------------*/
1761void MshParallelMeshReader::
1762_readMeshFromFile()
1763{
1764 IosFile* ios_file = m_ios_file.get();
1765 IMesh* mesh = m_mesh;
1766 info() << "Reading 'msh' file in parallel";
1767
1768 _initTypes();
1769
1770 const int MSH_BINARY_TYPE = 1;
1771
1772 if (ios_file) {
1773 Real version = ios_file->getReal();
1774 if (version != 4.1)
1775 ARCANE_THROW(IOException, "Wrong msh file version '{0}'. Only version '4.1' is supported in parallel", version);
1776 Integer file_type = ios_file->getInteger(); // is an integer equal to 0 in the ASCII file format, equal to 1 for the binary format
1777 if (file_type == MSH_BINARY_TYPE)
1778 m_is_binary = true;
1779 info() << "IsBinary?=" << m_is_binary;
1780 Int32 data_size = ios_file->getInteger(); // is an integer equal to the size of the floating point numbers used in the file
1781 ARCANE_UNUSED(data_size);
1782 if (data_size != 8)
1783 ARCANE_FATAL("Only 'size_t' of size '8' is allowed (current size is '{0}')", data_size);
1784 // En binaire, il a un entier à lire qui vaut 1 et qui permet de savoir si on n'est en big/little endian.
1785 if (m_is_binary) {
1786 // Il faut lire jusqu'à la fin de la ligne pour le binaire.
1787 _goToNextLine();
1788 Int32 int_value_one = 0;
1789 ios_file->binaryRead(SmallSpan<Int32>(&int_value_one, 1));
1790 if (int_value_one != 1)
1791 ARCANE_FATAL("Bad endianess for file. Read int as value '{0}' (expected=1)", int_value_one);
1792 }
1793
1794 _goToNextLine();
1795
1796 // $EndMeshFormat
1797 if (!ios_file->lookForString("$EndMeshFormat"))
1798 ARCANE_THROW(IOException, "$EndMeshFormat not found");
1799 }
1800
1801 // TODO: Les différentes sections ($Nodes, $Entitites, ...) peuvent
1802 // être dans n'importe quel ordre (à part $Nodes qui doit être avant $Elements)
1803 // Faire un méthode qui gère cela.
1804
1805 String next_line = _getNextLineAndBroadcast();
1806 // Noms des groupes
1807 if (next_line == "$PhysicalNames") {
1808 _readPhysicalNames();
1809 next_line = _getNextLineAndBroadcast();
1810 }
1811
1812 // Après le format, on peut avoir les entités mais cela est optionnel
1813 // Si elles sont présentes, on lit le fichier jusqu'à la fin de cette section.
1814 if (next_line == "$Entities") {
1815 _readEntities();
1816 next_line = _getNextLineAndBroadcast();
1817 }
1818 // $Nodes
1819 if (next_line != "$Nodes")
1820 ARCANE_THROW(IOException, "Unexpected string '{0}'. Valid values are '$Nodes'", next_line);
1821
1822 // Fetch nodes number and the coordinates
1824
1825 // $EndNodes
1826 if (ios_file && !ios_file->lookForString("$EndNodes"))
1827 ARCANE_THROW(IOException, "$EndNodes not found");
1828
1829 // $Elements
1830 if (ios_file && !ios_file->lookForString("$Elements"))
1831 ARCANE_THROW(IOException, "$Elements not found");
1832
1833 Int32 mesh_dimension = _readElementsFromFile();
1834
1835 // $EndElements
1836 if (ios_file && !ios_file->lookForString("$EndElements"))
1837 ARCANE_THROW(IOException, "$EndElements not found");
1838
1839 info() << "Computed mesh dimension = " << mesh_dimension;
1840
1841 IPrimaryMesh* pmesh = mesh->toPrimaryMesh();
1842 pmesh->setDimension(mesh_dimension);
1843
1844 info() << "NextLine=" << next_line;
1845
1846 bool is_end = _getIsEndOfFileAndBroadcast();
1847 if (!is_end) {
1848 next_line = _getNextLineAndBroadcast();
1849 // $Periodic
1850 if (next_line == "$Periodic") {
1851 _readPeriodic();
1852 }
1853 }
1854
1855 _allocateCells();
1857 _allocateGroups();
1858}
1859
1860/*---------------------------------------------------------------------------*/
1861/*---------------------------------------------------------------------------*/
1862
1863void MshParallelMeshReader::
1864_initTypes()
1865{
1866 // Initialise les types.
1867 // Il faut le faire au début de la lecture et ne plus en ajouter après.
1868 // La connectivité dans GMSH est décrite ici:
1869 // https://gmsh.info/doc/texinfo/gmsh.html#Node-ordering
1870 _addMshTypeInfo(MSH_PNT, ITI_Vertex);
1871 _addMshTypeInfo(MSH_LIN_2, ITI_Line2);
1872 _addMshTypeInfo(MSH_LIN_3, ITI_Line3);
1873 _addMshTypeInfo(MSH_TRI_3, ITI_Triangle3);
1874 _addMshTypeInfo(MSH_QUA_4, ITI_Quad4);
1875 _addMshTypeInfo(MSH_QUA_8, ITI_Quad8);
1876 _addMshTypeInfo(MSH_QUA_9, ITI_Quad9);
1877 _addMshTypeInfo(MSH_TET_4, ITI_Tetraedron4);
1878 _addMshTypeInfo(MSH_HEX_8, ITI_Hexaedron8);
1879 _addMshTypeInfo(MSH_PRI_6, ITI_Pentaedron6);
1880 _addMshTypeInfo(MSH_PRI_15, ITI_Pentaedron15);
1881 _addMshTypeInfo(MSH_PYR_5, ITI_Pyramid5);
1882 _addMshTypeInfo(MSH_PYR_13, ITI_Pyramid13);
1883 _addMshTypeInfo(MSH_TRI_6, ITI_Triangle6);
1884 {
1885 FixedArray<Int16, 10> x({ 0, 1, 2, 3, 4, 5, 6, 7, 9, 8 });
1886 _addMshTypeInfo(MSH_TET_10, ITI_Tetraedron10, x.view());
1887 }
1888 {
1889 FixedArray<Int16, 20> x({ 0, 1, 2, 3, 4, 5, 6, 7,
1890 8, 11, 13, 9, 16, 18, 19, 17, 10, 12, 14, 15 });
1891 _addMshTypeInfo(MSH_HEX_20, ITI_Hexaedron20, x.view());
1892 }
1893 {
1894 FixedArray<Int16, 27> x({ 0, 1, 2, 3, 4, 5, 6, 7,
1895 8, 11, 13, 9, 16, 18, 19, 17, 10, 12, 14, 15,
1896 22, 23, 21, 24, 20, 25, 26 });
1897 _addMshTypeInfo(MSH_HEX_27, ITI_Hexaedron27, x.view());
1898 }
1899}
1900
1901/*---------------------------------------------------------------------------*/
1902/*---------------------------------------------------------------------------*/
1903
1904void MshParallelMeshReader::
1905_addMshTypeInfo(Int32 msh_type, ItemTypeId arcane_type, ConstArrayView<Int16> reorder_infos)
1906{
1907 //info() << "ADD_TYPE msh_type=" << msh_type << " Arcane=" << arcane_type;
1908 if (msh_type < 0)
1909 ARCANE_FATAL("Bad MSH type {0}", msh_type);
1910 if (m_msh_to_arcane_type_infos.size() <= msh_type)
1911 m_msh_to_arcane_type_infos.resize(msh_type + 1);
1912 ItemTypeMng* item_type_mng = m_mesh->itemTypeMng();
1913 ItemTypeInfo* iti = item_type_mng->typeFromId(arcane_type);
1914 m_msh_to_arcane_type_infos[msh_type] = MshToArcaneTypeInfo(msh_type, iti, reorder_infos);
1915}
1916
1917/*---------------------------------------------------------------------------*/
1918/*---------------------------------------------------------------------------*/
1919
1920const MshParallelMeshReader::MshToArcaneTypeInfo& MshParallelMeshReader::
1921mshToArcaneTypeInfo(Int32 msh_type) const
1922{
1923 if (msh_type < m_msh_to_arcane_type_infos.size()) {
1924 const MshToArcaneTypeInfo& tx = m_msh_to_arcane_type_infos[msh_type];
1925 if (tx.m_arcane_type_info)
1926 return tx;
1927 }
1928 ARCANE_THROW(NotSupportedException, "MSH type '{0}' is not supported in Arcane", msh_type);
1929}
1930
1931/*---------------------------------------------------------------------------*/
1932/*---------------------------------------------------------------------------*/
1937readMeshFromMshFile(IMesh* mesh, const String& filename, bool use_internal_partition)
1938{
1939 m_mesh_info = impl::MshMeshGenerationInfo::getReference(mesh, true);
1940 info() << "Trying to read in parallel 'msh' file '" << filename << "'"
1941 << " use_internal_partition=" << use_internal_partition;
1942 m_mesh = mesh;
1943 IParallelMng* pm = mesh->parallelMng();
1944 // Lit en séquentiel si les fichiers sont déjà découpés
1945 if (!use_internal_partition)
1946 pm = pm->sequentialParallelMng();
1947 m_parallel_mng = pm;
1948 const Int32 nb_rank = pm->commSize();
1949
1950 // Détermine les rangs qui vont conserver les données.
1951 // Il n'est pas obligatoire que tous les rangs participent
1952 // à la conservation des données. L'idéal avec un
1953 // grand nombre de rangs serait qu'un rang sur 2 ou 4 participent.
1954 // Cependant, cela génère alors des partitions vides (pour
1955 // les rangs qui ne participent pas) et cela peut
1956 // faire planter certains partitionneurs (comme ParMetis)
1957 // lorsqu'il y a des partitions vides. Il faudrait d'abord
1958 // corriger ce problème.
1959 m_nb_part = nb_rank;
1960 m_parts_rank.resize(m_nb_part);
1961 for (Int32 i = 0; i < m_nb_part; ++i) {
1962 m_parts_rank[i] = i % nb_rank;
1963 }
1964
1965 bool is_master_io = pm->isMasterIO();
1966 Int32 master_io_rank = pm->masterIORank();
1967 m_is_parallel = pm->isParallel();
1968 m_master_io_rank = master_io_rank;
1969 FixedArray<Int32, 1> file_readable;
1970 // Seul le rang maître va lire le fichier.
1971 // On vérifie d'abord qu'il est lisible
1972 if (is_master_io) {
1973 bool is_readable = platform::isFileReadable(filename);
1974 info() << "Is file readable ?=" << is_readable;
1975 file_readable[0] = is_readable ? 1 : 0;
1976 if (!is_readable)
1977 error() << "Unable to read file '" << filename << "'";
1978 }
1979 pm->broadcast(file_readable.view(), master_io_rank);
1980 if (file_readable[0] == 0) {
1981 return IMeshReader::RTError;
1982 }
1983
1984 std::ifstream ifile;
1985 Ref<IosFile> ios_file;
1986 if (is_master_io) {
1987 // Ouvre toujours le fichier en binaire car on
1988 // ne sait pas à l'avance s'il est en mode texte ou binaire.
1989 ifile.open(filename.localstr(), ios::binary);
1990 ios_file = makeRef<IosFile>(new IosFile(&ifile));
1991 }
1992 m_ios_file = ios_file;
1993 String mesh_format_str = _getNextLineAndBroadcast();
1994 if (IosFile::isEqualString(mesh_format_str, "$MeshFormat")) {
1995 _readMeshFromFile();
1996 if (!use_internal_partition) {
1997 info() << "Synchronize groups and variables";
1998 mesh->synchronizeGroupsAndVariables();
1999 }
2000 return IMeshReader::RTOk;
2001 }
2002
2003 info() << "The file does not begin with '$MeshFormat' returning RTError";
2004 return IMeshReader::RTError;
2005}
2006
2007/*---------------------------------------------------------------------------*/
2008/*---------------------------------------------------------------------------*/
2009
2010extern "C++" Ref<IMshMeshReader>
2011createMshParallelMeshReader(ITraceMng* tm)
2012{
2014}
2015
2016/*---------------------------------------------------------------------------*/
2017/*---------------------------------------------------------------------------*/
2018
2019} // namespace Arcane
2020
2021/*---------------------------------------------------------------------------*/
2022/*---------------------------------------------------------------------------*/
#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.
Integer size() const
Nombre d'éléments du vecteur.
Vue modifiable d'un tableau d'un type T.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
void reserve(Int64 new_capacity)
Réserve le mémoire pour new_capacity éléments.
void addRange(ConstReferenceType val, Int64 n)
Ajoute n élément de valeur val à la fin du tableau.
ArrayView< T > view() const
Vue mutable sur ce tableau.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
Vue constante d'un tableau de type T.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
static std::optional< Int32 > tryParseFromEnvironment(StringView s, bool throw_if_invalid)
Definition Convert.cc:122
Tableau 1D de taille fixe.
Definition FixedArray.h:45
constexpr __host__ __device__ ArrayView< T > view()
Vue modifiable sur le tableau.
Definition FixedArray.h:97
constexpr __host__ __device__ SmallSpan< T, NbElement > span()
Vue modifiable sur le tableau.
Definition FixedArray.h:93
Informations sur le type flottant.
Definition Limits.h:48
Interface d'une famille d'entités.
Definition IItemFamily.h:84
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 Integer dimension()=0
Dimension du maillage (1D, 2D ou 3D).
eReturnType
Types des codes de retour d'une lecture ou écriture.
Definition IMeshReader.h:37
@ RTError
Erreur lors de l'opération.
Definition IMeshReader.h:39
@ RTOk
Opération effectuée avec succès.
Definition IMeshReader.h:38
virtual const MeshKind meshKind() const =0
Caractéristiques du maillage.
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 IParallelMng * sequentialParallelMng()=0
Retourne un gestionnaire de parallélisme séquentiel.
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.
virtual void endAllocate()=0
Indique une fin d'allocation de mailles.
virtual void allocateCells(Integer nb_cell, Int64ConstArrayView cells_infos, bool one_alloc=true)=0
Allocation d'un maillage.
virtual void setDimension(Integer dim)=0
Positionne la dimension du maillage (1D, 2D ou 3D).
Interface du gestionnaire de traces.
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:446
Type d'une entité (Item).
Definition ItemTypeId.h:32
Infos sur un type d'entité du maillage.
Integer nbLocalNode() const
Nombre de noeuds de l'entité
String typeName() const
Nom du type.
ItemTypeId itemTypeId() const
Numéro du type.
Gestionnaire des types d'entités d'un maillage.
Definition ItemTypeMng.h:65
ItemTypeInfo * typeFromId(Integer id) const
Type correspondant au numéro id.
Informations pour créer les entités d'un genre.
Informations pour créer les entités Arcane.
UniqueArray< Int64 > nodes_unique_id
UniqueId() des noeuds de ma partie.
std::unordered_map< Int64, Int32 > nodes_rank_map
Tableau associatif (uniqueId(),rang) auquel le noeud appartiendra.
UniqueArray< Real3 > nodes_coordinates
Coordonnées des noeuds de ma partie.
Informations de correspondance entre le type MSH et le type Arcane.
Lecteur de fichiers de maillage au format msh.
bool _getIsEndOfFileAndBroadcast()
Retourne true si on est à la fin du fichier.
Int32 m_verbosity_level
Niveau de verbosité
void _readPeriodic()
Lecture des informations périodiques.
Integer _readElementsFromFile()
Lecture des éléments (mailles,faces,...)
void _addCellOrNodeGroup(ArrayView< Int64 > block_uids, Int32 block_index, const String &group_name, IItemFamily *family, bool filter_invalid)
Ajoute des mailles ou noeuds au groupe group_name.
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.
UniqueArray< MshToArcaneTypeInfo > m_msh_to_arcane_type_infos
Informations de conversion entre les types MSH et Arcane pour les entités.
eReturnType readMeshFromMshFile(IMesh *mesh, const String &filename, bool use_internal_partition) override
Lit le maillage contenu dans le fichier filename et le construit dans mesh.
void _readNodesFromFile()
Lecture des noeuds du maillage.
void _setNodesCoordinates()
Positionne les coordonnées des noeuds.
bool m_is_binary
Vrai si le format est binaire.
void _addFaceGroup(const MshElementBlock &block, const String &group_name)
Ajoute des faces au groupe group_name.
void _readOneElementBlock(MshElementBlock &block)
Lit un bloc d'entité de type 'Element'.
String _getNextLineAndBroadcast()
Lis la valeur de la prochaine ligne et la broadcast aux autres rangs.
Vue sur les informations des noeuds.
Classe utilitaire pour réordonner les noeuds d'une entité.
Exception lorsqu'une opération n'est pas supportée.
Classe gérant un vecteur de réel de dimension 3.
Definition Real3.h:132
Référence à une instance.
InstanceType * get() const
Instance associée ou nullptr si aucune.
Tableau 1D de données avec buffer pré-alloué sur la pile.
Definition SmallArray.h:89
Vue d'un tableau d'éléments de type T.
Definition Span.h:673
constexpr __host__ __device__ SizeType size() const noexcept
Retourne la taille du tableau.
Definition Span.h:212
Vue d'un tableau d'éléments de type T.
Definition Span.h:513
Chaîne de caractères unicode.
const char * localstr() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:228
Span< const Byte > bytes() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:292
static String collapseWhiteSpace(const String &rhs)
Effectue une normalisation des caractères espaces.
Definition String.cc:453
TraceAccessor(ITraceMng *m)
Construit un accesseur via le gestionnaire de trace m.
TraceMessage info() const
Flot pour un message d'information.
TraceMessage error() const
Flot pour un message d'erreur.
Vecteur 1D de données avec sémantique par valeur (style STL).
UniqueArray< double > m_affine_values
Liste des valeurs affines.
UniqueArray< Int64 > m_corresponding_nodes
Liste de couples (uniqueId noeud esclave, unique() noeud maître)
Informations d'un maillage issu du format 'msh'.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
__host__ __device__ Real2 min(Real2 a, Real2 b)
Retourne le minimum de deux Real2.
Definition MathUtils.h:336
T max(const T &a, const T &b, const T &c)
Retourne le maximum de trois éléments.
Definition MathUtils.h:392
ItemGroupT< Face > FaceGroup
Groupe de faces.
Definition ItemTypes.h:178
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Grandeur au noeud de type coordonnées.
Int32 toInt32(Int64 v)
Converti un Int64 en un Int32.
@ ReduceSum
Somme des valeurs.
@ ReduceMin
Minimum des valeurs.
@ ReduceMax
Maximum des valeurs.
constexpr __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
ARCCORE_BASE_EXPORT bool isFileReadable(const String &file_name)
Vérifie que le fichier file_name est accessible et lisible.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
ConstArrayView< Int64 > Int64ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:567
std::int16_t Int16
Type entier signé sur 16 bits.
double Real
Type représentant un réel.
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Créé une référence sur un pointeur.
std::int32_t Int32
Type entier signé sur 32 bits.
Infos d'un bloc pour $Elements pour la version 4.
UniqueArray< Int64 > connectivities
< Liste des uniqueId() du bloc
Int32 item_nb_node
Nombre de noeuds de l'entité.
SmallSpan< const Int16 > reorder_infos
Si non vide, contient les indirections pour la renumérotation.
Int32 entity_dim
Dimension de l'entité associée.
Int64 index_in_allocation_info
Index dans MshMeshAllocateInfo des noeuds de ce bloc.
Real x
première composante du triplet
Definition Real3.h:35