Arcane  v4.1.0.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
MshParallelMeshReader.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-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
1015 ARCANE_FATAL("Not supported sub dimension cell type={0} for 2D mesh", item_type_name);
1016 }
1017 block.is_built_as_cells = true;
1018 _computeOwnItems(block, m_mesh_allocate_info.cells_infos, false);
1019 }
1020 }
1021 }
1022
1023 return mesh_dimension;
1024}
1025
1026/*---------------------------------------------------------------------------*/
1027/*---------------------------------------------------------------------------*/
1028
1029namespace
1030{
1031 template <typename DataType> inline ArrayView<DataType>
1032 _broadcastArrayWithSize(IParallelMng* pm, ArrayView<DataType> values,
1033 UniqueArray<DataType>& work_values, Int32 dest_rank, Int64 size)
1034 {
1035 const Int32 my_rank = pm->commRank();
1036 ArrayView<DataType> view = values;
1037 if (my_rank != dest_rank) {
1038 work_values.resize(size);
1039 view = work_values.view();
1040 }
1041 pm->broadcast(view, dest_rank);
1042 return view;
1043 }
1051 template <typename DataType> inline ArrayView<DataType>
1052 _broadcastArray(IParallelMng* pm, ArrayView<DataType> values,
1053 UniqueArray<DataType>& work_values, Int32 dest_rank)
1054 {
1055 const Int32 my_rank = pm->commRank();
1056 Int64 size = 0;
1057 // Envoie la taille
1058 if (dest_rank == my_rank)
1059 size = values.size();
1060 pm->broadcast(ArrayView<Int64>(1, &size), dest_rank);
1061 return _broadcastArrayWithSize(pm, values, work_values, dest_rank, size);
1062 }
1063
1064} // namespace
1065
1066/*---------------------------------------------------------------------------*/
1067/*---------------------------------------------------------------------------*/
1068
1069void MshParallelMeshReader::
1070_computeOwnItems(MshElementBlock& block, MshItemKindInfo& item_kind_info, bool is_generate_uid)
1071{
1072 // On ne conserve que les entités dont le premier noeud appartient à notre rang.
1073
1074 IParallelMng* pm = m_parallel_mng;
1075 const Int32 my_rank = pm->commRank();
1076 const bool is_print_level1 = m_verbosity_level > 0;
1077
1078 const ItemTypeId item_type = block.item_type;
1079 const Int32 item_nb_node = block.item_nb_node;
1080
1081 UniqueArray<Int64> connectivities;
1082 UniqueArray<Int64> uids;
1083 UniqueArray<Int32> nodes_rank;
1084
1085 SmallSpan<const Int16> reorder_infos = block.reorder_infos;
1086 bool has_reorder_info = !reorder_infos.empty();
1087 const Int32 nb_part = m_parts_rank.size();
1088 if (is_print_level1)
1089 info() << "Compute own items block_index=" << block.index << " nb_part=" << nb_part
1090 << " has_reorder?=" << has_reorder_info;
1091 // Liste des noeuds de l'élément avec la connectivité Arcane.
1092 SmallArray<Int64> arcane_reordered_uids;
1093 if (has_reorder_info)
1094 arcane_reordered_uids.resize(item_nb_node);
1095 for (Int32 i_part = 0; i_part < nb_part; ++i_part) {
1096 const Int32 dest_rank = m_parts_rank[i_part];
1097 // Broadcast la i_part-ème partie des uids et connectivités des mailles
1098 ArrayView<Int64> connectivities_view = _broadcastArray(pm, block.connectivities.view(), connectivities, dest_rank);
1099 ArrayView<Int64> uids_view = _broadcastArray(pm, block.uids.view(), uids, dest_rank);
1100
1101 Int32 nb_item = uids_view.size();
1102 nodes_rank.resize(nb_item);
1103 nodes_rank.fill(-1);
1104
1105 // Parcours les entités. Chaque entité appartiendra au rang
1106 // de son premier noeud. Si cette partie correspond à mon rang, alors
1107 // on conserve la maille.
1108 for (Int32 i = 0; i < nb_item; ++i) {
1109 Int64 first_node_uid = connectivities_view[i * item_nb_node];
1110 auto x = m_mesh_allocate_info.nodes_rank_map.find(first_node_uid);
1111 if (x == m_mesh_allocate_info.nodes_rank_map.end())
1112 // Le noeud n'est pas dans ma liste
1113 continue;
1114 Int32 rank = x->second;
1115 nodes_rank[i] = rank;
1116 }
1117 pm->reduce(Parallel::ReduceMax, nodes_rank);
1118 for (Int32 i = 0; i < nb_item; ++i) {
1119 const Int32 rank = nodes_rank[i];
1120 if (rank != my_rank)
1121 // Le noeud n'est pas dans ma partie
1122 continue;
1123 // Le noeud est chez moi, j'ajoute l'entité à la liste des
1124 // entités que je vais créer.
1125 ConstArrayView<Int64> v = connectivities_view.subView(i * item_nb_node, item_nb_node);
1126 Int64 uid = uids_view[i];
1127 if (is_generate_uid)
1128 // Le uniqueId() sera généré automatiquement
1129 uid = NULL_ITEM_UNIQUE_ID;
1130 if (has_reorder_info) {
1131 // Réordonne les noeuds si le type Arcane n'a pas la même numérotation
1132 // que le type MSH.
1133 for (Int32 zz = 0; zz < item_nb_node; ++zz)
1134 arcane_reordered_uids[zz] = v[reorder_infos[zz]];
1135 v = arcane_reordered_uids.view();
1136 }
1137 item_kind_info.addItem(item_type, uid, v);
1138 }
1139 }
1140}
1141
1142/*---------------------------------------------------------------------------*/
1143/*---------------------------------------------------------------------------*/
1160{
1161 UniqueArray<Int64> uids_storage;
1162 UniqueArray<Real3> coords_storage;
1163 UniqueArray<Int32> local_ids;
1164
1165 IParallelMng* pm = m_parallel_mng;
1166
1167 const IItemFamily* node_family = m_mesh->nodeFamily();
1168 VariableNodeReal3& nodes_coord_var(m_mesh->nodesCoordinates());
1169
1170 for (Int32 dest_rank : m_parts_rank) {
1171 ConstArrayView<Int64> uids = _broadcastArray(pm, m_mesh_allocate_info.nodes_unique_id.view(), uids_storage, dest_rank);
1172 ConstArrayView<Real3> coords = _broadcastArray(pm, m_mesh_allocate_info.nodes_coordinates.view(), coords_storage, dest_rank);
1173
1174 Int32 nb_item = uids.size();
1175 local_ids.resize(nb_item);
1176
1177 // Converti les uniqueId() en localId(). S'ils sont non nuls
1178 // c'est que l'entité est dans mon sous-domaine et donc on peut
1179 // positionner sa coordonnée
1180 node_family->itemsUniqueIdToLocalId(local_ids, uids, false);
1181 for (Int32 i = 0; i < nb_item; ++i) {
1182 NodeLocalId nid(local_ids[i]);
1183 if (!nid.isNull())
1184 nodes_coord_var[nid] = coords[i];
1185 }
1186 }
1187}
1188
1189/*---------------------------------------------------------------------------*/
1190/*---------------------------------------------------------------------------*/
1191
1192void MshParallelMeshReader::
1193_allocateCells()
1194{
1195 IMesh* mesh = m_mesh;
1196 Integer nb_elements = m_mesh_allocate_info.cells_infos.nb_item;
1197 info() << "nb_of_elements=cells_type.size()=" << nb_elements;
1198 Integer nb_cell_node = m_mesh_allocate_info.cells_infos.items_infos.size();
1199 info() << "nb_cell_node=cells_connectivity.size()=" << nb_cell_node;
1200
1201 // Création des mailles
1202 info() << "Building cells, nb_cell=" << nb_elements << " nb_cell_node=" << nb_cell_node;
1203 IPrimaryMesh* pmesh = mesh->toPrimaryMesh();
1204 info() << "## Allocating ##";
1205 pmesh->allocateCells(nb_elements, m_mesh_allocate_info.cells_infos.items_infos, false);
1206 info() << "## Ending ##";
1207 pmesh->endAllocate();
1208 info() << "## Done ##";
1209}
1210
1211/*---------------------------------------------------------------------------*/
1212/*---------------------------------------------------------------------------*/
1213
1214void MshParallelMeshReader::
1215_allocateGroups()
1216{
1217 IMesh* mesh = m_mesh;
1218 Int32 mesh_dim = mesh->dimension();
1219 Int32 face_dim = mesh_dim - 1;
1220 UniqueArray<MshEntitiesWithNodes> entity_list;
1221 UniqueArray<MshPhysicalName> physical_name_list;
1222 IItemFamily* node_family = mesh->nodeFamily();
1223
1224 for (MshElementBlock& block : m_mesh_allocate_info.element_blocks) {
1225 entity_list.clear();
1226 physical_name_list.clear();
1227 Int32 block_index = block.index;
1228 Int32 block_dim = block.dimension;
1229 // On alloue un groupe s'il a un nom physique associé.
1230 // Pour cela, il faut déjà qu'il soit associé à une entité.
1231 Int64 block_entity_tag = block.entity_tag;
1232 if (block_entity_tag < 0) {
1233 info(5) << "[Groups] Skipping block index=" << block_index << " because it has no entity";
1234 continue;
1235 }
1236 if (block_dim == 0) {
1237 const MshEntitiesNodes* entity = m_mesh_info->findNodeEntities(block_entity_tag);
1238 if (!entity) {
1239 info(5) << "[Groups] Skipping block index=" << block_index
1240 << " because entity tag is invalid";
1241 continue;
1242 }
1243 Int64 entity_physical_tag = entity->physicalTag();
1244 MshPhysicalName physical_name = m_mesh_info->findPhysicalName(block_dim, entity_physical_tag);
1245 physical_name_list.add(physical_name);
1246 }
1247 else {
1248 m_mesh_info->findEntities(block_dim, block_entity_tag, entity_list);
1249 for (const MshEntitiesWithNodes& x : entity_list) {
1250 Int64 entity_physical_tag = x.physicalTag();
1251 MshPhysicalName physical_name = m_mesh_info->findPhysicalName(block_dim, entity_physical_tag);
1252 physical_name_list.add(physical_name);
1253 }
1254 }
1255 for (const MshPhysicalName& physical_name : physical_name_list) {
1256 if (physical_name.isNull()) {
1257 info(5) << "[Groups] Skipping block index=" << block_index
1258 << " because entity physical tag is invalid";
1259 continue;
1260 }
1261 String group_name = physical_name.name();
1262 info(4) << "[Groups] Block index=" << block_index << " dim=" << block_dim
1263 << " name='" << group_name << "' built_as_cells=" << block.is_built_as_cells;
1264 if (block_dim == mesh_dim || block.is_built_as_cells) {
1265 _addCellOrNodeGroup(block.uids, block.index, group_name, mesh->cellFamily(), false);
1266 }
1267 else if (block_dim == face_dim) {
1268 _addFaceGroup(block, group_name);
1269 }
1270 else {
1271 // Il s'agit de noeuds
1272 _addCellOrNodeGroup(block.uids, block.index, group_name, node_family, false);
1273 }
1274 }
1275 }
1276
1277 // Crée les groupes de noeuds associés aux blocs de $Nodes
1278 {
1279 //bool has_periodic = m_mesh_info->m_periodic_info.hasValues();
1280 UniqueArray<Int64>& nodes_uids = m_mesh_allocate_info.nodes_unique_id;
1281 // Créé les groupes de noeuds issus des blocks dans $Nodes
1282 for (const MshNodeBlock& block : m_mesh_allocate_info.node_blocks) {
1283 ArrayView<Int64> block_uids = nodes_uids.subView(block.index_in_allocation_info, block.nb_node);
1284 MshPhysicalName physical_name = m_mesh_info->findPhysicalName(block.entity_dim, block.entity_tag);
1285 String group_name = physical_name.name();
1286 info(4) << "NodeBlock name=" << group_name << " index=" << block.index
1287 << " index_in_allocation=" << block.index_in_allocation_info
1288 << " nb_node=" << block.nb_node;
1289 // Si on a des infos de périodicité, on crée toujours les groupes de noeuds correspondants
1290 // aux blocs, car ils peuvent être référencés par les infos de périodicité.
1291 // Dans ce cas, on génère un nom de groupe.
1292 // NOTE: désactive cela car cela peut générer un très grand nombre de nombre de groupes
1293 // lorsqu'il y a beaucoup d'informations de périodicité et en plus on n'utilise pas encore
1294 // cela lors de l'écriture des informations périodiques.
1295 //if (physical_name.isNull() && has_periodic)
1296 //group_name = String::format("ArcaneMshInternalNodesDim{0}Entity{1}", block.entity_dim, block.entity_tag);
1297 if (!group_name.null())
1298 _addCellOrNodeGroup(block_uids, block.index, group_name, node_family, true);
1299 }
1300 }
1301}
1302
1303/*---------------------------------------------------------------------------*/
1304/*---------------------------------------------------------------------------*/
1309_addFaceGroup(const MshElementBlock& block, const String& group_name)
1310{
1311 IParallelMng* pm = m_parallel_mng;
1312 const Int32 item_nb_node = block.item_nb_node;
1313
1314 UniqueArray<Int64> connectivities;
1315 for (Int32 dest_rank : m_parts_rank) {
1316 ArrayView<Int64> connectivities_view = _broadcastArray(pm, block.connectivities.view(), connectivities, dest_rank);
1317 _addFaceGroupOnePart(block, connectivities_view, group_name);
1318 }
1319}
1320
1321/*---------------------------------------------------------------------------*/
1322/*---------------------------------------------------------------------------*/
1323
1324void MshParallelMeshReader::
1325_addFaceGroupOnePart(const MshElementBlock& block, ConstArrayView<Int64> connectivities,
1326 const String& group_name)
1327{
1328 IMesh* mesh = m_mesh;
1329 const Int32 item_nb_node = block.item_nb_node;
1330 const Int32 block_index = block.index;
1331 const ItemTypeId type_id = block.item_type;
1332 const Int32 nb_entity = connectivities.size() / item_nb_node;
1333
1334 // Il peut y avoir plusieurs blocs pour le même groupe.
1335 // On récupère le groupe s'il existe déjà.
1336 FaceGroup face_group = mesh->faceFamily()->findGroup(group_name, true);
1337
1338 UniqueArray<Int32> faces_id; // Numéro de la face dans le maillage \a mesh
1339 faces_id.reserve(nb_entity);
1340
1341 const Int32 face_nb_node = nb_entity * item_nb_node;
1342
1343 UniqueArray<Int64> faces_first_node_unique_id(nb_entity);
1344 UniqueArray<Int32> faces_first_node_local_id(nb_entity);
1345 UniqueArray<Int64> faces_nodes_unique_id(face_nb_node);
1346 Integer faces_nodes_unique_id_index = 0;
1347
1348 UniqueArray<Int64> orig_nodes_id(item_nb_node);
1349 //UniqueArray<Integer> face_nodes_index(item_nb_node);
1350
1351 IItemFamily* node_family = mesh->nodeFamily();
1352 NodeInfoListView mesh_nodes(node_family);
1353 NodesOfItemReorderer m_nodes_reorderer(mesh->itemTypeMng());
1354
1355 // Réordonne les identifiants des faces retrouver la face dans le maillage.
1356 // Pour cela, on récupère le premier noeud de la face et on regarde s'il
1357 // se trouve dans notre sous-domaine. Si oui, la face sera ajoutée à notre
1358 // partie du maillage
1359 for (Integer i_face = 0; i_face < nb_entity; ++i_face) {
1360 for (Integer z = 0; z < item_nb_node; ++z)
1361 orig_nodes_id[z] = connectivities[faces_nodes_unique_id_index + z];
1362 m_nodes_reorderer.reorder(type_id, orig_nodes_id);
1363 ConstArrayView<Int64> sorted_nodes(m_nodes_reorderer.sortedNodes());
1364 for (Integer z = 0; z < item_nb_node; ++z)
1365 faces_nodes_unique_id[faces_nodes_unique_id_index + z] = sorted_nodes[z];
1366 faces_first_node_unique_id[i_face] = sorted_nodes[0];
1367 faces_nodes_unique_id_index += item_nb_node;
1368 }
1369
1370 node_family->itemsUniqueIdToLocalId(faces_first_node_local_id, faces_first_node_unique_id, false);
1371
1372 const bool is_non_manifold = m_mesh->meshKind().isNonManifold();
1373 faces_nodes_unique_id_index = 0;
1374 for (Integer i_face = 0; i_face < nb_entity; ++i_face) {
1375 const Integer n = item_nb_node;
1376 Int32 face_first_node_lid = faces_first_node_local_id[i_face];
1377 if (face_first_node_lid != NULL_ITEM_LOCAL_ID) {
1378 Int64ConstArrayView face_nodes_id(item_nb_node, &faces_nodes_unique_id[faces_nodes_unique_id_index]);
1379 Node current_node(mesh_nodes[faces_first_node_local_id[i_face]]);
1380 Face face = MeshUtils::getFaceFromNodesUniqueId(current_node, face_nodes_id);
1381
1382 // En parallèle, il est possible que la face ne soit pas dans notre sous-domaine
1383 // même si un de ses noeuds l'est
1384 if (face.null()) {
1385 if (!m_is_parallel) {
1386 OStringStream ostr;
1387 ostr() << "(Nodes:";
1388 for (Integer z = 0; z < n; ++z)
1389 ostr() << ' ' << face_nodes_id[z];
1390 ostr() << " - node_lid=" << current_node.localId() << ")";
1391 String error_string = "INTERNAL: MshMeshReader face index={0} with nodes '{1}' is not in node/face connectivity.";
1392 if (!is_non_manifold)
1393 error_string = error_string + "\n This errors may occur if the mesh is non-manifold."
1394 "\n See Arcane documentation to specify the mesh is a non manifold one.\n";
1395 ARCANE_FATAL(error_string, i_face, ostr.str());
1396 }
1397 }
1398 else
1399 faces_id.add(face.localId());
1400 }
1401
1402 faces_nodes_unique_id_index += n;
1403 }
1404 info(4) << "Adding " << faces_id.size() << " faces from block index=" << block_index
1405 << " to group '" << face_group.name() << "'";
1406 face_group.addItems(faces_id);
1407}
1408
1409/*---------------------------------------------------------------------------*/
1410/*---------------------------------------------------------------------------*/
1415_addCellOrNodeGroup(ArrayView<Int64> block_uids, Int32 block_index,
1416 const String& group_name, IItemFamily* family, bool filter_invalid)
1417{
1418 IParallelMng* pm = m_parallel_mng;
1419
1420 UniqueArray<Int64> uids;
1421 for (Int32 dest_rank : m_parts_rank) {
1422 ArrayView<Int64> uids_view = _broadcastArray(pm, block_uids, uids, dest_rank);
1423 _addCellOrNodeGroupOnePart(uids_view, group_name, block_index, family, filter_invalid);
1424 }
1425}
1426
1427/*---------------------------------------------------------------------------*/
1428/*---------------------------------------------------------------------------*/
1429
1430void MshParallelMeshReader::
1431_addCellOrNodeGroupOnePart(ConstArrayView<Int64> uids, const String& group_name,
1432 Int32 block_index, IItemFamily* family, bool filter_invalid)
1433{
1434 const Int32 nb_entity = uids.size();
1435
1436 // Il peut y avoir plusieurs blocs pour le même groupe.
1437 // On récupère le groupe s'il existe déjà.
1438 ItemGroup group = family->findGroup(group_name, true);
1439
1440 UniqueArray<Int32> items_lid(nb_entity);
1441
1442 family->itemsUniqueIdToLocalId(items_lid, uids, false);
1443
1444 // En parallèle, il est possible que certaines entités du groupe ne soient
1445 // pas dans notre sous-domaine. Il faut les filtrer.
1446 // De même, s'il s'agit d'un groupe issu d'une $Entity node, il est possible
1447 // que le noeud n'existe pas s'il n'est pas attaché à une maille
1448 // (TODO: à vérifier avec sod3d-misc.msh)
1449 if (m_is_parallel || filter_invalid) {
1450 auto items_begin = items_lid.begin();
1451 Int64 new_size = std::remove(items_begin, items_lid.end(), NULL_ITEM_LOCAL_ID) - items_begin;
1452 items_lid.resize(new_size);
1453 }
1454
1455 info() << "Adding " << items_lid.size() << " items from block index=" << block_index
1456 << " to group '" << group_name << "' for family=" << family->name();
1457
1458 group.addItems(items_lid);
1459}
1460
1461/*---------------------------------------------------------------------------*/
1462/*---------------------------------------------------------------------------*/
1463/*
1464 * $PhysicalNames // same as MSH version 2
1465 * numPhysicalNames(ASCII int)
1466 * dimension(ASCII int) physicalTag(ASCII int) "name"(127 characters max)
1467 * ...
1468 * $EndPhysicalNames
1469 */
1470void MshParallelMeshReader::
1471_readPhysicalNames()
1472{
1473 // NOTE: même en binaire, la partie $PhysicalNames est écrite en ASCII.
1474 String quote_mark = "\"";
1475 Int32 nb_name = _getIntegerAndBroadcast();
1476 info() << "nb_physical_name=" << nb_name;
1477
1478 _goToNextLine();
1479
1480 for (Int32 i = 0; i < nb_name; ++i) {
1481 Int32 dim = _getIntegerAndBroadcast();
1482 Int32 tag = _getIntegerAndBroadcast();
1483 String s = _getNextLineAndBroadcast();
1484 if (dim < 0 || dim > 3)
1485 ARCANE_FATAL("Invalid value for physical name dimension dim={0}", dim);
1486 // Les noms des groupes peuvent commencer par des espaces et contiennent
1487 // des guillemets qu'il faut supprimer.
1489 if (s.startsWith(quote_mark))
1490 s = s.substring(1);
1491 if (s.endsWith(quote_mark))
1492 s = s.substring(0, s.length() - 1);
1493 m_mesh_info->physical_name_list.add(dim, tag, s);
1494 info(4) << "[PhysicalName] index=" << i << " dim=" << dim << " tag=" << tag << " name='" << s << "'";
1495 }
1496
1497 String s = _getNextLineAndBroadcast();
1498 if (s != "$EndPhysicalNames")
1499 ARCANE_FATAL("found '{0}' and expected '$EndPhysicalNames'", s);
1500}
1501
1502/*---------------------------------------------------------------------------*/
1503/*---------------------------------------------------------------------------*/
1536{
1537 IosFile* ios_file = m_ios_file.get();
1538
1539 FixedArray<Int64, 4> nb_dim_item;
1540 _getInt64ArrayAndBroadcast(nb_dim_item.view());
1541
1542 const bool is_print_level1 = m_verbosity_level > 0;
1543
1544 info() << "[Entities] nb_0d=" << nb_dim_item[0] << " nb_1d=" << nb_dim_item[1]
1545 << " nb_2d=" << nb_dim_item[2] << " nb_3d=" << nb_dim_item[3];
1546 // Après le format, on peut avoir les entités mais cela est optionnel
1547 // Si elles sont présentes, on lit le fichier jusqu'à la fin de cette section.
1548 if (!m_is_binary)
1549 _goToNextLine();
1550
1551 // Lecture des entités associées à des points
1552 for (Int64 i = 0; i < nb_dim_item[0]; ++i) {
1553 FixedArray<Int64, 2> tag_info;
1554 if (ios_file) {
1555 Int32 tag = _getInt32();
1556 Real3 xyz = _getReal3();
1557 Int64 num_physical_tag = _getInt64();
1558 if (num_physical_tag > 1)
1559 ARCANE_FATAL("NotImplemented numPhysicalTag>1 (n={0}, index={1} xyz={2})",
1560 num_physical_tag, i, xyz);
1561
1562 Int32 physical_tag = -1;
1563 if (num_physical_tag == 1)
1564 physical_tag = _getInt32();
1565 if (is_print_level1)
1566 info() << "[Entities] point tag=" << tag << " pos=" << xyz << " phys_tag=" << physical_tag;
1567
1568 tag_info[0] = tag;
1569 tag_info[1] = physical_tag;
1570 }
1571 m_parallel_mng->broadcast(tag_info.view(), m_master_io_rank);
1572 m_mesh_info->entities_nodes_list.add(MshEntitiesNodes(tag_info[0], tag_info[1]));
1573 if (!m_is_binary)
1574 _goToNextLine();
1575 }
1576
1577 // Lecture des entités de dimensions 1, 2 et 3.
1578 for (Int32 i_dim = 1; i_dim <= 3; ++i_dim)
1579 for (Int32 i = 0; i < nb_dim_item[i_dim]; ++i)
1580 _readOneEntity(i_dim, i);
1581
1582 // En binaire, il faut aller au début de la ligne suivante.
1583 if (m_is_binary)
1584 _goToNextLine();
1585 _readAndCheck("$EndEntities");
1586}
1587
1588/*---------------------------------------------------------------------------*/
1589/*---------------------------------------------------------------------------*/
1590
1591void MshParallelMeshReader::
1592_readOneEntity(Int32 entity_dim, Int32 entity_index_in_dim)
1593{
1594 IosFile* ios_file = m_ios_file.get();
1595 const bool is_print_level1 = m_verbosity_level > 0;
1596 const bool is_print_level2 = m_verbosity_level > 1;
1597
1598 // Infos pour les tags
1599 // [0] entity_dim
1600 // [1] tag
1601 // [2] nb_physical_tag
1602 // [2+1] physical_tag1
1603 // [2+N] physical_tagN
1604 // ...
1605 // [3+nb_physical_tag] nb_boundary
1606 // [3+nb_physical_tag+1] boundary_tag1
1607 // [3+nb_physical_tag+n] boundary_tagN
1608 // ...
1609 if (is_print_level1)
1610 info() << "[Entities] Reading entity dim=" << entity_dim << " index_in_dim=" << entity_index_in_dim;
1611 SmallArray<Int64, 128> dim_and_tag_info;
1612 dim_and_tag_info.add(entity_dim);
1613 if (ios_file) {
1614 Int32 tag = _getInt32();
1615 dim_and_tag_info.add(tag);
1616 Real3 min_pos = _getReal3();
1617 Real3 max_pos = _getReal3();
1618 Int64 nb_physical_tag = _getInt64();
1619 dim_and_tag_info.add(nb_physical_tag);
1620 for (Int32 z = 0; z < nb_physical_tag; ++z) {
1621 Int32 physical_tag = _getInt32();
1622 dim_and_tag_info.add(physical_tag);
1623 if (is_print_level2)
1624 info(4) << "[Entities] z=" << z << " physical_tag=" << physical_tag;
1625 }
1626 // TODO: Lire les informations numBounding...
1627 Int64 nb_bounding_group = _getInt64();
1628 dim_and_tag_info.add(nb_bounding_group);
1629 for (Int64 z = 0; z < nb_bounding_group; ++z) {
1630 Int32 boundary_tag = _getInt32();
1631 if (is_print_level2)
1632 info(4) << "[Entities] z=" << z << " boundary_tag=" << boundary_tag;
1633 }
1634 if (is_print_level2)
1635 info(4) << "[Entities] dim=" << entity_dim << " tag=" << tag
1636 << " min_pos=" << min_pos << " max_pos=" << max_pos
1637 << " nb_phys_tag=" << nb_physical_tag
1638 << " nb_bounding=" << nb_bounding_group;
1639 }
1640 Int32 info_size = dim_and_tag_info.size();
1641 m_parallel_mng->broadcast(ArrayView<Int32>(1, &info_size), m_master_io_rank);
1642 dim_and_tag_info.resize(info_size);
1643 m_parallel_mng->broadcast(dim_and_tag_info.view(), m_master_io_rank);
1644
1645 {
1646 Int32 dim = CheckedConvert::toInt32(dim_and_tag_info[0]);
1647 Int64 tag = dim_and_tag_info[1];
1648 Int64 nb_physical_tag = dim_and_tag_info[2];
1649 for (Int32 z = 0; z < nb_physical_tag; ++z) {
1650 Int64 physical_tag = dim_and_tag_info[3 + z];
1651 if (is_print_level2)
1652 info(4) << "[Entities] adding info dim=" << entity_dim << " tag=" << tag
1653 << " physical_tag=" << physical_tag;
1654 m_mesh_info->entities_with_nodes_list[dim - 1].add(MshEntitiesWithNodes(dim, tag, physical_tag));
1655 }
1656 }
1657
1658 if (!m_is_binary)
1659 _goToNextLine();
1660}
1661
1662/*---------------------------------------------------------------------------*/
1663/*---------------------------------------------------------------------------*/
1683{
1684 Int64 nb_link = _getInt64AndBroadcast();
1685 info() << "[Periodic] nb_link=" << nb_link;
1686 const bool is_print_level1 = m_verbosity_level > 0;
1687 const bool is_print_level2 = m_verbosity_level > 1;
1688 // TODO: pour l'instant, tous les rangs conservent les
1689 // données car on suppose qu'il n'y en a pas beaucoup.
1690 // A terme, il faudra aussi distribuer ces informations.
1691 MshPeriodicInfo& periodic_info = m_mesh_info->m_periodic_info;
1692 periodic_info.m_periodic_list.resize(nb_link);
1693 for (Int64 ilink = 0; ilink < nb_link; ++ilink) {
1694 MshPeriodicOneInfo& one_info = periodic_info.m_periodic_list[ilink];
1695 FixedArray<Int32, 3> entity_info;
1696 _getInt32ArrayAndBroadcast(entity_info.view());
1697
1698 if (is_print_level1)
1699 info() << "[Periodic] link_index=" << ilink << " dim=" << entity_info[0] << " entity_tag=" << entity_info[1]
1700 << " entity_tag_master=" << entity_info[2];
1701 one_info.m_entity_dim = entity_info[0];
1702 one_info.m_entity_tag = entity_info[1];
1703 one_info.m_entity_tag_master = entity_info[2];
1704
1705 Int64 num_affine = _getInt64AndBroadcast();
1706 if (is_print_level2)
1707 info() << "[Periodic] num_affine=" << num_affine;
1708 one_info.m_affine_values.resize(num_affine);
1709 _getDoubleArrayAndBroadcast(one_info.m_affine_values);
1710 one_info.m_nb_corresponding_node = CheckedConvert::toInt32(_getInt64AndBroadcast());
1711 if (is_print_level1)
1712 info() << "[Periodic] nb_corresponding_node=" << one_info.m_nb_corresponding_node;
1713 one_info.m_corresponding_nodes.resize(one_info.m_nb_corresponding_node * 2);
1714 _getInt64ArrayAndBroadcast(one_info.m_corresponding_nodes);
1715 if (is_print_level2)
1716 info(4) << "[Periodic] corresponding_nodes=" << one_info.m_corresponding_nodes;
1717 }
1718
1719 _goToNextLine();
1720
1722 if (s != "$EndPeriodic")
1723 ARCANE_FATAL("found '{0}' and expected '$EndPeriodic'", s);
1724}
1725
1726/*---------------------------------------------------------------------------*/
1727/*---------------------------------------------------------------------------*/
1732_readAndCheck(const String& expected_value)
1733{
1734 String s;
1735 if (m_is_binary) {
1736 constexpr Int32 MAX_SIZE = 128;
1738 Span<const Byte> expected_bytes = expected_value.bytes();
1739 Int32 read_size = CheckedConvert::toInt32(expected_bytes.size());
1740 SmallSpan<Byte> bytes_to_read = buf_bytes.span().subSpan(0, read_size);
1741 if (read_size >= MAX_SIZE)
1742 ARCANE_FATAL("local buffer is too small (size={0} max={1})", read_size, MAX_SIZE);
1743 IosFile* f = m_ios_file.get();
1744 if (f) {
1745 f->binaryRead(bytes_to_read);
1746 s = String(bytes_to_read);
1747 info() << "S=" << s;
1748 if (m_is_parallel) {
1749 m_parallel_mng->broadcastString(s, m_master_io_rank);
1750 }
1751 }
1752 _goToNextLine();
1753 }
1754 else {
1756 }
1757 if (s != expected_value)
1758 ARCANE_FATAL("found '{0}' and expected '{1}'", s, expected_value);
1759}
1760
1761/*---------------------------------------------------------------------------*/
1762/*---------------------------------------------------------------------------*/
1765void MshParallelMeshReader::
1766_readMeshFromFile()
1767{
1768 IosFile* ios_file = m_ios_file.get();
1769 IMesh* mesh = m_mesh;
1770 info() << "Reading 'msh' file in parallel";
1771
1772 _initTypes();
1773
1774 const int MSH_BINARY_TYPE = 1;
1775
1776 if (ios_file) {
1777 Real version = ios_file->getReal();
1778 if (version != 4.1)
1779 ARCANE_THROW(IOException, "Wrong msh file version '{0}'. Only version '4.1' is supported in parallel", version);
1780 Integer file_type = ios_file->getInteger(); // is an integer equal to 0 in the ASCII file format, equal to 1 for the binary format
1781 if (file_type == MSH_BINARY_TYPE)
1782 m_is_binary = true;
1783 info() << "IsBinary?=" << m_is_binary;
1784 Int32 data_size = ios_file->getInteger(); // is an integer equal to the size of the floating point numbers used in the file
1785 ARCANE_UNUSED(data_size);
1786 if (data_size != 8)
1787 ARCANE_FATAL("Only 'size_t' of size '8' is allowed (current size is '{0}')", data_size);
1788 // En binaire, il a un entier à lire qui vaut 1 et qui permet de savoir si on n'est en big/little endian.
1789 if (m_is_binary) {
1790 // Il faut lire jusqu'à la fin de la ligne pour le binaire.
1791 _goToNextLine();
1792 Int32 int_value_one = 0;
1793 ios_file->binaryRead(SmallSpan<Int32>(&int_value_one, 1));
1794 if (int_value_one != 1)
1795 ARCANE_FATAL("Bad endianess for file. Read int as value '{0}' (expected=1)", int_value_one);
1796 }
1797
1798 _goToNextLine();
1799
1800 // $EndMeshFormat
1801 if (!ios_file->lookForString("$EndMeshFormat"))
1802 ARCANE_THROW(IOException, "$EndMeshFormat not found");
1803 }
1804
1805 // TODO: Les différentes sections ($Nodes, $Entitites, ...) peuvent
1806 // être dans n'importe quel ordre (à part $Nodes qui doit être avant $Elements)
1807 // Faire un méthode qui gère cela.
1808
1809 String next_line = _getNextLineAndBroadcast();
1810 // Noms des groupes
1811 if (next_line == "$PhysicalNames") {
1812 _readPhysicalNames();
1813 next_line = _getNextLineAndBroadcast();
1814 }
1815
1816 // Après le format, on peut avoir les entités mais cela est optionnel
1817 // Si elles sont présentes, on lit le fichier jusqu'à la fin de cette section.
1818 if (next_line == "$Entities") {
1819 _readEntities();
1820 next_line = _getNextLineAndBroadcast();
1821 }
1822 // $Nodes
1823 if (next_line != "$Nodes")
1824 ARCANE_THROW(IOException, "Unexpected string '{0}'. Valid values are '$Nodes'", next_line);
1825
1826 // Fetch nodes number and the coordinates
1828
1829 // $EndNodes
1830 if (ios_file && !ios_file->lookForString("$EndNodes"))
1831 ARCANE_THROW(IOException, "$EndNodes not found");
1832
1833 // $Elements
1834 if (ios_file && !ios_file->lookForString("$Elements"))
1835 ARCANE_THROW(IOException, "$Elements not found");
1836
1837 Int32 mesh_dimension = _readElementsFromFile();
1838
1839 // $EndElements
1840 if (ios_file && !ios_file->lookForString("$EndElements"))
1841 ARCANE_THROW(IOException, "$EndElements not found");
1842
1843 info() << "Computed mesh dimension = " << mesh_dimension;
1844
1845 IPrimaryMesh* pmesh = mesh->toPrimaryMesh();
1846 pmesh->setDimension(mesh_dimension);
1847
1848 info() << "NextLine=" << next_line;
1849
1850 bool is_end = _getIsEndOfFileAndBroadcast();
1851 if (!is_end) {
1852 next_line = _getNextLineAndBroadcast();
1853 // $Periodic
1854 if (next_line == "$Periodic") {
1855 _readPeriodic();
1856 }
1857 }
1858
1859 _allocateCells();
1861 _allocateGroups();
1862}
1863
1864/*---------------------------------------------------------------------------*/
1865/*---------------------------------------------------------------------------*/
1866
1867void MshParallelMeshReader::
1868_initTypes()
1869{
1870 // Initialise les types.
1871 // Il faut le faire au début de la lecture et ne plus en ajouter après.
1872 // La connectivité dans GMSH est décrite ici:
1873 // https://gmsh.info/doc/texinfo/gmsh.html#Node-ordering
1874 _addMshTypeInfo(MSH_PNT, ITI_Vertex);
1875 _addMshTypeInfo(MSH_LIN_2, ITI_Line2);
1876 _addMshTypeInfo(MSH_LIN_3, ITI_Line3);
1877 _addMshTypeInfo(MSH_TRI_3, ITI_Triangle3);
1878 _addMshTypeInfo(MSH_QUA_4, ITI_Quad4);
1879 _addMshTypeInfo(MSH_QUA_8, ITI_Quad8);
1880 _addMshTypeInfo(MSH_QUA_9, ITI_Quad9);
1881 _addMshTypeInfo(MSH_TET_4, ITI_Tetraedron4);
1882 _addMshTypeInfo(MSH_HEX_8, ITI_Hexaedron8);
1883 _addMshTypeInfo(MSH_PRI_6, ITI_Pentaedron6);
1884 _addMshTypeInfo(MSH_PRI_15, ITI_Pentaedron15);
1885 _addMshTypeInfo(MSH_PYR_5, ITI_Pyramid5);
1886 _addMshTypeInfo(MSH_PYR_13, ITI_Pyramid13);
1887 _addMshTypeInfo(MSH_TRI_6, ITI_Triangle6);
1888 {
1889 FixedArray<Int16, 10> x({ 0, 1, 2, 3, 4, 5, 6, 7, 9, 8 });
1890 _addMshTypeInfo(MSH_TET_10, ITI_Tetraedron10, x.view());
1891 }
1892 {
1893 FixedArray<Int16, 20> x({ 0, 1, 2, 3, 4, 5, 6, 7,
1894 8, 11, 13, 9, 16, 18, 19, 17, 10, 12, 14, 15 });
1895 _addMshTypeInfo(MSH_HEX_20, ITI_Hexaedron20, x.view());
1896 }
1897 {
1898 FixedArray<Int16, 27> x({ 0, 1, 2, 3, 4, 5, 6, 7,
1899 8, 11, 13, 9, 16, 18, 19, 17, 10, 12, 14, 15,
1900 22, 23, 21, 24, 20, 25, 26 });
1901 _addMshTypeInfo(MSH_HEX_27, ITI_Hexaedron27, x.view());
1902 }
1903}
1904
1905/*---------------------------------------------------------------------------*/
1906/*---------------------------------------------------------------------------*/
1907
1908void MshParallelMeshReader::
1909_addMshTypeInfo(Int32 msh_type, ItemTypeId arcane_type, ConstArrayView<Int16> reorder_infos)
1910{
1911 //info() << "ADD_TYPE msh_type=" << msh_type << " Arcane=" << arcane_type;
1912 if (msh_type < 0)
1913 ARCANE_FATAL("Bad MSH type {0}", msh_type);
1914 if (m_msh_to_arcane_type_infos.size() <= msh_type)
1915 m_msh_to_arcane_type_infos.resize(msh_type + 1);
1916 ItemTypeMng* item_type_mng = m_mesh->itemTypeMng();
1917 ItemTypeInfo* iti = item_type_mng->typeFromId(arcane_type);
1918 m_msh_to_arcane_type_infos[msh_type] = MshToArcaneTypeInfo(msh_type, iti, reorder_infos);
1919}
1920
1921/*---------------------------------------------------------------------------*/
1922/*---------------------------------------------------------------------------*/
1923
1924const MshParallelMeshReader::MshToArcaneTypeInfo& MshParallelMeshReader::
1925mshToArcaneTypeInfo(Int32 msh_type) const
1926{
1927 if (msh_type < m_msh_to_arcane_type_infos.size()) {
1928 const MshToArcaneTypeInfo& tx = m_msh_to_arcane_type_infos[msh_type];
1929 if (tx.m_arcane_type_info)
1930 return tx;
1931 }
1932 ARCANE_THROW(NotSupportedException, "MSH type '{0}' is not supported in Arcane", msh_type);
1933}
1934
1935/*---------------------------------------------------------------------------*/
1936/*---------------------------------------------------------------------------*/
1941readMeshFromMshFile(IMesh* mesh, const String& filename, bool use_internal_partition)
1942{
1943 m_mesh_info = impl::MshMeshGenerationInfo::getReference(mesh, true);
1944 info() << "Trying to read in parallel 'msh' file '" << filename << "'"
1945 << " use_internal_partition=" << use_internal_partition;
1946 m_mesh = mesh;
1947 IParallelMng* pm = mesh->parallelMng();
1948 // Lit en séquentiel si les fichiers sont déjà découpés
1949 if (!use_internal_partition)
1950 pm = pm->sequentialParallelMng();
1951 m_parallel_mng = pm;
1952 const Int32 nb_rank = pm->commSize();
1953
1954 // Détermine les rangs qui vont conserver les données.
1955 // Il n'est pas obligatoire que tous les rangs participent
1956 // à la conservation des données. L'idéal avec un
1957 // grand nombre de rangs serait qu'un rang sur 2 ou 4 participent.
1958 // Cependant, cela génère alors des partitions vides (pour
1959 // les rangs qui ne participent pas) et cela peut
1960 // faire planter certains partitionneurs (comme ParMetis)
1961 // lorsqu'il y a des partitions vides. Il faudrait d'abord
1962 // corriger ce problème.
1963 m_nb_part = nb_rank;
1964 m_parts_rank.resize(m_nb_part);
1965 for (Int32 i = 0; i < m_nb_part; ++i) {
1966 m_parts_rank[i] = i % nb_rank;
1967 }
1968
1969 bool is_master_io = pm->isMasterIO();
1970 Int32 master_io_rank = pm->masterIORank();
1971 m_is_parallel = pm->isParallel();
1972 m_master_io_rank = master_io_rank;
1973 FixedArray<Int32, 1> file_readable;
1974 // Seul le rang maître va lire le fichier.
1975 // On vérifie d'abord qu'il est lisible
1976 if (is_master_io) {
1977 bool is_readable = platform::isFileReadable(filename);
1978 info() << "Is file readable ?=" << is_readable;
1979 file_readable[0] = is_readable ? 1 : 0;
1980 if (!is_readable)
1981 error() << "Unable to read file '" << filename << "'";
1982 }
1983 pm->broadcast(file_readable.view(), master_io_rank);
1984 if (file_readable[0] == 0) {
1985 return IMeshReader::RTError;
1986 }
1987
1988 std::ifstream ifile;
1989 Ref<IosFile> ios_file;
1990 if (is_master_io) {
1991 // Ouvre toujours le fichier en binaire car on
1992 // ne sait pas à l'avance s'il est en mode texte ou binaire.
1993 ifile.open(filename.localstr(), ios::binary);
1994 ios_file = makeRef<IosFile>(new IosFile(&ifile));
1995 }
1996 m_ios_file = ios_file;
1997 String mesh_format_str = _getNextLineAndBroadcast();
1998 if (IosFile::isEqualString(mesh_format_str, "$MeshFormat")) {
1999 _readMeshFromFile();
2000 if (!use_internal_partition) {
2001 info() << "Synchronize groups and variables";
2002 mesh->synchronizeGroupsAndVariables();
2003 }
2004 return IMeshReader::RTOk;
2005 }
2006
2007 info() << "The file does not begin with '$MeshFormat' returning RTError";
2008 return IMeshReader::RTError;
2009}
2010
2011/*---------------------------------------------------------------------------*/
2012/*---------------------------------------------------------------------------*/
2013
2014extern "C++" Ref<IMshMeshReader>
2015createMshParallelMeshReader(ITraceMng* tm)
2016{
2018}
2019
2020/*---------------------------------------------------------------------------*/
2021/*---------------------------------------------------------------------------*/
2022
2023} // namespace Arcane
2024
2025/*---------------------------------------------------------------------------*/
2026/*---------------------------------------------------------------------------*/
#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