Arcane  v4.1.1.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 node_block.nb_node = nodes_uids.size();
707 }
708 }
709
710 // Lecture par partie des coordonnées
711 for (Int32 i_part = 0; i_part < m_nb_part; ++i_part) {
712 Int64 nb_to_read = _interval(i_part, m_nb_part, nb_node2).second;
713 Int32 dest_rank = m_parts_rank[i_part];
714 info(4) << "Reading COORDS part i=" << i_part << " dest_rank=" << dest_rank << " nb_to_read=" << nb_to_read;
715 if (my_rank == dest_rank || my_rank == m_master_io_rank) {
716 nodes_coordinates.resize(nb_to_read);
717 }
718
719 // Le rang maitre lit les informations des noeuds pour la partie concernée
720 // et les transfère au rang destination
721 if (ios_file) {
722 if (m_is_binary) {
723 ios_file->binaryRead(nodes_coordinates.view());
724 }
725 else {
726 for (Integer i = 0; i < nb_to_read; ++i) {
727 nodes_coordinates[i] = _getReal3();
728 //info() << "I=" << i << " ID=" << nodes_uids[i] << " COORD=" << Real3(nx, ny, nz);
729 }
730 }
731 if (dest_rank != m_master_io_rank) {
732 pm->send(nodes_coordinates, dest_rank);
733 }
734 }
735 else if (my_rank == dest_rank) {
736 pm->recv(nodes_coordinates, m_master_io_rank);
737 }
738
739 // Conserve les informations de ma partie
740 if (my_rank == dest_rank) {
741 m_mesh_allocate_info.nodes_coordinates.addRange(nodes_coordinates);
742 }
743 }
744
745 if (!m_is_binary)
746 _goToNextLine();
747}
748
749/*---------------------------------------------------------------------------*/
750/*---------------------------------------------------------------------------*/
756{
757 IosFile* ios_file = m_ios_file.get();
758 IParallelMng* pm = m_parallel_mng;
759 const Int32 my_rank = pm->commRank();
760 const Int64 nb_entity_in_block = block.nb_entity;
761 const Int32 item_nb_node = block.item_nb_node;
762 const bool is_print_level1 = m_verbosity_level > 0;
763 const bool is_print_level2 = m_verbosity_level > 1;
764
765 if (is_print_level1)
766 info() << "Reading block nb_entity=" << nb_entity_in_block << " item_nb_node=" << item_nb_node;
767
769 UniqueArray<Int64> connectivities;
770
771 UniqueArray<Int64> tmp_uid_and_connectivities;
772
773 for (Int32 i_part = 0; i_part < m_nb_part; ++i_part) {
774 const Int64 nb_to_read = _interval(i_part, m_nb_part, nb_entity_in_block).second;
775 const Int32 dest_rank = m_parts_rank[i_part];
776
777 if (is_print_level2)
778 info(4) << "Reading block part i_part=" << i_part
779 << " nb_to_read=" << nb_to_read << " dest_rank=" << dest_rank;
780
781 const Int64 nb_uid = nb_to_read;
782 const Int64 nb_connectivity = nb_uid * item_nb_node;
783 if (my_rank == dest_rank || my_rank == m_master_io_rank) {
784 uids.resize(nb_uid);
785 connectivities.resize(nb_connectivity);
786 }
787 if (ios_file) {
788 if (m_is_binary) {
789 Int64 nb_to_read = nb_uid * (item_nb_node + 1);
790 tmp_uid_and_connectivities.resize(nb_to_read);
791 ios_file->binaryRead(tmp_uid_and_connectivities.view());
792 Int64 index = 0;
793 for (Int64 i = 0; i < nb_uid; ++i) {
794 Int64 item_unique_id = tmp_uid_and_connectivities[index];
795 ++index;
796 uids[i] = item_unique_id;
797 for (Int32 j = 0; j < item_nb_node; ++j) {
798 connectivities[(i * item_nb_node) + j] = tmp_uid_and_connectivities[index];
799 ++index;
800 }
801 }
802 }
803 else {
804 // Utilise des Int64 pour garantir qu'on ne déborde pas.
805 for (Int64 i = 0; i < nb_uid; ++i) {
806 Int64 item_unique_id = ios_file->getInt64();
807 uids[i] = item_unique_id;
808 for (Int32 j = 0; j < item_nb_node; ++j)
809 connectivities[(i * item_nb_node) + j] = ios_file->getInt64();
810 }
811 }
812 if (dest_rank != m_master_io_rank) {
813 pm->send(uids, dest_rank);
814 pm->send(connectivities, dest_rank);
815 }
816 }
817 else if (my_rank == dest_rank) {
818 pm->recv(uids, m_master_io_rank);
819 pm->recv(connectivities, m_master_io_rank);
820 }
821 if (my_rank == dest_rank) {
822 block.uids.addRange(uids);
823 block.connectivities.addRange(connectivities);
824 }
825 }
826}
827
828/*---------------------------------------------------------------------------*/
829/*---------------------------------------------------------------------------*/
860{
861 IosFile* ios_file = m_ios_file.get();
862 IParallelMng* pm = m_parallel_mng;
863
864 const bool is_print_level1 = m_verbosity_level > 0;
865
866 FixedArray<Int64, 4> elements_info;
867 _getInt64ArrayAndBroadcast(elements_info.view());
868
869 Int64 nb_block = elements_info[0];
870 Int64 number_of_elements = elements_info[1];
871 Int64 min_element_tag = elements_info[2];
872 Int64 max_element_tag = elements_info[3];
873
874 if (!m_is_binary)
875 _goToNextLine();
876
877 info() << "[Elements] nb_block=" << nb_block
878 << " nb_elements=" << number_of_elements
879 << " min_element_tag=" << min_element_tag
880 << " max_element_tag=" << max_element_tag;
881
882 if (number_of_elements < 0)
883 ARCANE_THROW(IOException, "Invalid number of elements: {0}", number_of_elements);
884
885 UniqueArray<MshElementBlock>& blocks = m_mesh_allocate_info.element_blocks;
886 blocks.resize(nb_block);
887
888 {
889 // Numérote les blocs (pour le débug)
890 Integer index = 0;
891 for (MshElementBlock& block : blocks) {
892 block.index = index;
893 ++index;
894 }
895 }
896
897 for (MshElementBlock& block : blocks) {
898
899 FixedArray<Int32, 3> block_info;
900 _getInt32ArrayAndBroadcast(block_info.view());
901
902 Int32 entity_dim = block_info[0];
903 Int32 entity_tag = block_info[1];
904 Int32 entity_type = block_info[2];
905 Int64 nb_entity_in_block = _getInt64AndBroadcast();
906
907 const MshToArcaneTypeInfo& msh_tinfo = mshToArcaneTypeInfo(entity_type);
908 ItemTypeInfo* tinfo = msh_tinfo.m_arcane_type_info;
909 Int32 item_nb_node = tinfo->nbLocalNode();
910 ItemTypeId item_type = tinfo->itemTypeId();
911
912 if (is_print_level1)
913 info() << "[Elements] index=" << block.index << " entity_dim=" << entity_dim
914 << " entity_tag=" << entity_tag
915 << " msh_entity_type=" << entity_type << " nb_in_block=" << nb_entity_in_block
916 << " arcane_item_type=" << item_type << " item_nb_node=" << item_nb_node;
917
918 block.nb_entity = nb_entity_in_block;
919 block.item_type = item_type;
920 block.item_nb_node = item_nb_node;
921 block.dimension = entity_dim;
922 block.entity_tag = entity_tag;
923 block.reorder_infos = msh_tinfo.m_reorder_infos;
924 if (entity_type == MSH_PNT) {
925 // Si le type est un point, le traitement semble un peu particulier.
926 // Il y a dans ce cas deux entiers dans la ligne suivante:
927 // - un entier qui ne semble pas être utilisé
928 // - le numéro unique du noeud qui nous intéresse
929 Int64 item_unique_id = NULL_ITEM_UNIQUE_ID;
930 if (ios_file) {
931 [[maybe_unused]] Int64 unused_id = _getInt64();
932 item_unique_id = _getInt64();
933 if (is_print_level1)
934 info() << "Adding unique node uid=" << item_unique_id;
935 }
936 if (m_is_parallel)
937 pm->broadcast(ArrayView<Int64>(1, &item_unique_id), m_master_io_rank);
938 block.uids.add(item_unique_id);
939 }
940 else {
942 }
943 if (!m_is_binary)
944 _goToNextLine();
945 }
946
947 if (m_is_binary)
948 _goToNextLine();
949
950 // Maintenant qu'on a tous les blocs, la dimension du maillage est
951 // la plus grande dimension des blocs
952 Integer mesh_dimension = -1;
953 for (const MshElementBlock& block : blocks)
954 mesh_dimension = math::max(mesh_dimension, block.dimension);
955 if (mesh_dimension < 0)
956 ARCANE_FATAL("Invalid computed mesh dimension '{0}'", mesh_dimension);
957 if (mesh_dimension != 2 && mesh_dimension != 3)
958 ARCANE_THROW(NotSupportedException, "mesh dimension '{0}'. Only 2D or 3D meshes are supported", mesh_dimension);
959 info() << "Computed mesh dimension = " << mesh_dimension;
960
961 bool allow_multi_dim_cell = m_mesh->meshKind().isNonManifold();
962 bool use_experimental_type_for_cell = false;
963 if (allow_multi_dim_cell) {
964 // Par défaut utilise les nouveaux types.
965 use_experimental_type_for_cell = true;
966 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_USE_EXPERIMENTAL_CELL_TYPE", true))
967 use_experimental_type_for_cell = (v.value() != 0);
968 }
969 info() << "Use experimental cell type?=" << use_experimental_type_for_cell;
970 ItemTypeMng* item_type_mng = m_mesh->itemTypeMng();
971 for (MshElementBlock& block : blocks) {
972 const Int32 block_dim = block.dimension;
973 String item_type_name = item_type_mng->typeFromId(block.item_type)->typeName();
974 if (is_print_level1)
975 info() << "Reading block dim=" << block_dim << " type_name=" << item_type_name;
976 if (block_dim == mesh_dimension)
977 _computeOwnItems(block, m_mesh_allocate_info.cells_infos, false);
978 else if (allow_multi_dim_cell) {
979 // Regarde si on peut créé des mailles de dimension inférieures à celles
980 // du maillage.
981 bool use_sub_dim_cell = false;
982 if (mesh_dimension == 3 && (block_dim == 2 || block_dim == 1))
983 // Maille 1D ou 2D dans un maillage 3D
984 use_sub_dim_cell = true;
985 else if (mesh_dimension == 2 && block_dim == 1)
986 // Maille 1D dans un maillage 2D
987 use_sub_dim_cell = true;
988 if (!use_experimental_type_for_cell)
989 use_sub_dim_cell = false;
990 if (use_sub_dim_cell) {
991 // Ici on va créer des mailles 2D dans un maillage 3D.
992 // On converti le type de base en un type équivalent pour les mailles.
993 if (mesh_dimension == 3) {
994 if (block.item_type == IT_Triangle3)
995 block.item_type = ItemTypeId(IT_Cell3D_Triangle3);
996 else if (block.item_type == IT_Triangle6)
997 block.item_type = ItemTypeId(ITI_Cell3D_Triangle6);
998 else if (block.item_type == IT_Quad4)
999 block.item_type = ItemTypeId(IT_Cell3D_Quad4);
1000 else if (block.item_type == IT_Quad8)
1001 block.item_type = ItemTypeId(IT_Cell3D_Quad8);
1002 else if (block.item_type == IT_Quad9)
1003 block.item_type = ItemTypeId(IT_Cell3D_Quad9);
1004 else if (block.item_type == IT_Line2)
1005 block.item_type = ItemTypeId(IT_Cell3D_Line2);
1006 else if (block.item_type == IT_Line3)
1007 block.item_type = ItemTypeId(IT_Cell3D_Line3);
1008 else
1009 ARCANE_FATAL("Not supported sub dimension cell type={0} for 3D mesh", item_type_name);
1010 }
1011 else if (mesh_dimension == 2) {
1012 if (block.item_type == IT_Line2)
1013 block.item_type = ItemTypeId(IT_CellLine2);
1014 else if (block.item_type == IT_Line3)
1015 block.item_type = ItemTypeId(IT_CellLine3);
1016 else
1017 ARCANE_FATAL("Not supported sub dimension cell type={0} for 2D mesh", item_type_name);
1018 }
1019 block.is_built_as_cells = true;
1020 _computeOwnItems(block, m_mesh_allocate_info.cells_infos, false);
1021 }
1022 }
1023 }
1024
1025 return mesh_dimension;
1026}
1027
1028/*---------------------------------------------------------------------------*/
1029/*---------------------------------------------------------------------------*/
1030
1031namespace
1032{
1033 template <typename DataType> inline ArrayView<DataType>
1034 _broadcastArrayWithSize(IParallelMng* pm, ArrayView<DataType> values,
1035 UniqueArray<DataType>& work_values, Int32 dest_rank, Int64 size)
1036 {
1037 const Int32 my_rank = pm->commRank();
1038 ArrayView<DataType> view = values;
1039 if (my_rank != dest_rank) {
1040 work_values.resize(size);
1041 view = work_values.view();
1042 }
1043 pm->broadcast(view, dest_rank);
1044 return view;
1045 }
1053 template <typename DataType> inline ArrayView<DataType>
1054 _broadcastArray(IParallelMng* pm, ArrayView<DataType> values,
1055 UniqueArray<DataType>& work_values, Int32 dest_rank)
1056 {
1057 const Int32 my_rank = pm->commRank();
1058 Int64 size = 0;
1059 // Envoie la taille
1060 if (dest_rank == my_rank)
1061 size = values.size();
1062 pm->broadcast(ArrayView<Int64>(1, &size), dest_rank);
1063 return _broadcastArrayWithSize(pm, values, work_values, dest_rank, size);
1064 }
1065
1066} // namespace
1067
1068/*---------------------------------------------------------------------------*/
1069/*---------------------------------------------------------------------------*/
1070
1071void MshParallelMeshReader::
1072_computeOwnItems(MshElementBlock& block, MshItemKindInfo& item_kind_info, bool is_generate_uid)
1073{
1074 // On ne conserve que les entités dont le premier noeud appartient à notre rang.
1075
1076 IParallelMng* pm = m_parallel_mng;
1077 const Int32 my_rank = pm->commRank();
1078 const bool is_print_level1 = m_verbosity_level > 0;
1079
1080 const ItemTypeId item_type = block.item_type;
1081 const Int32 item_nb_node = block.item_nb_node;
1082
1083 UniqueArray<Int64> connectivities;
1084 UniqueArray<Int64> uids;
1085 UniqueArray<Int32> nodes_rank;
1086
1087 SmallSpan<const Int16> reorder_infos = block.reorder_infos;
1088 bool has_reorder_info = !reorder_infos.empty();
1089 const Int32 nb_part = m_parts_rank.size();
1090 if (is_print_level1)
1091 info() << "Compute own items block_index=" << block.index << " nb_part=" << nb_part
1092 << " has_reorder?=" << has_reorder_info;
1093 // Liste des noeuds de l'élément avec la connectivité Arcane.
1094 SmallArray<Int64> arcane_reordered_uids;
1095 if (has_reorder_info)
1096 arcane_reordered_uids.resize(item_nb_node);
1097 for (Int32 i_part = 0; i_part < nb_part; ++i_part) {
1098 const Int32 dest_rank = m_parts_rank[i_part];
1099 // Broadcast la i_part-ème partie des uids et connectivités des mailles
1100 ArrayView<Int64> connectivities_view = _broadcastArray(pm, block.connectivities.view(), connectivities, dest_rank);
1101 ArrayView<Int64> uids_view = _broadcastArray(pm, block.uids.view(), uids, dest_rank);
1102
1103 Int32 nb_item = uids_view.size();
1104 nodes_rank.resize(nb_item);
1105 nodes_rank.fill(-1);
1106
1107 // Parcours les entités. Chaque entité appartiendra au rang
1108 // de son premier noeud. Si cette partie correspond à mon rang, alors
1109 // on conserve la maille.
1110 for (Int32 i = 0; i < nb_item; ++i) {
1111 Int64 first_node_uid = connectivities_view[i * item_nb_node];
1112 auto x = m_mesh_allocate_info.nodes_rank_map.find(first_node_uid);
1113 if (x == m_mesh_allocate_info.nodes_rank_map.end())
1114 // Le noeud n'est pas dans ma liste
1115 continue;
1116 Int32 rank = x->second;
1117 nodes_rank[i] = rank;
1118 }
1119 pm->reduce(Parallel::ReduceMax, nodes_rank);
1120 for (Int32 i = 0; i < nb_item; ++i) {
1121 const Int32 rank = nodes_rank[i];
1122 if (rank != my_rank)
1123 // Le noeud n'est pas dans ma partie
1124 continue;
1125 // Le noeud est chez moi, j'ajoute l'entité à la liste des
1126 // entités que je vais créer.
1127 ConstArrayView<Int64> v = connectivities_view.subView(i * item_nb_node, item_nb_node);
1128 Int64 uid = uids_view[i];
1129 if (is_generate_uid)
1130 // Le uniqueId() sera généré automatiquement
1131 uid = NULL_ITEM_UNIQUE_ID;
1132 if (has_reorder_info) {
1133 // Réordonne les noeuds si le type Arcane n'a pas la même numérotation
1134 // que le type MSH.
1135 for (Int32 zz = 0; zz < item_nb_node; ++zz)
1136 arcane_reordered_uids[zz] = v[reorder_infos[zz]];
1137 v = arcane_reordered_uids.view();
1138 }
1139 item_kind_info.addItem(item_type, uid, v);
1140 }
1141 }
1142}
1143
1144/*---------------------------------------------------------------------------*/
1145/*---------------------------------------------------------------------------*/
1162{
1163 UniqueArray<Int64> uids_storage;
1164 UniqueArray<Real3> coords_storage;
1165 UniqueArray<Int32> local_ids;
1166
1167 IParallelMng* pm = m_parallel_mng;
1168
1169 const IItemFamily* node_family = m_mesh->nodeFamily();
1170 VariableNodeReal3& nodes_coord_var(m_mesh->nodesCoordinates());
1171
1172 for (Int32 dest_rank : m_parts_rank) {
1173 ConstArrayView<Int64> uids = _broadcastArray(pm, m_mesh_allocate_info.nodes_unique_id.view(), uids_storage, dest_rank);
1174 ConstArrayView<Real3> coords = _broadcastArray(pm, m_mesh_allocate_info.nodes_coordinates.view(), coords_storage, dest_rank);
1175
1176 Int32 nb_item = uids.size();
1177 local_ids.resize(nb_item);
1178
1179 // Converti les uniqueId() en localId(). S'ils sont non nuls
1180 // c'est que l'entité est dans mon sous-domaine et donc on peut
1181 // positionner sa coordonnée
1182 node_family->itemsUniqueIdToLocalId(local_ids, uids, false);
1183 for (Int32 i = 0; i < nb_item; ++i) {
1184 NodeLocalId nid(local_ids[i]);
1185 if (!nid.isNull())
1186 nodes_coord_var[nid] = coords[i];
1187 }
1188 }
1189}
1190
1191/*---------------------------------------------------------------------------*/
1192/*---------------------------------------------------------------------------*/
1193
1194void MshParallelMeshReader::
1195_allocateCells()
1196{
1197 IMesh* mesh = m_mesh;
1198 Integer nb_elements = m_mesh_allocate_info.cells_infos.nb_item;
1199 info() << "nb_of_elements=cells_type.size()=" << nb_elements;
1200 Integer nb_cell_node = m_mesh_allocate_info.cells_infos.items_infos.size();
1201 info() << "nb_cell_node=cells_connectivity.size()=" << nb_cell_node;
1202
1203 // Création des mailles
1204 info() << "Building cells, nb_cell=" << nb_elements << " nb_cell_node=" << nb_cell_node;
1205 IPrimaryMesh* pmesh = mesh->toPrimaryMesh();
1206 info() << "## Allocating ##";
1207 pmesh->allocateCells(nb_elements, m_mesh_allocate_info.cells_infos.items_infos, false);
1208 info() << "## Ending ##";
1209 pmesh->endAllocate();
1210 info() << "## Done ##";
1211}
1212
1213/*---------------------------------------------------------------------------*/
1214/*---------------------------------------------------------------------------*/
1215
1216void MshParallelMeshReader::
1217_allocateGroups()
1218{
1219 IMesh* mesh = m_mesh;
1220 Int32 mesh_dim = mesh->dimension();
1221 Int32 face_dim = mesh_dim - 1;
1222 UniqueArray<MshEntitiesWithNodes> entity_list;
1223 UniqueArray<MshPhysicalName> physical_name_list;
1224 IItemFamily* node_family = mesh->nodeFamily();
1225
1226 for (MshElementBlock& block : m_mesh_allocate_info.element_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 MshEntitiesNodes* 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->physicalTag();
1246 MshPhysicalName physical_name = m_mesh_info->findPhysicalName(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 MshEntitiesWithNodes& x : entity_list) {
1252 Int64 entity_physical_tag = x.physicalTag();
1253 MshPhysicalName physical_name = m_mesh_info->findPhysicalName(block_dim, entity_physical_tag);
1254 physical_name_list.add(physical_name);
1255 }
1256 }
1257 for (const MshPhysicalName& 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 String group_name = physical_name.name();
1264 info(4) << "[Groups] Block index=" << block_index << " dim=" << block_dim
1265 << " name='" << group_name << "' built_as_cells=" << block.is_built_as_cells;
1266 if (block_dim == mesh_dim || block.is_built_as_cells) {
1267 _addCellOrNodeGroup(block.uids, block.index, group_name, mesh->cellFamily(), false);
1268 }
1269 else if (block_dim == face_dim) {
1270 _addFaceGroup(block, group_name);
1271 }
1272 else {
1273 // Il s'agit de noeuds
1274 _addCellOrNodeGroup(block.uids, block.index, group_name, node_family, false);
1275 }
1276 }
1277 }
1278
1279 // Crée les groupes de noeuds associés aux blocs de $Nodes
1280 {
1281 //bool has_periodic = m_mesh_info->m_periodic_info.hasValues();
1282 UniqueArray<Int64>& nodes_uids = m_mesh_allocate_info.nodes_unique_id;
1283 // Créé les groupes de noeuds issus des blocks dans $Nodes
1284 for (const MshNodeBlock& block : m_mesh_allocate_info.node_blocks) {
1285 ArrayView<Int64> block_uids = nodes_uids.subView(block.index_in_allocation_info, block.nb_node);
1286 MshPhysicalName physical_name = m_mesh_info->findPhysicalName(block.entity_dim, block.entity_tag);
1287 String group_name = physical_name.name();
1288 info(4) << "NodeBlock name=" << group_name << " index=" << block.index
1289 << " index_in_allocation=" << block.index_in_allocation_info
1290 << " nb_node=" << block.nb_node;
1291 // Si on a des infos de périodicité, on crée toujours les groupes de noeuds correspondants
1292 // aux blocs, car ils peuvent être référencés par les infos de périodicité.
1293 // Dans ce cas, on génère un nom de groupe.
1294 // NOTE: désactive cela car cela peut générer un très grand nombre de nombre de groupes
1295 // lorsqu'il y a beaucoup d'informations de périodicité et en plus on n'utilise pas encore
1296 // cela lors de l'écriture des informations périodiques.
1297 //if (physical_name.isNull() && has_periodic)
1298 //group_name = String::format("ArcaneMshInternalNodesDim{0}Entity{1}", block.entity_dim, block.entity_tag);
1299 if (!group_name.null())
1300 _addCellOrNodeGroup(block_uids, block.index, group_name, node_family, true);
1301 }
1302 }
1303}
1304
1305/*---------------------------------------------------------------------------*/
1306/*---------------------------------------------------------------------------*/
1311_addFaceGroup(const MshElementBlock& block, const String& group_name)
1312{
1313 IParallelMng* pm = m_parallel_mng;
1314
1315 UniqueArray<Int64> connectivities;
1316 for (Int32 dest_rank : m_parts_rank) {
1317 ArrayView<Int64> connectivities_view = _broadcastArray(pm, block.connectivities.view(), connectivities, dest_rank);
1318 _addFaceGroupOnePart(block, connectivities_view, group_name);
1319 }
1320}
1321
1322/*---------------------------------------------------------------------------*/
1323/*---------------------------------------------------------------------------*/
1324
1325void MshParallelMeshReader::
1326_addFaceGroupOnePart(const MshElementBlock& block, ConstArrayView<Int64> connectivities,
1327 const String& group_name)
1328{
1329 IMesh* mesh = m_mesh;
1330 const Int32 item_nb_node = block.item_nb_node;
1331 const Int32 block_index = block.index;
1332 const ItemTypeId type_id = block.item_type;
1333 const Int32 nb_entity = connectivities.size() / item_nb_node;
1334
1335 // Il peut y avoir plusieurs blocs pour le même groupe.
1336 // On récupère le groupe s'il existe déjà.
1337 FaceGroup face_group = mesh->faceFamily()->findGroup(group_name, true);
1338
1339 UniqueArray<Int32> faces_id; // Numéro de la face dans le maillage \a mesh
1340 faces_id.reserve(nb_entity);
1341
1342 const Int32 face_nb_node = nb_entity * item_nb_node;
1343
1344 UniqueArray<Int64> faces_first_node_unique_id(nb_entity);
1345 UniqueArray<Int32> faces_first_node_local_id(nb_entity);
1346 UniqueArray<Int64> faces_nodes_unique_id(face_nb_node);
1347 Integer faces_nodes_unique_id_index = 0;
1348
1349 UniqueArray<Int64> orig_nodes_id(item_nb_node);
1350 //UniqueArray<Integer> face_nodes_index(item_nb_node);
1351
1352 IItemFamily* node_family = mesh->nodeFamily();
1353 NodeInfoListView mesh_nodes(node_family);
1354 NodesOfItemReorderer m_nodes_reorderer(mesh->itemTypeMng());
1355
1356 // Réordonne les identifiants des faces retrouver la face dans le maillage.
1357 // Pour cela, on récupère le premier noeud de la face et on regarde s'il
1358 // se trouve dans notre sous-domaine. Si oui, la face sera ajoutée à notre
1359 // partie du maillage
1360 for (Integer i_face = 0; i_face < nb_entity; ++i_face) {
1361 for (Integer z = 0; z < item_nb_node; ++z)
1362 orig_nodes_id[z] = connectivities[faces_nodes_unique_id_index + z];
1363 m_nodes_reorderer.reorder(type_id, orig_nodes_id);
1364 ConstArrayView<Int64> sorted_nodes(m_nodes_reorderer.sortedNodes());
1365 for (Integer z = 0; z < item_nb_node; ++z)
1366 faces_nodes_unique_id[faces_nodes_unique_id_index + z] = sorted_nodes[z];
1367 faces_first_node_unique_id[i_face] = sorted_nodes[0];
1368 faces_nodes_unique_id_index += item_nb_node;
1369 }
1370
1371 node_family->itemsUniqueIdToLocalId(faces_first_node_local_id, faces_first_node_unique_id, false);
1372
1373 const bool is_non_manifold = m_mesh->meshKind().isNonManifold();
1374 faces_nodes_unique_id_index = 0;
1375 for (Integer i_face = 0; i_face < nb_entity; ++i_face) {
1376 const Integer n = item_nb_node;
1377 Int32 face_first_node_lid = faces_first_node_local_id[i_face];
1378 if (face_first_node_lid != NULL_ITEM_LOCAL_ID) {
1379 Int64ConstArrayView face_nodes_id(item_nb_node, &faces_nodes_unique_id[faces_nodes_unique_id_index]);
1380 Node current_node(mesh_nodes[faces_first_node_local_id[i_face]]);
1381 Face face = MeshUtils::getFaceFromNodesUniqueId(current_node, face_nodes_id);
1382
1383 // En parallèle, il est possible que la face ne soit pas dans notre sous-domaine
1384 // même si un de ses noeuds l'est
1385 if (face.null()) {
1386 if (!m_is_parallel) {
1387 OStringStream ostr;
1388 ostr() << "(Nodes:";
1389 for (Integer z = 0; z < n; ++z)
1390 ostr() << ' ' << face_nodes_id[z];
1391 ostr() << " - node_lid=" << current_node.localId() << ")";
1392 String error_string = "INTERNAL: MshMeshReader face index={0} with nodes '{1}' is not in node/face connectivity.";
1393 if (!is_non_manifold)
1394 error_string = error_string + "\n This errors may occur if the mesh is non-manifold."
1395 "\n See Arcane documentation to specify the mesh is a non manifold one.\n";
1396 ARCANE_FATAL(error_string, i_face, ostr.str());
1397 }
1398 }
1399 else
1400 faces_id.add(face.localId());
1401 }
1402
1403 faces_nodes_unique_id_index += n;
1404 }
1405 info(4) << "Adding " << faces_id.size() << " faces from block index=" << block_index
1406 << " to group '" << face_group.name() << "'";
1407 face_group.addItems(faces_id);
1408}
1409
1410/*---------------------------------------------------------------------------*/
1411/*---------------------------------------------------------------------------*/
1416_addCellOrNodeGroup(ArrayView<Int64> block_uids, Int32 block_index,
1417 const String& group_name, IItemFamily* family, bool filter_invalid)
1418{
1419 IParallelMng* pm = m_parallel_mng;
1420
1421 UniqueArray<Int64> uids;
1422 for (Int32 dest_rank : m_parts_rank) {
1423 ArrayView<Int64> uids_view = _broadcastArray(pm, block_uids, uids, dest_rank);
1424 _addCellOrNodeGroupOnePart(uids_view, group_name, block_index, family, filter_invalid);
1425 }
1426}
1427
1428/*---------------------------------------------------------------------------*/
1429/*---------------------------------------------------------------------------*/
1430
1431void MshParallelMeshReader::
1432_addCellOrNodeGroupOnePart(ConstArrayView<Int64> uids, const String& group_name,
1433 Int32 block_index, IItemFamily* family, bool filter_invalid)
1434{
1435 const Int32 nb_entity = uids.size();
1436
1437 // Il peut y avoir plusieurs blocs pour le même groupe.
1438 // On récupère le groupe s'il existe déjà.
1439 ItemGroup group = family->findGroup(group_name, true);
1440
1441 UniqueArray<Int32> items_lid(nb_entity);
1442
1443 family->itemsUniqueIdToLocalId(items_lid, uids, false);
1444
1445 // En parallèle, il est possible que certaines entités du groupe ne soient
1446 // pas dans notre sous-domaine. Il faut les filtrer.
1447 // De même, s'il s'agit d'un groupe issu d'une $Entity node, il est possible
1448 // que le noeud n'existe pas s'il n'est pas attaché à une maille
1449 // (TODO: à vérifier avec sod3d-misc.msh)
1450 if (m_is_parallel || filter_invalid) {
1451 auto items_begin = items_lid.begin();
1452 Int64 new_size = std::remove(items_begin, items_lid.end(), NULL_ITEM_LOCAL_ID) - items_begin;
1453 items_lid.resize(new_size);
1454 }
1455
1456 info() << "Adding " << items_lid.size() << " items from block index=" << block_index
1457 << " to group '" << group_name << "' for family=" << family->name();
1458
1459 group.addItems(items_lid);
1460}
1461
1462/*---------------------------------------------------------------------------*/
1463/*---------------------------------------------------------------------------*/
1464/*
1465 * $PhysicalNames // same as MSH version 2
1466 * numPhysicalNames(ASCII int)
1467 * dimension(ASCII int) physicalTag(ASCII int) "name"(127 characters max)
1468 * ...
1469 * $EndPhysicalNames
1470 */
1471void MshParallelMeshReader::
1472_readPhysicalNames()
1473{
1474 // NOTE: même en binaire, la partie $PhysicalNames est écrite en ASCII.
1475 String quote_mark = "\"";
1476 Int32 nb_name = _getIntegerAndBroadcast();
1477 info() << "nb_physical_name=" << nb_name;
1478
1479 _goToNextLine();
1480
1481 for (Int32 i = 0; i < nb_name; ++i) {
1482 Int32 dim = _getIntegerAndBroadcast();
1483 Int32 tag = _getIntegerAndBroadcast();
1484 String s = _getNextLineAndBroadcast();
1485 if (dim < 0 || dim > 3)
1486 ARCANE_FATAL("Invalid value for physical name dimension dim={0}", dim);
1487 // Les noms des groupes peuvent commencer par des espaces et contiennent
1488 // des guillemets qu'il faut supprimer.
1490 if (s.startsWith(quote_mark))
1491 s = s.substring(1);
1492 if (s.endsWith(quote_mark))
1493 s = s.substring(0, s.length() - 1);
1494 m_mesh_info->physical_name_list.add(dim, tag, s);
1495 info(4) << "[PhysicalName] index=" << i << " dim=" << dim << " tag=" << tag << " name='" << s << "'";
1496 }
1497
1498 String s = _getNextLineAndBroadcast();
1499 if (s != "$EndPhysicalNames")
1500 ARCANE_FATAL("found '{0}' and expected '$EndPhysicalNames'", s);
1501}
1502
1503/*---------------------------------------------------------------------------*/
1504/*---------------------------------------------------------------------------*/
1537{
1538 IosFile* ios_file = m_ios_file.get();
1539
1540 FixedArray<Int64, 4> nb_dim_item;
1541 _getInt64ArrayAndBroadcast(nb_dim_item.view());
1542
1543 const bool is_print_level1 = m_verbosity_level > 0;
1544
1545 info() << "[Entities] nb_0d=" << nb_dim_item[0] << " nb_1d=" << nb_dim_item[1]
1546 << " nb_2d=" << nb_dim_item[2] << " nb_3d=" << nb_dim_item[3];
1547 // Après le format, on peut avoir les entités mais cela est optionnel
1548 // Si elles sont présentes, on lit le fichier jusqu'à la fin de cette section.
1549 if (!m_is_binary)
1550 _goToNextLine();
1551
1552 // Lecture des entités associées à des points
1553 for (Int64 i = 0; i < nb_dim_item[0]; ++i) {
1554 FixedArray<Int64, 2> tag_info;
1555 if (ios_file) {
1556 Int32 tag = _getInt32();
1557 Real3 xyz = _getReal3();
1558 Int64 num_physical_tag = _getInt64();
1559 if (num_physical_tag > 1)
1560 ARCANE_FATAL("NotImplemented numPhysicalTag>1 (n={0}, index={1} xyz={2})",
1561 num_physical_tag, i, xyz);
1562
1563 Int32 physical_tag = -1;
1564 if (num_physical_tag == 1)
1565 physical_tag = _getInt32();
1566 if (is_print_level1)
1567 info() << "[Entities] point tag=" << tag << " pos=" << xyz << " phys_tag=" << physical_tag;
1568
1569 tag_info[0] = tag;
1570 tag_info[1] = physical_tag;
1571 }
1572 m_parallel_mng->broadcast(tag_info.view(), m_master_io_rank);
1573 m_mesh_info->entities_nodes_list.add(MshEntitiesNodes(tag_info[0], tag_info[1]));
1574 if (!m_is_binary)
1575 _goToNextLine();
1576 }
1577
1578 // Lecture des entités de dimensions 1, 2 et 3.
1579 for (Int32 i_dim = 1; i_dim <= 3; ++i_dim)
1580 for (Int32 i = 0; i < nb_dim_item[i_dim]; ++i)
1581 _readOneEntity(i_dim, i);
1582
1583 // En binaire, il faut aller au début de la ligne suivante.
1584 if (m_is_binary)
1585 _goToNextLine();
1586 _readAndCheck("$EndEntities");
1587}
1588
1589/*---------------------------------------------------------------------------*/
1590/*---------------------------------------------------------------------------*/
1591
1592void MshParallelMeshReader::
1593_readOneEntity(Int32 entity_dim, Int32 entity_index_in_dim)
1594{
1595 IosFile* ios_file = m_ios_file.get();
1596 const bool is_print_level1 = m_verbosity_level > 0;
1597 const bool is_print_level2 = m_verbosity_level > 1;
1598
1599 // Infos pour les tags
1600 // [0] entity_dim
1601 // [1] tag
1602 // [2] nb_physical_tag
1603 // [2+1] physical_tag1
1604 // [2+N] physical_tagN
1605 // ...
1606 // [3+nb_physical_tag] nb_boundary
1607 // [3+nb_physical_tag+1] boundary_tag1
1608 // [3+nb_physical_tag+n] boundary_tagN
1609 // ...
1610 if (is_print_level1)
1611 info() << "[Entities] Reading entity dim=" << entity_dim << " index_in_dim=" << entity_index_in_dim;
1612 SmallArray<Int64, 128> dim_and_tag_info;
1613 dim_and_tag_info.add(entity_dim);
1614 if (ios_file) {
1615 Int32 tag = _getInt32();
1616 dim_and_tag_info.add(tag);
1617 Real3 min_pos = _getReal3();
1618 Real3 max_pos = _getReal3();
1619 Int64 nb_physical_tag = _getInt64();
1620 dim_and_tag_info.add(nb_physical_tag);
1621 for (Int32 z = 0; z < nb_physical_tag; ++z) {
1622 Int32 physical_tag = _getInt32();
1623 dim_and_tag_info.add(physical_tag);
1624 if (is_print_level2)
1625 info(4) << "[Entities] z=" << z << " physical_tag=" << physical_tag;
1626 }
1627 // TODO: Lire les informations numBounding...
1628 Int64 nb_bounding_group = _getInt64();
1629 dim_and_tag_info.add(nb_bounding_group);
1630 for (Int64 z = 0; z < nb_bounding_group; ++z) {
1631 Int32 boundary_tag = _getInt32();
1632 if (is_print_level2)
1633 info(4) << "[Entities] z=" << z << " boundary_tag=" << boundary_tag;
1634 }
1635 if (is_print_level2)
1636 info(4) << "[Entities] dim=" << entity_dim << " tag=" << tag
1637 << " min_pos=" << min_pos << " max_pos=" << max_pos
1638 << " nb_phys_tag=" << nb_physical_tag
1639 << " nb_bounding=" << nb_bounding_group;
1640 }
1641 Int32 info_size = dim_and_tag_info.size();
1642 m_parallel_mng->broadcast(ArrayView<Int32>(1, &info_size), m_master_io_rank);
1643 dim_and_tag_info.resize(info_size);
1644 m_parallel_mng->broadcast(dim_and_tag_info.view(), m_master_io_rank);
1645
1646 {
1647 Int32 dim = CheckedConvert::toInt32(dim_and_tag_info[0]);
1648 Int64 tag = dim_and_tag_info[1];
1649 Int64 nb_physical_tag = dim_and_tag_info[2];
1650 for (Int32 z = 0; z < nb_physical_tag; ++z) {
1651 Int64 physical_tag = dim_and_tag_info[3 + z];
1652 if (is_print_level2)
1653 info(4) << "[Entities] adding info dim=" << entity_dim << " tag=" << tag
1654 << " physical_tag=" << physical_tag;
1655 m_mesh_info->entities_with_nodes_list[dim - 1].add(MshEntitiesWithNodes(dim, tag, physical_tag));
1656 }
1657 }
1658
1659 if (!m_is_binary)
1660 _goToNextLine();
1661}
1662
1663/*---------------------------------------------------------------------------*/
1664/*---------------------------------------------------------------------------*/
1684{
1685 Int64 nb_link = _getInt64AndBroadcast();
1686 info() << "[Periodic] nb_link=" << nb_link;
1687 const bool is_print_level1 = m_verbosity_level > 0;
1688 const bool is_print_level2 = m_verbosity_level > 1;
1689 // TODO: pour l'instant, tous les rangs conservent les
1690 // données car on suppose qu'il n'y en a pas beaucoup.
1691 // A terme, il faudra aussi distribuer ces informations.
1692 MshPeriodicInfo& periodic_info = m_mesh_info->m_periodic_info;
1693 periodic_info.m_periodic_list.resize(nb_link);
1694 for (Int64 ilink = 0; ilink < nb_link; ++ilink) {
1695 MshPeriodicOneInfo& one_info = periodic_info.m_periodic_list[ilink];
1696 FixedArray<Int32, 3> entity_info;
1697 _getInt32ArrayAndBroadcast(entity_info.view());
1698
1699 if (is_print_level1)
1700 info() << "[Periodic] link_index=" << ilink << " dim=" << entity_info[0] << " entity_tag=" << entity_info[1]
1701 << " entity_tag_master=" << entity_info[2];
1702 one_info.m_entity_dim = entity_info[0];
1703 one_info.m_entity_tag = entity_info[1];
1704 one_info.m_entity_tag_master = entity_info[2];
1705
1706 Int64 num_affine = _getInt64AndBroadcast();
1707 if (is_print_level2)
1708 info() << "[Periodic] num_affine=" << num_affine;
1709 one_info.m_affine_values.resize(num_affine);
1710 _getDoubleArrayAndBroadcast(one_info.m_affine_values);
1711 one_info.m_nb_corresponding_node = CheckedConvert::toInt32(_getInt64AndBroadcast());
1712 if (is_print_level1)
1713 info() << "[Periodic] nb_corresponding_node=" << one_info.m_nb_corresponding_node;
1714 one_info.m_corresponding_nodes.resize(one_info.m_nb_corresponding_node * 2);
1715 _getInt64ArrayAndBroadcast(one_info.m_corresponding_nodes);
1716 if (is_print_level2)
1717 info(4) << "[Periodic] corresponding_nodes=" << one_info.m_corresponding_nodes;
1718 }
1719
1720 _goToNextLine();
1721
1723 if (s != "$EndPeriodic")
1724 ARCANE_FATAL("found '{0}' and expected '$EndPeriodic'", s);
1725}
1726
1727/*---------------------------------------------------------------------------*/
1728/*---------------------------------------------------------------------------*/
1733_readAndCheck(const String& expected_value)
1734{
1735 String s;
1736 if (m_is_binary) {
1737 constexpr Int32 MAX_SIZE = 128;
1739 Span<const Byte> expected_bytes = expected_value.bytes();
1740 Int32 read_size = CheckedConvert::toInt32(expected_bytes.size());
1741 SmallSpan<Byte> bytes_to_read = buf_bytes.span().subSpan(0, read_size);
1742 if (read_size >= MAX_SIZE)
1743 ARCANE_FATAL("local buffer is too small (size={0} max={1})", read_size, MAX_SIZE);
1744 IosFile* f = m_ios_file.get();
1745 if (f) {
1746 f->binaryRead(bytes_to_read);
1747 s = String(bytes_to_read);
1748 info() << "S=" << s;
1749 if (m_is_parallel) {
1750 m_parallel_mng->broadcastString(s, m_master_io_rank);
1751 }
1752 }
1753 _goToNextLine();
1754 }
1755 else {
1757 }
1758 if (s != expected_value)
1759 ARCANE_FATAL("found '{0}' and expected '{1}'", s, expected_value);
1760}
1761
1762/*---------------------------------------------------------------------------*/
1763/*---------------------------------------------------------------------------*/
1766void MshParallelMeshReader::
1767_readMeshFromFile()
1768{
1769 IosFile* ios_file = m_ios_file.get();
1770 IMesh* mesh = m_mesh;
1771 info() << "Reading 'msh' file in parallel";
1772
1773 _initTypes();
1774
1775 const int MSH_BINARY_TYPE = 1;
1776
1777 if (ios_file) {
1778 Real version = ios_file->getReal();
1779 if (version != 4.1)
1780 ARCANE_THROW(IOException, "Wrong msh file version '{0}'. Only version '4.1' is supported in parallel", version);
1781 Integer file_type = ios_file->getInteger(); // is an integer equal to 0 in the ASCII file format, equal to 1 for the binary format
1782 if (file_type == MSH_BINARY_TYPE)
1783 m_is_binary = true;
1784 info() << "IsBinary?=" << m_is_binary;
1785 Int32 data_size = ios_file->getInteger(); // is an integer equal to the size of the floating point numbers used in the file
1786 ARCANE_UNUSED(data_size);
1787 if (data_size != 8)
1788 ARCANE_FATAL("Only 'size_t' of size '8' is allowed (current size is '{0}')", data_size);
1789 // En binaire, il a un entier à lire qui vaut 1 et qui permet de savoir si on n'est en big/little endian.
1790 if (m_is_binary) {
1791 // Il faut lire jusqu'à la fin de la ligne pour le binaire.
1792 _goToNextLine();
1793 Int32 int_value_one = 0;
1794 ios_file->binaryRead(SmallSpan<Int32>(&int_value_one, 1));
1795 if (int_value_one != 1)
1796 ARCANE_FATAL("Bad endianess for file. Read int as value '{0}' (expected=1)", int_value_one);
1797 }
1798
1799 _goToNextLine();
1800
1801 // $EndMeshFormat
1802 if (!ios_file->lookForString("$EndMeshFormat"))
1803 ARCANE_THROW(IOException, "$EndMeshFormat not found");
1804 }
1805
1806 // TODO: Les différentes sections ($Nodes, $Entitites, ...) peuvent
1807 // être dans n'importe quel ordre (à part $Nodes qui doit être avant $Elements)
1808 // Faire un méthode qui gère cela.
1809
1810 String next_line = _getNextLineAndBroadcast();
1811 // Noms des groupes
1812 if (next_line == "$PhysicalNames") {
1813 _readPhysicalNames();
1814 next_line = _getNextLineAndBroadcast();
1815 }
1816
1817 // Après le format, on peut avoir les entités mais cela est optionnel
1818 // Si elles sont présentes, on lit le fichier jusqu'à la fin de cette section.
1819 if (next_line == "$Entities") {
1820 _readEntities();
1821 next_line = _getNextLineAndBroadcast();
1822 }
1823 // $Nodes
1824 if (next_line != "$Nodes")
1825 ARCANE_THROW(IOException, "Unexpected string '{0}'. Valid values are '$Nodes'", next_line);
1826
1827 // Fetch nodes number and the coordinates
1829
1830 // $EndNodes
1831 if (ios_file && !ios_file->lookForString("$EndNodes"))
1832 ARCANE_THROW(IOException, "$EndNodes not found");
1833
1834 // $Elements
1835 if (ios_file && !ios_file->lookForString("$Elements"))
1836 ARCANE_THROW(IOException, "$Elements not found");
1837
1838 Int32 mesh_dimension = _readElementsFromFile();
1839
1840 // $EndElements
1841 if (ios_file && !ios_file->lookForString("$EndElements"))
1842 ARCANE_THROW(IOException, "$EndElements not found");
1843
1844 info() << "Computed mesh dimension = " << mesh_dimension;
1845
1846 IPrimaryMesh* pmesh = mesh->toPrimaryMesh();
1847 pmesh->setDimension(mesh_dimension);
1848
1849 info() << "NextLine=" << next_line;
1850
1851 bool is_end = _getIsEndOfFileAndBroadcast();
1852 if (!is_end) {
1853 next_line = _getNextLineAndBroadcast();
1854 // $Periodic
1855 if (next_line == "$Periodic") {
1856 _readPeriodic();
1857 }
1858 }
1859
1860 _allocateCells();
1862 _allocateGroups();
1863}
1864
1865/*---------------------------------------------------------------------------*/
1866/*---------------------------------------------------------------------------*/
1867
1868void MshParallelMeshReader::
1869_initTypes()
1870{
1871 // Initialise les types.
1872 // Il faut le faire au début de la lecture et ne plus en ajouter après.
1873 // La connectivité dans GMSH est décrite ici:
1874 // https://gmsh.info/doc/texinfo/gmsh.html#Node-ordering
1875 _addMshTypeInfo(MSH_PNT, ITI_Vertex);
1876 _addMshTypeInfo(MSH_LIN_2, ITI_Line2);
1877 _addMshTypeInfo(MSH_LIN_3, ITI_Line3);
1878 _addMshTypeInfo(MSH_TRI_3, ITI_Triangle3);
1879 _addMshTypeInfo(MSH_QUA_4, ITI_Quad4);
1880 _addMshTypeInfo(MSH_QUA_8, ITI_Quad8);
1881 _addMshTypeInfo(MSH_QUA_9, ITI_Quad9);
1882 _addMshTypeInfo(MSH_TET_4, ITI_Tetraedron4);
1883 _addMshTypeInfo(MSH_HEX_8, ITI_Hexaedron8);
1884 _addMshTypeInfo(MSH_PRI_6, ITI_Pentaedron6);
1885 _addMshTypeInfo(MSH_PRI_15, ITI_Pentaedron15);
1886 _addMshTypeInfo(MSH_PYR_5, ITI_Pyramid5);
1887 _addMshTypeInfo(MSH_PYR_13, ITI_Pyramid13);
1888 _addMshTypeInfo(MSH_TRI_6, ITI_Triangle6);
1889 _addMshTypeInfo(MSH_TRI_10, ITI_Triangle10);
1890 {
1891 FixedArray<Int16, 10> x({ 0, 1, 2, 3, 4, 5, 6, 7, 9, 8 });
1892 _addMshTypeInfo(MSH_TET_10, ITI_Tetraedron10, x.view());
1893 }
1894 {
1895 FixedArray<Int16, 20> x({ 0, 1, 2, 3, 4, 5, 6, 7,
1896 8, 11, 13, 9, 16, 18, 19, 17, 10, 12, 14, 15 });
1897 _addMshTypeInfo(MSH_HEX_20, ITI_Hexaedron20, x.view());
1898 }
1899 {
1900 FixedArray<Int16, 27> x({ 0, 1, 2, 3, 4, 5, 6, 7,
1901 8, 11, 13, 9, 16, 18, 19, 17, 10, 12, 14, 15,
1902 22, 23, 21, 24, 20, 25, 26 });
1903 _addMshTypeInfo(MSH_HEX_27, ITI_Hexaedron27, x.view());
1904 }
1905}
1906
1907/*---------------------------------------------------------------------------*/
1908/*---------------------------------------------------------------------------*/
1909
1910void MshParallelMeshReader::
1911_addMshTypeInfo(Int32 msh_type, ItemTypeId arcane_type, ConstArrayView<Int16> reorder_infos)
1912{
1913 //info() << "ADD_TYPE msh_type=" << msh_type << " Arcane=" << arcane_type;
1914 if (msh_type < 0)
1915 ARCANE_FATAL("Bad MSH type {0}", msh_type);
1916 if (m_msh_to_arcane_type_infos.size() <= msh_type)
1917 m_msh_to_arcane_type_infos.resize(msh_type + 1);
1918 ItemTypeMng* item_type_mng = m_mesh->itemTypeMng();
1919 ItemTypeInfo* iti = item_type_mng->typeFromId(arcane_type);
1920 m_msh_to_arcane_type_infos[msh_type] = MshToArcaneTypeInfo(msh_type, iti, reorder_infos);
1921}
1922
1923/*---------------------------------------------------------------------------*/
1924/*---------------------------------------------------------------------------*/
1925
1926const MshParallelMeshReader::MshToArcaneTypeInfo& MshParallelMeshReader::
1927mshToArcaneTypeInfo(Int32 msh_type) const
1928{
1929 if (msh_type < m_msh_to_arcane_type_infos.size()) {
1930 const MshToArcaneTypeInfo& tx = m_msh_to_arcane_type_infos[msh_type];
1931 if (tx.m_arcane_type_info)
1932 return tx;
1933 }
1934 ARCANE_THROW(NotSupportedException, "MSH type '{0}' is not supported in Arcane", msh_type);
1935}
1936
1937/*---------------------------------------------------------------------------*/
1938/*---------------------------------------------------------------------------*/
1943readMeshFromMshFile(IMesh* mesh, const String& filename, bool use_internal_partition)
1944{
1945 m_mesh_info = impl::MshMeshGenerationInfo::getReference(mesh, true);
1946 info() << "Trying to read in parallel 'msh' file '" << filename << "'"
1947 << " use_internal_partition=" << use_internal_partition;
1948 m_mesh = mesh;
1949 IParallelMng* pm = mesh->parallelMng();
1950 // Lit en séquentiel si les fichiers sont déjà découpés
1951 if (!use_internal_partition)
1952 pm = pm->sequentialParallelMng();
1953 m_parallel_mng = pm;
1954 const Int32 nb_rank = pm->commSize();
1955
1956 // Détermine les rangs qui vont conserver les données.
1957 // Il n'est pas obligatoire que tous les rangs participent
1958 // à la conservation des données. L'idéal avec un
1959 // grand nombre de rangs serait qu'un rang sur 2 ou 4 participent.
1960 // Cependant, cela génère alors des partitions vides (pour
1961 // les rangs qui ne participent pas) et cela peut
1962 // faire planter certains partitionneurs (comme ParMetis)
1963 // lorsqu'il y a des partitions vides. Il faudrait d'abord
1964 // corriger ce problème.
1965 m_nb_part = nb_rank;
1966 m_parts_rank.resize(m_nb_part);
1967 for (Int32 i = 0; i < m_nb_part; ++i) {
1968 m_parts_rank[i] = i % nb_rank;
1969 }
1970
1971 bool is_master_io = pm->isMasterIO();
1972 Int32 master_io_rank = pm->masterIORank();
1973 m_is_parallel = pm->isParallel();
1974 m_master_io_rank = master_io_rank;
1975 FixedArray<Int32, 1> file_readable;
1976 // Seul le rang maître va lire le fichier.
1977 // On vérifie d'abord qu'il est lisible
1978 if (is_master_io) {
1979 bool is_readable = platform::isFileReadable(filename);
1980 info() << "Is file readable ?=" << is_readable;
1981 file_readable[0] = is_readable ? 1 : 0;
1982 if (!is_readable)
1983 error() << "Unable to read file '" << filename << "'";
1984 }
1985 pm->broadcast(file_readable.view(), master_io_rank);
1986 if (file_readable[0] == 0) {
1987 return IMeshReader::RTError;
1988 }
1989
1990 std::ifstream ifile;
1991 Ref<IosFile> ios_file;
1992 if (is_master_io) {
1993 // Ouvre toujours le fichier en binaire car on
1994 // ne sait pas à l'avance s'il est en mode texte ou binaire.
1995 ifile.open(filename.localstr(), ios::binary);
1996 ios_file = makeRef<IosFile>(new IosFile(&ifile));
1997 }
1998 m_ios_file = ios_file;
1999 String mesh_format_str = _getNextLineAndBroadcast();
2000 if (IosFile::isEqualString(mesh_format_str, "$MeshFormat")) {
2001 _readMeshFromFile();
2002 if (!use_internal_partition) {
2003 info() << "Synchronize groups and variables";
2004 mesh->synchronizeGroupsAndVariables();
2005 }
2006 return IMeshReader::RTOk;
2007 }
2008
2009 info() << "The file does not begin with '$MeshFormat' returning RTError";
2010 return IMeshReader::RTError;
2011}
2012
2013/*---------------------------------------------------------------------------*/
2014/*---------------------------------------------------------------------------*/
2015
2016extern "C++" Ref<IMshMeshReader>
2017createMshParallelMeshReader(ITraceMng* tm)
2018{
2020}
2021
2022/*---------------------------------------------------------------------------*/
2023/*---------------------------------------------------------------------------*/
2024
2025} // namespace Arcane
2026
2027/*---------------------------------------------------------------------------*/
2028/*---------------------------------------------------------------------------*/
#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 ARCCORE_BASE_EXPORT std::optional< Int32 > tryParseFromEnvironment(StringView s, bool throw_if_invalid)
Classe template pour convertir un type.
constexpr __host__ __device__ ArrayView< T > view()
Vue modifiable sur le tableau.
constexpr __host__ __device__ SmallSpan< T, NbElement > span()
Vue modifiable sur le tableau.
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.
bool isNonManifold() const
Vrai si la structure du maillage est eMeshCellDimensionKind::NonManifold.
Definition MeshKind.h:118
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.
Vue d'un tableau d'éléments de type T.
Definition Span.h:801
constexpr __host__ __device__ SizeType size() const noexcept
Retourne la taille du tableau.
Definition Span.h:325
Vue d'un tableau d'éléments de type T.
Definition Span.h:633
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.
@ 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:496
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