Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
MshParallelMeshReader.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 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/* Parallel reading of an MSH file. */
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 * - The `gmsh` library provides an 'open.py' script in the 'demos/api' directory
49 * that allows generating a '.msh' file from a '.geo'.
50 * - It is also possible to use the 'gmsh' executable directly with
51 * the '-save-all' option to save a '.msh' file from a '.geo'
52 *
53 * TODO:
54 * - support partitions
55 * - be able to use the 'gmsh' library directly.
56 */
57
58/*---------------------------------------------------------------------------*/
59/*---------------------------------------------------------------------------*/
60
61namespace Arcane
62{
63
64/*---------------------------------------------------------------------------*/
65/*---------------------------------------------------------------------------*/
66
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: Allocate connectivity per block to avoid overly large 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 except for the master rank.
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 // For the last interval, take the remaining elements
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/*---------------------------------------------------------------------------*/
307
313{
314 IosFile* f = m_ios_file.get();
315 String s;
316 if (f) {
317 s = f->getNextLine();
318 }
319 if (m_is_parallel) {
320 if (f)
321 info(4) << "BroadcastNextLine: " << s;
322 m_parallel_mng->broadcastString(s, m_master_io_rank);
323 }
324 info(4) << "GetNextLine: " << s;
325 return s;
326}
327
328/*---------------------------------------------------------------------------*/
329/*---------------------------------------------------------------------------*/
330
336{
337 IosFile* f = m_ios_file.get();
338 Int32 is_end_int = 0;
339 if (f) {
340 is_end_int = f->isEnd() ? 1 : 0;
341 info(4) << "IsEndOfFile_Master: " << is_end_int;
342 }
343 if (m_is_parallel) {
344 if (f)
345 info(4) << "IsEndOfFile: " << is_end_int;
346 m_parallel_mng->broadcast(ArrayView<Int32>(1, &is_end_int), m_master_io_rank);
347 }
348 bool is_end = (is_end_int != 0);
349 info(4) << "IsEnd: " << is_end;
350 return is_end;
351}
352
353/*---------------------------------------------------------------------------*/
354/*---------------------------------------------------------------------------*/
355
357//_getASCIIIntegerAndBroadcast()
358_getIntegerAndBroadcast()
359{
360 IosFile* f = m_ios_file.get();
362 if (f)
363 v[0] = f->getInteger();
364 if (m_is_parallel) {
365 m_parallel_mng->broadcast(v.view(), m_master_io_rank);
366 }
367 return v[0];
368}
369
370/*---------------------------------------------------------------------------*/
371/*---------------------------------------------------------------------------*/
372
373Int64 MshParallelMeshReader::
374_getInt64AndBroadcast()
375{
376 IosFile* f = m_ios_file.get();
377 FixedArray<Int64, 1> v;
378 if (f)
379 v[0] = _getInt64();
380 if (m_is_parallel) {
381 m_parallel_mng->broadcast(v.view(), m_master_io_rank);
382 }
383 return v[0];
384}
385
386/*---------------------------------------------------------------------------*/
387/*---------------------------------------------------------------------------*/
388
389void MshParallelMeshReader::
390_getInt64ArrayAndBroadcast(ArrayView<Int64> values)
391{
392 IosFile* f = m_ios_file.get();
393 if (f) {
394 if (m_is_binary) {
395 f->binaryRead(values);
396 }
397 else {
398 for (Int64& v : values)
399 v = f->getInt64();
400 }
401 }
402 if (m_is_parallel)
403 m_parallel_mng->broadcast(values, m_master_io_rank);
404}
405
406/*---------------------------------------------------------------------------*/
407/*---------------------------------------------------------------------------*/
408
409void MshParallelMeshReader::
410_getInt32ArrayAndBroadcast(ArrayView<Int32> values)
411{
412 IosFile* f = m_ios_file.get();
413 if (f) {
414 if (m_is_binary) {
415 f->binaryRead(values);
416 }
417 else {
418 for (Int32& v : values)
419 v = f->getInteger();
420 }
421 }
422 if (m_is_parallel)
423 m_parallel_mng->broadcast(values, m_master_io_rank);
424}
425
426/*---------------------------------------------------------------------------*/
427/*---------------------------------------------------------------------------*/
428
429void MshParallelMeshReader::
430_getDoubleArrayAndBroadcast(ArrayView<double> values)
431{
432 IosFile* f = m_ios_file.get();
433 if (f) {
434 if (m_is_binary) {
435 f->binaryRead(values);
436 }
437 else {
438 for (double& v : values)
439 v = f->getReal();
440 }
441 }
442 if (m_is_parallel)
443 m_parallel_mng->broadcast(values, m_master_io_rank);
444}
445
446/*---------------------------------------------------------------------------*/
447/*---------------------------------------------------------------------------*/
448
449Real3 MshParallelMeshReader::
450_getReal3()
451{
452 IosFile* f = m_ios_file.get();
454 Real3 v;
455 if (m_is_binary) {
456 f->binaryRead(SmallSpan<Real3>(&v, 1));
457 }
458 else {
459 Real x = f->getReal();
460 Real y = f->getReal();
461 Real z = f->getReal();
462 v = Real3(x, y, z);
463 }
464 return v;
465}
466
467/*---------------------------------------------------------------------------*/
468/*---------------------------------------------------------------------------*/
469
470Int32 MshParallelMeshReader::
471_getInt32()
472{
473 IosFile* f = m_ios_file.get();
475 Int32 v = 0;
476 if (m_is_binary)
477 f->binaryRead(SmallSpan<Int32>(&v, 1));
478 else
479 v = f->getInteger();
480 return v;
481}
482
483/*---------------------------------------------------------------------------*/
484/*---------------------------------------------------------------------------*/
485
486Int64 MshParallelMeshReader::
487_getInt64()
488{
489 IosFile* f = m_ios_file.get();
491 Int64 v = 0;
492 if (m_is_binary)
493 f->binaryRead(SmallSpan<Int64>(&v, 1));
494 else
495 v = f->getInt64();
496 return v;
497}
498
499/*---------------------------------------------------------------------------*/
500/*---------------------------------------------------------------------------*/
501
502void MshParallelMeshReader::
503_goToNextLine()
504{
505 if (m_ios_file.get())
506 m_ios_file->goToEndOfLine();
507}
508
509/*---------------------------------------------------------------------------*/
510/*---------------------------------------------------------------------------*/
511
514{
515 // Determines the cell bounding box
516 Real max_value = FloatInfo<Real>::maxValue();
517 Real min_value = -max_value;
518 Real3 min_box(max_value, max_value, max_value);
519 Real3 max_box(min_value, min_value, min_value);
520 const Int64 nb_node = m_mesh_allocate_info.nodes_coordinates.largeSize();
521 for (Real3 pos : m_mesh_allocate_info.nodes_coordinates) {
522 min_box = math::min(min_box, pos);
523 max_box = math::max(max_box, pos);
524 }
525
527 UniqueArray<Int32> nodes_part(nb_node, 0);
528
529 // For partitioning, only the X coordinate is considered.
530 // We are sure it is valid for all mesh dimensions.
531 // We partition using intervals of equal length.
532 // NOTE: This works well if the set of nodes is well distributed.
533 // If not, we could use bisection by cutting
534 // at the average each time.
535 Real min_x = min_box.x;
536 Real max_x = max_box.x;
537 IParallelMng* pm = m_parallel_mng;
538 Real global_min_x = pm->reduce(Parallel::ReduceMin, min_x);
539 Real global_max_x = pm->reduce(Parallel::ReduceMax, max_x);
540 info() << "MIN_MAX_X=" << global_min_x << " " << global_max_x;
541
542 Real diff_v = (global_max_x - global_min_x) / static_cast<Real>(m_nb_part);
543 // Should not happen but necessary to avoid potential
544 // division by zero.
545 if (!math::isNearlyEqual(global_min_x, global_max_x)) {
546 for (Int64 i = 0; i < nb_node; ++i) {
547 Int32 part = static_cast<Int32>((m_mesh_allocate_info.nodes_coordinates[i].x - global_min_x) / diff_v);
548 part = std::clamp(part, 0, m_nb_part - 1);
549 nodes_part[i] = part;
550 }
551 }
552 UniqueArray<Int32> nb_node_per_rank(m_nb_part, 0);
553 // Builds the rank hash table
554 for (Int64 i = 0; i < nb_node; ++i) {
555 Int32 rank = m_parts_rank[nodes_part[i]];
556 Int64 uid = m_mesh_allocate_info.nodes_unique_id[i];
557 ++nb_node_per_rank[rank];
558 m_mesh_allocate_info.nodes_rank_map.insert(std::make_pair(uid, rank));
559 }
560 pm->reduce(Parallel::ReduceSum, nb_node_per_rank);
561 info() << "NB_NODE_PER_RANK=" << nb_node_per_rank;
562}
563
564/*---------------------------------------------------------------------------*/
565/*---------------------------------------------------------------------------*/
566
593{
594 FixedArray<Int64, 4> nodes_info;
595 _getInt64ArrayAndBroadcast(nodes_info.view());
596
597 Int64 nb_node_block = static_cast<Int32>(nodes_info[0]);
598 Int64 total_nb_node = nodes_info[1];
599 Int64 min_node_tag = nodes_info[2];
600 Int64 max_node_tag = nodes_info[3];
601
602 if (!m_is_binary)
603 _goToNextLine();
604
605 if (total_nb_node < 0)
606 ARCANE_THROW(IOException, "Invalid number of nodes : '{0}'", total_nb_node);
607
608 info() << "[Nodes] nb_node_block=" << nb_node_block
609 << " total_nb_node=" << total_nb_node
610 << " min_tag=" << min_node_tag
611 << " max_tag=" << max_node_tag
612 << " read_nb_part=" << m_nb_part
613 << " nb_rank=" << m_parallel_mng->commSize();
614
615 UniqueArray<MshNodeBlock>& node_blocks = m_mesh_allocate_info.node_blocks;
616 node_blocks.resize(nb_node_block);
617
618 for (Int32 i = 0; i < nb_node_block; ++i) {
619 MshNodeBlock& node_block = node_blocks[i];
620 node_block.index = i;
621 _readNodesOneEntity(node_block);
622 }
623
625
626 if (m_is_binary)
627 _goToNextLine();
628}
629
630/*---------------------------------------------------------------------------*/
631/*---------------------------------------------------------------------------*/
632
633void MshParallelMeshReader::
634_readNodesOneEntity(MshNodeBlock& node_block)
635{
636 IosFile* ios_file = m_ios_file.get();
637 IParallelMng* pm = m_parallel_mng;
638 const Int32 my_rank = pm->commRank();
639
640 UniqueArray<Int64> nodes_uids;
641 UniqueArray<Real3> nodes_coordinates;
642
643 FixedArray<Int32, 3> entity_infos;
644 _getInt32ArrayAndBroadcast(entity_infos.view());
645 Int32 nb_node2 = CheckedConvert::toInt32(_getInt64AndBroadcast());
646
647 if (!m_is_binary)
648 _goToNextLine();
649
650 // Entity dimension (not useful)
651 Int32 entity_dim = entity_infos[0];
652 node_block.entity_dim = entity_dim;
653 // Associated entity tag
654 Int32 entity_tag = entity_infos[1];
655 node_block.entity_tag = entity_tag;
656
657 node_block.index_in_allocation_info = m_mesh_allocate_info.nodes_coordinates.size();
658 node_block.nb_node = nb_node2;
659
660 Int32 parametric_coordinates = entity_infos[2];
661
662 info(4) << "[Nodes] index=" << node_block.index << " entity_dim=" << entity_dim << " entity_tag=" << entity_tag
663 << " parametric=" << parametric_coordinates
664 << " nb_node2=" << nb_node2;
665
666 if (parametric_coordinates != 0)
667 ARCANE_THROW(NotSupportedException, "Only 'parametric coordinates' value of '0' is supported (current={0})", parametric_coordinates);
668
669 // It is possible that the number of nodes is 0.
670 // In this case, we must proceed directly to the next line
671 if (nb_node2 == 0)
672 return;
673
674 // Partition the reading into \a m_nb_part
675 // For each i_entity, we first have the list of identifiers then the list of coordinates
676
677 for (Int32 i_part = 0; i_part < m_nb_part; ++i_part) {
678 Int64 nb_to_read = _interval(i_part, m_nb_part, nb_node2).second;
679 Int32 dest_rank = m_parts_rank[i_part];
680 info(4) << "Reading UIDS part i=" << i_part << " dest_rank=" << dest_rank << " nb_to_read=" << nb_to_read;
681 if (my_rank == dest_rank || my_rank == m_master_io_rank) {
682 nodes_uids.resize(nb_to_read);
683 }
684
685 // The master rank reads the node information for the relevant part
686 // and transfers it to the destination rank
687 if (ios_file) {
688 if (m_is_binary) {
689 ios_file->binaryRead(nodes_uids.view());
690 }
691 else {
692 for (Integer i = 0; i < nb_to_read; ++i) {
693 // Keeps the node uniqueId().
694 nodes_uids[i] = ios_file->getInt64();
695 //info() << "I=" << i << " ID=" << nodes_uids[i];
696 }
697 }
698 if (dest_rank != m_master_io_rank) {
699 pm->send(nodes_uids, dest_rank);
700 }
701 }
702 else if (my_rank == dest_rank) {
703 pm->recv(nodes_uids, m_master_io_rank);
704 }
705
706 // Keeps the information for my part
707 if (my_rank == dest_rank) {
708 m_mesh_allocate_info.nodes_unique_id.addRange(nodes_uids);
709 node_block.nb_node = nodes_uids.size();
710 }
711 }
712
713 // Reading coordinates by part
714 for (Int32 i_part = 0; i_part < m_nb_part; ++i_part) {
715 Int64 nb_to_read = _interval(i_part, m_nb_part, nb_node2).second;
716 Int32 dest_rank = m_parts_rank[i_part];
717 info(4) << "Reading COORDS part i=" << i_part << " dest_rank=" << dest_rank << " nb_to_read=" << nb_to_read;
718 if (my_rank == dest_rank || my_rank == m_master_io_rank) {
719 nodes_coordinates.resize(nb_to_read);
720 }
721
722 // The master rank reads the node information for the relevant part
723 // and transfers it to the destination rank
724 if (ios_file) {
725 if (m_is_binary) {
726 ios_file->binaryRead(nodes_coordinates.view());
727 }
728 else {
729 for (Integer i = 0; i < nb_to_read; ++i) {
730 nodes_coordinates[i] = _getReal3();
731 //info() << "I=" << i << " ID=" << nodes_uids[i] << " COORD=" << Real3(nx, ny, nz);
732 }
733 }
734 if (dest_rank != m_master_io_rank) {
735 pm->send(nodes_coordinates, dest_rank);
736 }
737 }
738 else if (my_rank == dest_rank) {
739 pm->recv(nodes_coordinates, m_master_io_rank);
740 }
741
742 // Keeps the information for my part
743 if (my_rank == dest_rank) {
744 m_mesh_allocate_info.nodes_coordinates.addRange(nodes_coordinates);
745 }
746 }
747
748 if (!m_is_binary)
749 _goToNextLine();
750}
751
752/*---------------------------------------------------------------------------*/
753/*---------------------------------------------------------------------------*/
754
760{
761 IosFile* ios_file = m_ios_file.get();
762 IParallelMng* pm = m_parallel_mng;
763 const Int32 my_rank = pm->commRank();
764 const Int64 nb_entity_in_block = block.nb_entity;
765 const Int32 item_nb_node = block.item_nb_node;
766 const bool is_print_level1 = m_verbosity_level > 0;
767 const bool is_print_level2 = m_verbosity_level > 1;
768
769 if (is_print_level1)
770 info() << "Reading block nb_entity=" << nb_entity_in_block << " item_nb_node=" << item_nb_node;
771
773 UniqueArray<Int64> connectivities;
774
775 UniqueArray<Int64> tmp_uid_and_connectivities;
776
777 for (Int32 i_part = 0; i_part < m_nb_part; ++i_part) {
778 const Int64 nb_to_read = _interval(i_part, m_nb_part, nb_entity_in_block).second;
779 const Int32 dest_rank = m_parts_rank[i_part];
780
781 if (is_print_level2)
782 info(4) << "Reading block part i_part=" << i_part
783 << " nb_to_read=" << nb_to_read << " dest_rank=" << dest_rank;
784
785 const Int64 nb_uid = nb_to_read;
786 const Int64 nb_connectivity = nb_uid * item_nb_node;
787 if (my_rank == dest_rank || my_rank == m_master_io_rank) {
788 uids.resize(nb_uid);
789 connectivities.resize(nb_connectivity);
790 }
791 if (ios_file) {
792 if (m_is_binary) {
793 Int64 nb_to_read = nb_uid * (item_nb_node + 1);
794 tmp_uid_and_connectivities.resize(nb_to_read);
795 ios_file->binaryRead(tmp_uid_and_connectivities.view());
796 Int64 index = 0;
797 for (Int64 i = 0; i < nb_uid; ++i) {
798 Int64 item_unique_id = tmp_uid_and_connectivities[index];
799 ++index;
800 uids[i] = item_unique_id;
801 for (Int32 j = 0; j < item_nb_node; ++j) {
802 connectivities[(i * item_nb_node) + j] = tmp_uid_and_connectivities[index];
803 ++index;
804 }
805 }
806 }
807 else {
808 // Use Int64 to ensure no overflow.
809 for (Int64 i = 0; i < nb_uid; ++i) {
810 Int64 item_unique_id = ios_file->getInt64();
811 uids[i] = item_unique_id;
812 for (Int32 j = 0; j < item_nb_node; ++j)
813 connectivities[(i * item_nb_node) + j] = ios_file->getInt64();
814 }
815 }
816 if (dest_rank != m_master_io_rank) {
817 pm->send(uids, dest_rank);
818 pm->send(connectivities, dest_rank);
819 }
820 }
821 else if (my_rank == dest_rank) {
822 pm->recv(uids, m_master_io_rank);
823 pm->recv(connectivities, m_master_io_rank);
824 }
825 if (my_rank == dest_rank) {
826 block.uids.addRange(uids);
827 block.connectivities.addRange(connectivities);
828 }
829 }
830}
831
832/*---------------------------------------------------------------------------*/
833/*---------------------------------------------------------------------------*/
834
865{
866 IosFile* ios_file = m_ios_file.get();
867 IParallelMng* pm = m_parallel_mng;
868
869 const bool is_print_level1 = m_verbosity_level > 0;
870
871 FixedArray<Int64, 4> elements_info;
872 _getInt64ArrayAndBroadcast(elements_info.view());
873
874 Int64 nb_block = elements_info[0];
875 Int64 number_of_elements = elements_info[1];
876 Int64 min_element_tag = elements_info[2];
877 Int64 max_element_tag = elements_info[3];
878
879 if (!m_is_binary)
880 _goToNextLine();
881
882 info() << "[Elements] nb_block=" << nb_block
883 << " nb_elements=" << number_of_elements
884 << " min_element_tag=" << min_element_tag
885 << " max_element_tag=" << max_element_tag;
886
887 if (number_of_elements < 0)
888 ARCANE_THROW(IOException, "Invalid number of elements: {0}", number_of_elements);
889
890 UniqueArray<MshElementBlock>& blocks = m_mesh_allocate_info.element_blocks;
891 blocks.resize(nb_block);
892
893 {
894 // Number the blocks (for debugging)
895 Integer index = 0;
896 for (MshElementBlock& block : blocks) {
897 block.index = index;
898 ++index;
899 }
900 }
901
902 for (MshElementBlock& block : blocks) {
903
904 FixedArray<Int32, 3> block_info;
905 _getInt32ArrayAndBroadcast(block_info.view());
906
907 Int32 entity_dim = block_info[0];
908 Int32 entity_tag = block_info[1];
909 Int32 entity_type = block_info[2];
910 Int64 nb_entity_in_block = _getInt64AndBroadcast();
911
912 const MshToArcaneTypeInfo& msh_tinfo = mshToArcaneTypeInfo(entity_type);
913 ItemTypeInfo* tinfo = msh_tinfo.m_arcane_type_info;
914 Int32 item_nb_node = tinfo->nbLocalNode();
915 ItemTypeId item_type = tinfo->itemTypeId();
916
917 if (is_print_level1)
918 info() << "[Elements] index=" << block.index << " entity_dim=" << entity_dim
919 << " entity_tag=" << entity_tag
920 << " msh_entity_type=" << entity_type << " nb_in_block=" << nb_entity_in_block
921 << " arcane_item_type=" << item_type << " item_nb_node=" << item_nb_node;
922
923 block.nb_entity = nb_entity_in_block;
924 block.item_type = item_type;
925 block.item_nb_node = item_nb_node;
926 block.dimension = entity_dim;
927 block.entity_tag = entity_tag;
928 block.reorder_infos = msh_tinfo.m_reorder_infos;
929 if (entity_type == MSH_PNT) {
930 // If the type is a point, the processing seems a bit special.
931 // In this case, there are two integers in the following line:
932 // - an integer that does not seem to be used
933 // - the unique node number we are interested in
934 Int64 item_unique_id = NULL_ITEM_UNIQUE_ID;
935 if (ios_file) {
936 [[maybe_unused]] Int64 unused_id = _getInt64();
937 item_unique_id = _getInt64();
938 if (is_print_level1)
939 info() << "Adding unique node uid=" << item_unique_id;
940 }
941 if (m_is_parallel)
942 pm->broadcast(ArrayView<Int64>(1, &item_unique_id), m_master_io_rank);
943 block.uids.add(item_unique_id);
944 }
945 else {
947 }
948 if (!m_is_binary)
949 _goToNextLine();
950 }
951
952 if (m_is_binary)
953 _goToNextLine();
954
955 // Now that we have all the blocks, the mesh dimension is
956 // the largest dimension of the blocks
957 Integer mesh_dimension = -1;
958 for (const MshElementBlock& block : blocks)
959 mesh_dimension = math::max(mesh_dimension, block.dimension);
960 if (mesh_dimension < 0)
961 ARCANE_FATAL("Invalid computed mesh dimension '{0}'", mesh_dimension);
962 if (mesh_dimension != 2 && mesh_dimension != 3)
963 ARCANE_THROW(NotSupportedException, "mesh dimension '{0}'. Only 2D or 3D meshes are supported", mesh_dimension);
964 info() << "Computed mesh dimension = " << mesh_dimension;
965
966 bool allow_multi_dim_cell = m_mesh->meshKind().isNonManifold();
967 bool use_experimental_type_for_cell = false;
968 if (allow_multi_dim_cell) {
969 // By default, use the new types.
970 use_experimental_type_for_cell = true;
971 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_USE_EXPERIMENTAL_CELL_TYPE", true))
972 use_experimental_type_for_cell = (v.value() != 0);
973 }
974 info() << "Use experimental cell type?=" << use_experimental_type_for_cell;
975 ItemTypeMng* item_type_mng = m_mesh->itemTypeMng();
976 for (MshElementBlock& block : blocks) {
977 const Int32 block_dim = block.dimension;
978 String item_type_name = item_type_mng->typeFromId(block.item_type)->typeName();
979 if (is_print_level1)
980 info() << "Reading block dim=" << block_dim << " type_name=" << item_type_name;
981 if (block_dim == mesh_dimension)
982 _computeOwnItems(block, m_mesh_allocate_info.cells_infos, false);
983 else if (allow_multi_dim_cell) {
984 // Check if we can create cells of dimensions lower than those
985 // of the mesh.
986 bool use_sub_dim_cell = false;
987 if (mesh_dimension == 3 && (block_dim == 2 || block_dim == 1))
988 // 1D or 2D cell in a 3D mesh
989 use_sub_dim_cell = true;
990 else if (mesh_dimension == 2 && block_dim == 1)
991 // 1D cell in a 2D mesh
992 use_sub_dim_cell = true;
993 if (!use_experimental_type_for_cell)
994 use_sub_dim_cell = false;
995 if (use_sub_dim_cell) {
996 // Here we will create 2D cells in a 3D mesh.
997 // We convert the base type into an equivalent type for the cells.
998 if (mesh_dimension == 3) {
999 if (block.item_type == IT_Triangle3)
1000 block.item_type = ItemTypeId(IT_Cell3D_Triangle3);
1001 else if (block.item_type == IT_Triangle6)
1002 block.item_type = ItemTypeId(ITI_Cell3D_Triangle6);
1003 else if (block.item_type == IT_Quad4)
1004 block.item_type = ItemTypeId(IT_Cell3D_Quad4);
1005 else if (block.item_type == IT_Quad8)
1006 block.item_type = ItemTypeId(IT_Cell3D_Quad8);
1007 else if (block.item_type == IT_Quad9)
1008 block.item_type = ItemTypeId(IT_Cell3D_Quad9);
1009 else if (block.item_type == IT_Line2)
1010 block.item_type = ItemTypeId(IT_Cell3D_Line2);
1011 else if (block.item_type == IT_Line3)
1012 block.item_type = ItemTypeId(IT_Cell3D_Line3);
1013 else
1014 ARCANE_FATAL("Not supported sub dimension cell type={0} for 3D mesh", item_type_name);
1015 }
1016 else if (mesh_dimension == 2) {
1017 if (block.item_type == IT_Line2)
1018 block.item_type = ItemTypeId(IT_CellLine2);
1019 else if (block.item_type == IT_Line3)
1020 block.item_type = ItemTypeId(IT_CellLine3);
1021 else
1022 ARCANE_FATAL("Not supported sub dimension cell type={0} for 2D mesh", item_type_name);
1023 }
1024 block.is_built_as_cells = true;
1025 _computeOwnItems(block, m_mesh_allocate_info.cells_infos, false);
1026 }
1027 }
1028 }
1029
1030 return mesh_dimension;
1031}
1032
1033/*---------------------------------------------------------------------------*/
1034/*---------------------------------------------------------------------------*/
1035
1036namespace
1037{
1038 template <typename DataType> inline ArrayView<DataType>
1039 _broadcastArrayWithSize(IParallelMng* pm, ArrayView<DataType> values,
1040 UniqueArray<DataType>& work_values, Int32 dest_rank, Int64 size)
1041 {
1042 const Int32 my_rank = pm->commRank();
1043 ArrayView<DataType> view = values;
1044 if (my_rank != dest_rank) {
1045 work_values.resize(size);
1046 view = work_values.view();
1047 }
1048 pm->broadcast(view, dest_rank);
1049 return view;
1050 }
1058 template <typename DataType> inline ArrayView<DataType>
1059 _broadcastArray(IParallelMng* pm, ArrayView<DataType> values,
1060 UniqueArray<DataType>& work_values, Int32 dest_rank)
1061 {
1062 const Int32 my_rank = pm->commRank();
1063 Int64 size = 0;
1064 // Send the size
1065 if (dest_rank == my_rank)
1066 size = values.size();
1067 pm->broadcast(ArrayView<Int64>(1, &size), dest_rank);
1068 return _broadcastArrayWithSize(pm, values, work_values, dest_rank, size);
1069 }
1070
1071} // namespace
1072
1073/*---------------------------------------------------------------------------*/
1074/*---------------------------------------------------------------------------*/
1075
1076void MshParallelMeshReader::
1077_computeOwnItems(MshElementBlock& block, MshItemKindInfo& item_kind_info, bool is_generate_uid)
1078{
1079 // We only keep entities whose first node belongs to our rank.
1080
1081 IParallelMng* pm = m_parallel_mng;
1082 const Int32 my_rank = pm->commRank();
1083 const bool is_print_level1 = m_verbosity_level > 0;
1084
1085 const ItemTypeId item_type = block.item_type;
1086 const Int32 item_nb_node = block.item_nb_node;
1087
1088 UniqueArray<Int64> connectivities;
1089 UniqueArray<Int64> uids;
1090 UniqueArray<Int32> nodes_rank;
1091
1092 SmallSpan<const Int16> reorder_infos = block.reorder_infos;
1093 bool has_reorder_info = !reorder_infos.empty();
1094 const Int32 nb_part = m_parts_rank.size();
1095 if (is_print_level1)
1096 info() << "Compute own items block_index=" << block.index << " nb_part=" << nb_part
1097 << " has_reorder?=" << has_reorder_info;
1098 // List of element nodes with Arcane connectivity.
1099 SmallArray<Int64> arcane_reordered_uids;
1100 if (has_reorder_info)
1101 arcane_reordered_uids.resize(item_nb_node);
1102 for (Int32 i_part = 0; i_part < nb_part; ++i_part) {
1103 const Int32 dest_rank = m_parts_rank[i_part];
1104 // Broadcast the i_part-th part of the cell uids and connectivities
1105 ArrayView<Int64> connectivities_view = _broadcastArray(pm, block.connectivities.view(), connectivities, dest_rank);
1106 ArrayView<Int64> uids_view = _broadcastArray(pm, block.uids.view(), uids, dest_rank);
1107
1108 Int32 nb_item = uids_view.size();
1109 nodes_rank.resize(nb_item);
1110 nodes_rank.fill(-1);
1111
1112 // Iterate through the entities. Each entity will belong to the rank
1113 // of its first node. If this part corresponds to my rank, then
1114 // we keep the cell.
1115 for (Int32 i = 0; i < nb_item; ++i) {
1116 Int64 first_node_uid = connectivities_view[i * item_nb_node];
1117 auto x = m_mesh_allocate_info.nodes_rank_map.find(first_node_uid);
1118 if (x == m_mesh_allocate_info.nodes_rank_map.end())
1119 // The node is not in my list
1120 continue;
1121 Int32 rank = x->second;
1122 nodes_rank[i] = rank;
1123 }
1124 pm->reduce(Parallel::ReduceMax, nodes_rank);
1125 for (Int32 i = 0; i < nb_item; ++i) {
1126 const Int32 rank = nodes_rank[i];
1127 if (rank != my_rank)
1128 // The node is not in my part
1129 continue;
1130 // The node is mine, I add the entity to the list of
1131 // entities I will create.
1132 ConstArrayView<Int64> v = connectivities_view.subView(i * item_nb_node, item_nb_node);
1133 Int64 uid = uids_view[i];
1134 if (is_generate_uid)
1135 // The uniqueId() will be generated automatically
1136 uid = NULL_ITEM_UNIQUE_ID;
1137 if (has_reorder_info) {
1138 // Reorder the nodes if the Arcane type does not have the same numbering
1139 // as the MSH type.
1140 for (Int32 zz = 0; zz < item_nb_node; ++zz)
1141 arcane_reordered_uids[zz] = v[reorder_infos[zz]];
1142 v = arcane_reordered_uids.view();
1143 }
1144 item_kind_info.addItem(item_type, uid, v);
1145 }
1146 }
1147}
1148
1149/*---------------------------------------------------------------------------*/
1150/*---------------------------------------------------------------------------*/
1166{
1167 UniqueArray<Int64> uids_storage;
1168 UniqueArray<Real3> coords_storage;
1169 UniqueArray<Int32> local_ids;
1170
1171 IParallelMng* pm = m_parallel_mng;
1172
1173 const IItemFamily* node_family = m_mesh->nodeFamily();
1174 VariableNodeReal3& nodes_coord_var(m_mesh->nodesCoordinates());
1175
1176 for (Int32 dest_rank : m_parts_rank) {
1177 ConstArrayView<Int64> uids = _broadcastArray(pm, m_mesh_allocate_info.nodes_unique_id.view(), uids_storage, dest_rank);
1178 ConstArrayView<Real3> coords = _broadcastArray(pm, m_mesh_allocate_info.nodes_coordinates.view(), coords_storage, dest_rank);
1179
1180 Int32 nb_item = uids.size();
1181 local_ids.resize(nb_item);
1182
1183 // Convert uniqueId() to localId(). If they are non-null
1184 // it means the entity is in my subdomain and therefore we can
1185 // position its coordinate
1186 node_family->itemsUniqueIdToLocalId(local_ids, uids, false);
1187 for (Int32 i = 0; i < nb_item; ++i) {
1188 NodeLocalId nid(local_ids[i]);
1189 if (!nid.isNull())
1190 nodes_coord_var[nid] = coords[i];
1191 }
1192 }
1193}
1194
1195/*---------------------------------------------------------------------------*/
1196/*---------------------------------------------------------------------------*/
1197
1198void MshParallelMeshReader::
1199_allocateCells()
1200{
1201 IMesh* mesh = m_mesh;
1202 Integer nb_elements = m_mesh_allocate_info.cells_infos.nb_item;
1203 info() << "nb_of_elements=cells_type.size()=" << nb_elements;
1204 Integer nb_cell_node = m_mesh_allocate_info.cells_infos.items_infos.size();
1205 info() << "nb_cell_node=cells_connectivity.size()=" << nb_cell_node;
1206
1207 // Creating cells
1208 info() << "Building cells, nb_cell=" << nb_elements << " nb_cell_node=" << nb_cell_node;
1209 IPrimaryMesh* pmesh = mesh->toPrimaryMesh();
1210 info() << "## Allocating ##";
1211 pmesh->allocateCells(nb_elements, m_mesh_allocate_info.cells_infos.items_infos, false);
1212 info() << "## Ending ##";
1213 pmesh->endAllocate();
1214 info() << "## Done ##";
1215}
1216
1217/*---------------------------------------------------------------------------*/
1218/*---------------------------------------------------------------------------*/
1219
1220void MshParallelMeshReader::
1221_allocateGroups()
1222{
1223 IMesh* mesh = m_mesh;
1224 Int32 mesh_dim = mesh->dimension();
1225 Int32 face_dim = mesh_dim - 1;
1226 UniqueArray<MshEntitiesWithNodes> entity_list;
1227 UniqueArray<MshPhysicalName> physical_name_list;
1228 IItemFamily* node_family = mesh->nodeFamily();
1229
1230 for (MshElementBlock& block : m_mesh_allocate_info.element_blocks) {
1231 entity_list.clear();
1232 physical_name_list.clear();
1233 Int32 block_index = block.index;
1234 Int32 block_dim = block.dimension;
1235 // We allocate a group if it has an associated physical name.
1236 // For this, it must already be associated with an entity.
1237 Int64 block_entity_tag = block.entity_tag;
1238 if (block_entity_tag < 0) {
1239 info(5) << "[Groups] Skipping block index=" << block_index << " because it has no entity";
1240 continue;
1241 }
1242 if (block_dim == 0) {
1243 const MshEntitiesNodes* entity = m_mesh_info->findNodeEntities(block_entity_tag);
1244 if (!entity) {
1245 info(5) << "[Groups] Skipping block index=" << block_index
1246 << " because entity tag is invalid";
1247 continue;
1248 }
1249 Int64 entity_physical_tag = entity->physicalTag();
1250 MshPhysicalName physical_name = m_mesh_info->findPhysicalName(block_dim, entity_physical_tag);
1251 physical_name_list.add(physical_name);
1252 }
1253 else {
1254 m_mesh_info->findEntities(block_dim, block_entity_tag, entity_list);
1255 for (const MshEntitiesWithNodes& x : entity_list) {
1256 Int64 entity_physical_tag = x.physicalTag();
1257 MshPhysicalName physical_name = m_mesh_info->findPhysicalName(block_dim, entity_physical_tag);
1258 physical_name_list.add(physical_name);
1259 }
1260 }
1261 for (const MshPhysicalName& physical_name : physical_name_list) {
1262 if (physical_name.isNull()) {
1263 info(5) << "[Groups] Skipping block index=" << block_index
1264 << " because entity physical tag is invalid";
1265 continue;
1266 }
1267 String group_name = physical_name.name();
1268 info(4) << "[Groups] Block index=" << block_index << " dim=" << block_dim
1269 << " name='" << group_name << "' built_as_cells=" << block.is_built_as_cells;
1270 if (block_dim == mesh_dim || block.is_built_as_cells) {
1271 _addCellOrNodeGroup(block.uids, block.index, group_name, mesh->cellFamily(), false);
1272 }
1273 else if (block_dim == face_dim) {
1274 _addFaceGroup(block, group_name);
1275 }
1276 else {
1277 // These are nodes
1278 _addCellOrNodeGroup(block.uids, block.index, group_name, node_family, false);
1279 }
1280 }
1281 }
1282
1283 // Create the node groups associated with the $Nodes blocks
1284 {
1285 //bool has_periodic = m_mesh_info->m_periodic_info.hasValues();
1286 UniqueArray<Int64>& nodes_uids = m_mesh_allocate_info.nodes_unique_id;
1287 // Create the node groups derived from the blocks in $Nodes
1288 for (const MshNodeBlock& block : m_mesh_allocate_info.node_blocks) {
1289 ArrayView<Int64> block_uids = nodes_uids.subView(block.index_in_allocation_info, block.nb_node);
1290 MshPhysicalName physical_name = m_mesh_info->findPhysicalName(block.entity_dim, block.entity_tag);
1291 String group_name = physical_name.name();
1292 info(4) << "NodeBlock name=" << group_name << " index=" << block.index
1293 << " index_in_allocation=" << block.index_in_allocation_info
1294 << " nb_node=" << block.nb_node;
1295 // If we have periodicity information, we always create the corresponding node groups
1296 // to the blocks, because they can be referenced by the periodicity information.
1297 // In this case, we generate a group name.
1298 // NOTE: disable this because it can generate a very large number of groups
1299 // when there is a lot of periodicity information and furthermore we are not yet using
1300 // this when writing the periodic information.
1301 //if (physical_name.isNull() && has_periodic)
1302 //group_name = String::format("ArcaneMshInternalNodesDim{0}Entity{1}", block.entity_dim, block.entity_tag);
1303 if (!group_name.null())
1304 _addCellOrNodeGroup(block_uids, block.index, group_name, node_family, true);
1305 }
1306 }
1307}
1308
1309/*---------------------------------------------------------------------------*/
1310/*---------------------------------------------------------------------------*/
1311
1316_addFaceGroup(const MshElementBlock& block, const String& group_name)
1317{
1318 IParallelMng* pm = m_parallel_mng;
1319
1320 UniqueArray<Int64> connectivities;
1321 for (Int32 dest_rank : m_parts_rank) {
1322 ArrayView<Int64> connectivities_view = _broadcastArray(pm, block.connectivities.view(), connectivities, dest_rank);
1323 _addFaceGroupOnePart(block, connectivities_view, group_name);
1324 }
1325}
1326
1327/*---------------------------------------------------------------------------*/
1328/*---------------------------------------------------------------------------*/
1329
1330void MshParallelMeshReader::
1331_addFaceGroupOnePart(const MshElementBlock& block, ConstArrayView<Int64> connectivities,
1332 const String& group_name)
1333{
1334 IMesh* mesh = m_mesh;
1335 const Int32 item_nb_node = block.item_nb_node;
1336 const Int32 block_index = block.index;
1337 const ItemTypeId type_id = block.item_type;
1338 const Int32 nb_entity = connectivities.size() / item_nb_node;
1339
1340 // There may be several blocks for the same group.
1341 // We retrieve the group if it already exists.
1342 FaceGroup face_group = mesh->faceFamily()->findGroup(group_name, true);
1343
1344 UniqueArray<Int32> faces_id; // Face number in the mesh \a mesh
1345 faces_id.reserve(nb_entity);
1346
1347 const Int32 face_nb_node = nb_entity * item_nb_node;
1348
1349 UniqueArray<Int64> faces_first_node_unique_id(nb_entity);
1350 UniqueArray<Int32> faces_first_node_local_id(nb_entity);
1351 UniqueArray<Int64> faces_nodes_unique_id(face_nb_node);
1352 Integer faces_nodes_unique_id_index = 0;
1353
1354 UniqueArray<Int64> orig_nodes_id(item_nb_node);
1355 //UniqueArray<Integer> face_nodes_index(item_nb_node);
1356
1357 IItemFamily* node_family = mesh->nodeFamily();
1358 NodeInfoListView mesh_nodes(node_family);
1359 NodesOfItemReorderer m_nodes_reorderer(mesh->itemTypeMng());
1360
1361 // Reorders the face identifiers to find the face in the mesh.
1362 // For this, we retrieve the first node of the face and check if it
1363 // is located in our subdomain. If so, the face will be added to our
1364 // part of the mesh
1365 for (Integer i_face = 0; i_face < nb_entity; ++i_face) {
1366 for (Integer z = 0; z < item_nb_node; ++z)
1367 orig_nodes_id[z] = connectivities[faces_nodes_unique_id_index + z];
1368 m_nodes_reorderer.reorder(type_id, orig_nodes_id);
1369 ConstArrayView<Int64> sorted_nodes(m_nodes_reorderer.sortedNodes());
1370 for (Integer z = 0; z < item_nb_node; ++z)
1371 faces_nodes_unique_id[faces_nodes_unique_id_index + z] = sorted_nodes[z];
1372 faces_first_node_unique_id[i_face] = sorted_nodes[0];
1373 faces_nodes_unique_id_index += item_nb_node;
1374 }
1375
1376 node_family->itemsUniqueIdToLocalId(faces_first_node_local_id, faces_first_node_unique_id, false);
1377
1378 const bool is_non_manifold = m_mesh->meshKind().isNonManifold();
1379 faces_nodes_unique_id_index = 0;
1380 for (Integer i_face = 0; i_face < nb_entity; ++i_face) {
1381 const Integer n = item_nb_node;
1382 Int32 face_first_node_lid = faces_first_node_local_id[i_face];
1383 if (face_first_node_lid != NULL_ITEM_LOCAL_ID) {
1384 Int64ConstArrayView face_nodes_id(item_nb_node, &faces_nodes_unique_id[faces_nodes_unique_id_index]);
1385 Node current_node(mesh_nodes[faces_first_node_local_id[i_face]]);
1386 Face face = MeshUtils::getFaceFromNodesUniqueId(current_node, face_nodes_id);
1387
1388 // In parallel, it is possible that the face is not in our subdomain
1389 // even if one of its nodes is
1390 if (face.null()) {
1391 if (!m_is_parallel) {
1392 OStringStream ostr;
1393 ostr() << "(Nodes:";
1394 for (Integer z = 0; z < n; ++z)
1395 ostr() << ' ' << face_nodes_id[z];
1396 ostr() << " - node_lid=" << current_node.localId() << ")";
1397 String error_string = "INTERNAL: MshMeshReader face index={0} with nodes '{1}' is not in node/face connectivity.";
1398 if (!is_non_manifold)
1399 error_string = error_string + "\n This errors may occur if the mesh is non-manifold."
1400 "\n See Arcane documentation to specify the mesh is a non manifold one.\n";
1401 ARCANE_FATAL(error_string, i_face, ostr.str());
1402 }
1403 }
1404 else
1405 faces_id.add(face.localId());
1406 }
1407
1408 faces_nodes_unique_id_index += n;
1409 }
1410 info(4) << "Adding " << faces_id.size() << " faces from block index=" << block_index
1411 << " to group '" << face_group.name() << "'";
1412 face_group.addItems(faces_id);
1413}
1414
1415/*---------------------------------------------------------------------------*/
1416/*---------------------------------------------------------------------------*/
1417
1422_addCellOrNodeGroup(ArrayView<Int64> block_uids, Int32 block_index,
1423 const String& group_name, IItemFamily* family, bool filter_invalid)
1424{
1425 IParallelMng* pm = m_parallel_mng;
1426
1427 UniqueArray<Int64> uids;
1428 for (Int32 dest_rank : m_parts_rank) {
1429 ArrayView<Int64> uids_view = _broadcastArray(pm, block_uids, uids, dest_rank);
1430 _addCellOrNodeGroupOnePart(uids_view, group_name, block_index, family, filter_invalid);
1431 }
1432}
1433
1434/*---------------------------------------------------------------------------*/
1435/*---------------------------------------------------------------------------*/
1436
1437void MshParallelMeshReader::
1438_addCellOrNodeGroupOnePart(ConstArrayView<Int64> uids, const String& group_name,
1439 Int32 block_index, IItemFamily* family, bool filter_invalid)
1440{
1441 const Int32 nb_entity = uids.size();
1442
1443 // There may be several blocks for the same group.
1444 // We retrieve the group if it already exists.
1445 ItemGroup group = family->findGroup(group_name, true);
1446
1447 UniqueArray<Int32> items_lid(nb_entity);
1448
1449 family->itemsUniqueIdToLocalId(items_lid, uids, false);
1450
1451 // In parallel, it is possible that some entities of the group are not
1452 // in our subdomain. They must be filtered.
1453 // Similarly, if it is a group derived from a $Entity node, it is possible
1454 // that the node does not exist if it is not attached to a cell
1455 // (TODO: to verify with sod3d-misc.msh)
1456 if (m_is_parallel || filter_invalid) {
1457 auto items_begin = items_lid.begin();
1458 Int64 new_size = std::remove(items_begin, items_lid.end(), NULL_ITEM_LOCAL_ID) - items_begin;
1459 items_lid.resize(new_size);
1460 }
1461
1462 info() << "Adding " << items_lid.size() << " items from block index=" << block_index
1463 << " to group '" << group_name << "' for family=" << family->name();
1464
1465 group.addItems(items_lid);
1466}
1467
1468/*---------------------------------------------------------------------------*/
1469/*---------------------------------------------------------------------------*/
1470/*
1471 * $PhysicalNames // same as MSH version 2
1472 * numPhysicalNames(ASCII int)
1473 * dimension(ASCII int) physicalTag(ASCII int) "name"(127 characters max)
1474 * ...
1475 * $EndPhysicalNames
1476 */
1477void MshParallelMeshReader::
1478_readPhysicalNames()
1479{
1480 // NOTE: even in binary, the $PhysicalNames section is written in ASCII.
1481 String quote_mark = "\"";
1482 Int32 nb_name = _getIntegerAndBroadcast();
1483 info() << "nb_physical_name=" << nb_name;
1484
1485 _goToNextLine();
1486
1487 for (Int32 i = 0; i < nb_name; ++i) {
1488 Int32 dim = _getIntegerAndBroadcast();
1489 Int32 tag = _getIntegerAndBroadcast();
1490 String s = _getNextLineAndBroadcast();
1491 if (dim < 0 || dim > 3)
1492 ARCANE_FATAL("Invalid value for physical name dimension dim={0}", dim);
1493 // Group names may start with spaces and contain
1494 // quotes that must be removed.
1496 if (s.startsWith(quote_mark))
1497 s = s.substring(1);
1498 if (s.endsWith(quote_mark))
1499 s = s.substring(0, s.length() - 1);
1500 m_mesh_info->physical_name_list.add(dim, tag, s);
1501 info(4) << "[PhysicalName] index=" << i << " dim=" << dim << " tag=" << tag << " name='" << s << "'";
1502 }
1503
1504 String s = _getNextLineAndBroadcast();
1505 if (s != "$EndPhysicalNames")
1506 ARCANE_FATAL("found '{0}' and expected '$EndPhysicalNames'", s);
1507}
1508
1509/*---------------------------------------------------------------------------*/
1510/*---------------------------------------------------------------------------*/
1511
1544{
1545 IosFile* ios_file = m_ios_file.get();
1546
1547 FixedArray<Int64, 4> nb_dim_item;
1548 _getInt64ArrayAndBroadcast(nb_dim_item.view());
1549
1550 const bool is_print_level1 = m_verbosity_level > 0;
1551
1552 info() << "[Entities] nb_0d=" << nb_dim_item[0] << " nb_1d=" << nb_dim_item[1]
1553 << " nb_2d=" << nb_dim_item[2] << " nb_3d=" << nb_dim_item[3];
1554 // After the format, we may have entities, but this is optional
1555 // If they are present, we read the file until the end of this section.
1556 if (!m_is_binary)
1557 _goToNextLine();
1558
1559 // Reading entities associated with points
1560 for (Int64 i = 0; i < nb_dim_item[0]; ++i) {
1561 FixedArray<Int64, 2> tag_info;
1562 if (ios_file) {
1563 Int32 tag = _getInt32();
1564 Real3 xyz = _getReal3();
1565 Int64 num_physical_tag = _getInt64();
1566 if (num_physical_tag > 1)
1567 ARCANE_FATAL("NotImplemented numPhysicalTag>1 (n={0}, index={1} xyz={2})",
1568 num_physical_tag, i, xyz);
1569
1570 Int32 physical_tag = -1;
1571 if (num_physical_tag == 1)
1572 physical_tag = _getInt32();
1573 if (is_print_level1)
1574 info() << "[Entities] point tag=" << tag << " pos=" << xyz << " phys_tag=" << physical_tag;
1575
1576 tag_info[0] = tag;
1577 tag_info[1] = physical_tag;
1578 }
1579 m_parallel_mng->broadcast(tag_info.view(), m_master_io_rank);
1580 m_mesh_info->entities_nodes_list.add(MshEntitiesNodes(tag_info[0], tag_info[1]));
1581 if (!m_is_binary)
1582 _goToNextLine();
1583 }
1584
1585 // Reading entities of dimensions 1, 2, and 3.
1586 for (Int32 i_dim = 1; i_dim <= 3; ++i_dim)
1587 for (Int32 i = 0; i < nb_dim_item[i_dim]; ++i)
1588 _readOneEntity(i_dim, i);
1589
1590 // In binary, we must go to the beginning of the next line.
1591 if (m_is_binary)
1592 _goToNextLine();
1593 _readAndCheck("$EndEntities");
1594}
1595
1596/*---------------------------------------------------------------------------*/
1597/*---------------------------------------------------------------------------*/
1598
1599void MshParallelMeshReader::
1600_readOneEntity(Int32 entity_dim, Int32 entity_index_in_dim)
1601{
1602 IosFile* ios_file = m_ios_file.get();
1603 const bool is_print_level1 = m_verbosity_level > 0;
1604 const bool is_print_level2 = m_verbosity_level > 1;
1605
1606 // Info for the tags
1607 // [0] entity_dim
1608 // [1] tag
1609 // [2] nb_physical_tag
1610 // [2+1] physical_tag1
1611 // [2+N] physical_tagN
1612 // ...
1613 // [3+nb_physical_tag] nb_boundary
1614 // [3+nb_physical_tag+1] boundary_tag1
1615 // [3+nb_physical_tag+n] boundary_tagN
1616 // ...
1617 if (is_print_level1)
1618 info() << "[Entities] Reading entity dim=" << entity_dim << " index_in_dim=" << entity_index_in_dim;
1619 SmallArray<Int64, 128> dim_and_tag_info;
1620 dim_and_tag_info.add(entity_dim);
1621 if (ios_file) {
1622 Int32 tag = _getInt32();
1623 dim_and_tag_info.add(tag);
1624 Real3 min_pos = _getReal3();
1625 Real3 max_pos = _getReal3();
1626 Int64 nb_physical_tag = _getInt64();
1627 dim_and_tag_info.add(nb_physical_tag);
1628 for (Int32 z = 0; z < nb_physical_tag; ++z) {
1629 Int32 physical_tag = _getInt32();
1630 dim_and_tag_info.add(physical_tag);
1631 if (is_print_level2)
1632 info(4) << "[Entities] z=" << z << " physical_tag=" << physical_tag;
1633 }
1634 // TODO: Read the numBounding information...
1635 Int64 nb_bounding_group = _getInt64();
1636 dim_and_tag_info.add(nb_bounding_group);
1637 for (Int64 z = 0; z < nb_bounding_group; ++z) {
1638 Int32 boundary_tag = _getInt32();
1639 if (is_print_level2)
1640 info(4) << "[Entities] z=" << z << " boundary_tag=" << boundary_tag;
1641 }
1642 if (is_print_level2)
1643 info(4) << "[Entities] dim=" << entity_dim << " tag=" << tag
1644 << " min_pos=" << min_pos << " max_pos=" << max_pos
1645 << " nb_phys_tag=" << nb_physical_tag
1646 << " nb_bounding=" << nb_bounding_group;
1647 }
1648 Int32 info_size = dim_and_tag_info.size();
1649 m_parallel_mng->broadcast(ArrayView<Int32>(1, &info_size), m_master_io_rank);
1650 dim_and_tag_info.resize(info_size);
1651 m_parallel_mng->broadcast(dim_and_tag_info.view(), m_master_io_rank);
1652
1653 {
1654 Int32 dim = CheckedConvert::toInt32(dim_and_tag_info[0]);
1655 Int64 tag = dim_and_tag_info[1];
1656 Int64 nb_physical_tag = dim_and_tag_info[2];
1657 for (Int32 z = 0; z < nb_physical_tag; ++z) {
1658 Int64 physical_tag = dim_and_tag_info[3 + z];
1659 if (is_print_level2)
1660 info(4) << "[Entities] adding info dim=" << entity_dim << " tag=" << tag
1661 << " physical_tag=" << physical_tag;
1662 m_mesh_info->entities_with_nodes_list[dim - 1].add(MshEntitiesWithNodes(dim, tag, physical_tag));
1663 }
1664 }
1665
1666 if (!m_is_binary)
1667 _goToNextLine();
1668}
1669
1670/*---------------------------------------------------------------------------*/
1671/*---------------------------------------------------------------------------*/
1672
1692{
1693 Int64 nb_link = _getInt64AndBroadcast();
1694 info() << "[Periodic] nb_link=" << nb_link;
1695 const bool is_print_level1 = m_verbosity_level > 0;
1696 const bool is_print_level2 = m_verbosity_level > 1;
1697 // TODO: for now, all ranks keep the
1698 // data because we assume there aren't many.
1699 // In the future, this information will also need to be distributed.
1700 MshPeriodicInfo& periodic_info = m_mesh_info->m_periodic_info;
1701 periodic_info.m_periodic_list.resize(nb_link);
1702 for (Int64 ilink = 0; ilink < nb_link; ++ilink) {
1703 MshPeriodicOneInfo& one_info = periodic_info.m_periodic_list[ilink];
1704 FixedArray<Int32, 3> entity_info;
1705 _getInt32ArrayAndBroadcast(entity_info.view());
1706
1707 if (is_print_level1)
1708 info() << "[Periodic] link_index=" << ilink << " dim=" << entity_info[0] << " entity_tag=" << entity_info[1]
1709 << " entity_tag_master=" << entity_info[2];
1710 one_info.m_entity_dim = entity_info[0];
1711 one_info.m_entity_tag = entity_info[1];
1712 one_info.m_entity_tag_master = entity_info[2];
1713
1714 Int64 num_affine = _getInt64AndBroadcast();
1715 if (is_print_level2)
1716 info() << "[Periodic] num_affine=" << num_affine;
1717 one_info.m_affine_values.resize(num_affine);
1718 _getDoubleArrayAndBroadcast(one_info.m_affine_values);
1719 one_info.m_nb_corresponding_node = CheckedConvert::toInt32(_getInt64AndBroadcast());
1720 if (is_print_level1)
1721 info() << "[Periodic] nb_corresponding_node=" << one_info.m_nb_corresponding_node;
1722 one_info.m_corresponding_nodes.resize(one_info.m_nb_corresponding_node * 2);
1723 _getInt64ArrayAndBroadcast(one_info.m_corresponding_nodes);
1724 if (is_print_level2)
1725 info(4) << "[Periodic] corresponding_nodes=" << one_info.m_corresponding_nodes;
1726 }
1727
1728 _goToNextLine();
1729
1731 if (s != "$EndPeriodic")
1732 ARCANE_FATAL("found '{0}' and expected '$EndPeriodic'", s);
1733}
1734
1735/*---------------------------------------------------------------------------*/
1736/*---------------------------------------------------------------------------*/
1737
1742_readAndCheck(const String& expected_value)
1743{
1744 String s;
1745 if (m_is_binary) {
1746 constexpr Int32 MAX_SIZE = 128;
1748 Span<const Byte> expected_bytes = expected_value.bytes();
1749 Int32 read_size = CheckedConvert::toInt32(expected_bytes.size());
1750 SmallSpan<Byte> bytes_to_read = buf_bytes.span().subSpan(0, read_size);
1751 if (read_size >= MAX_SIZE)
1752 ARCANE_FATAL("local buffer is too small (size={0} max={1})", read_size, MAX_SIZE);
1753 IosFile* f = m_ios_file.get();
1754 if (f) {
1755 f->binaryRead(bytes_to_read);
1756 s = String(bytes_to_read);
1757 info() << "S=" << s;
1758 if (m_is_parallel) {
1759 m_parallel_mng->broadcastString(s, m_master_io_rank);
1760 }
1761 }
1762 _goToNextLine();
1763 }
1764 else {
1766 }
1767 if (s != expected_value)
1768 ARCANE_FATAL("found '{0}' and expected '{1}'", s, expected_value);
1769}
1770
1771/*---------------------------------------------------------------------------*/
1772/*---------------------------------------------------------------------------*/
1775void MshParallelMeshReader::
1776_readMeshFromFile()
1777{
1778 IosFile* ios_file = m_ios_file.get();
1779 IMesh* mesh = m_mesh;
1780 info() << "Reading 'msh' file in parallel";
1781
1782 _initTypes();
1783
1784 const int MSH_BINARY_TYPE = 1;
1785
1786 if (ios_file) {
1787 Real version = ios_file->getReal();
1788 if (version != 4.1)
1789 ARCANE_THROW(IOException, "Wrong msh file version '{0}'. Only version '4.1' is supported in parallel", version);
1790 Integer file_type = ios_file->getInteger(); // is an integer equal to 0 in the ASCII file format, equal to 1 for the binary format
1791 if (file_type == MSH_BINARY_TYPE)
1792 m_is_binary = true;
1793 info() << "IsBinary?=" << m_is_binary;
1794 Int32 data_size = ios_file->getInteger(); // is an integer equal to the size of the floating point numbers used in the file
1795 ARCANE_UNUSED(data_size);
1796 if (data_size != 8)
1797 ARCANE_FATAL("Only 'size_t' of size '8' is allowed (current size is '{0}')", data_size);
1798 // In binary, there is an integer to read that equals 1 and allows us to know if we are in big/little endian.
1799 if (m_is_binary) {
1800 // We must read until the end of the line for binary.
1801 _goToNextLine();
1802 Int32 int_value_one = 0;
1803 ios_file->binaryRead(SmallSpan<Int32>(&int_value_one, 1));
1804 if (int_value_one != 1)
1805 ARCANE_FATAL("Bad endianess for file. Read int as value '{0}' (expected=1)", int_value_one);
1806 }
1807
1808 _goToNextLine();
1809
1810 // $EndMeshFormat
1811 if (!ios_file->lookForString("$EndMeshFormat"))
1812 ARCANE_THROW(IOException, "$EndMeshFormat not found");
1813 }
1814
1815 // TODO: The different sections ($Nodes, $Entities, ...) can
1816 // be in any order (except $Nodes which must be before $Elements)
1817 // Create a method that handles this.
1818
1819 String next_line = _getNextLineAndBroadcast();
1820 // Group names
1821 if (next_line == "$PhysicalNames") {
1822 _readPhysicalNames();
1823 next_line = _getNextLineAndBroadcast();
1824 }
1825
1826 // After the format, we may have entities but this is optional
1827 // If they are present, we read the file until the end of this section.
1828 if (next_line == "$Entities") {
1829 _readEntities();
1830 next_line = _getNextLineAndBroadcast();
1831 }
1832 // $Nodes
1833 if (next_line != "$Nodes")
1834 ARCANE_THROW(IOException, "Unexpected string '{0}'. Valid values are '$Nodes'", next_line);
1835
1836 // Fetch nodes number and the coordinates
1838
1839 // $EndNodes
1840 if (ios_file && !ios_file->lookForString("$EndNodes"))
1841 ARCANE_THROW(IOException, "$EndNodes not found");
1842
1843 // $Elements
1844 if (ios_file && !ios_file->lookForString("$Elements"))
1845 ARCANE_THROW(IOException, "$Elements not found");
1846
1847 Int32 mesh_dimension = _readElementsFromFile();
1848
1849 // $EndElements
1850 if (ios_file && !ios_file->lookForString("$EndElements"))
1851 ARCANE_THROW(IOException, "$EndElements not found");
1852
1853 info() << "Computed mesh dimension = " << mesh_dimension;
1854
1855 IPrimaryMesh* pmesh = mesh->toPrimaryMesh();
1856 pmesh->setDimension(mesh_dimension);
1857
1858 info() << "NextLine=" << next_line;
1859
1860 bool is_end = _getIsEndOfFileAndBroadcast();
1861 if (!is_end) {
1862 next_line = _getNextLineAndBroadcast();
1863 // $Periodic
1864 if (next_line == "$Periodic") {
1865 _readPeriodic();
1866 }
1867 }
1868
1869 _allocateCells();
1871 _allocateGroups();
1872}
1873
1874/*---------------------------------------------------------------------------*/
1875/*---------------------------------------------------------------------------*/
1876
1877void MshParallelMeshReader::
1878_initTypes()
1879{
1880 // Initializes the types.
1881 // This must be done at the beginning of the reading and no more added afterward.
1882 // Connectivity in GMSH is described here:
1883 // https://gmsh.info/doc/texinfo/gmsh.html#Node-ordering
1884 _addMshTypeInfo(MSH_PNT, ITI_Vertex);
1885 _addMshTypeInfo(MSH_LIN_2, ITI_Line2);
1886 _addMshTypeInfo(MSH_LIN_3, ITI_Line3);
1887 _addMshTypeInfo(MSH_TRI_3, ITI_Triangle3);
1888 _addMshTypeInfo(MSH_QUA_4, ITI_Quad4);
1889 _addMshTypeInfo(MSH_QUA_8, ITI_Quad8);
1890 _addMshTypeInfo(MSH_QUA_9, ITI_Quad9);
1891 _addMshTypeInfo(MSH_TET_4, ITI_Tetraedron4);
1892 _addMshTypeInfo(MSH_HEX_8, ITI_Hexaedron8);
1893 _addMshTypeInfo(MSH_PRI_6, ITI_Pentaedron6);
1894 _addMshTypeInfo(MSH_PRI_15, ITI_Pentaedron15);
1895 _addMshTypeInfo(MSH_PYR_5, ITI_Pyramid5);
1896 _addMshTypeInfo(MSH_PYR_13, ITI_Pyramid13);
1897 _addMshTypeInfo(MSH_TRI_6, ITI_Triangle6);
1898 _addMshTypeInfo(MSH_TRI_10, ITI_Triangle10);
1899 {
1900 FixedArray<Int16, 10> x({ 0, 1, 2, 3, 4, 5, 6, 7, 9, 8 });
1901 _addMshTypeInfo(MSH_TET_10, ITI_Tetraedron10, x.view());
1902 }
1903 {
1904 FixedArray<Int16, 20> x({ 0, 1, 2, 3, 4, 5, 6, 7,
1905 8, 11, 13, 9, 16, 18, 19, 17, 10, 12, 14, 15 });
1906 _addMshTypeInfo(MSH_HEX_20, ITI_Hexaedron20, x.view());
1907 }
1908 {
1909 FixedArray<Int16, 27> x({ 0, 1, 2, 3, 4, 5, 6, 7,
1910 8, 11, 13, 9, 16, 18, 19, 17, 10, 12, 14, 15,
1911 22, 23, 21, 24, 20, 25, 26 });
1912 _addMshTypeInfo(MSH_HEX_27, ITI_Hexaedron27, x.view());
1913 }
1914}
1915
1916/*---------------------------------------------------------------------------*/
1917/*---------------------------------------------------------------------------*/
1918
1919void MshParallelMeshReader::
1920_addMshTypeInfo(Int32 msh_type, ItemTypeId arcane_type, ConstArrayView<Int16> reorder_infos)
1921{
1922 //info() << "ADD_TYPE msh_type=" << msh_type << " Arcane=" << arcane_type;
1923 if (msh_type < 0)
1924 ARCANE_FATAL("Bad MSH type {0}", msh_type);
1925 if (m_msh_to_arcane_type_infos.size() <= msh_type)
1926 m_msh_to_arcane_type_infos.resize(msh_type + 1);
1927 ItemTypeMng* item_type_mng = m_mesh->itemTypeMng();
1928 ItemTypeInfo* iti = item_type_mng->typeFromId(arcane_type);
1929 m_msh_to_arcane_type_infos[msh_type] = MshToArcaneTypeInfo(msh_type, iti, reorder_infos);
1930}
1931
1932/*---------------------------------------------------------------------------*/
1933/*---------------------------------------------------------------------------*/
1934
1935const MshParallelMeshReader::MshToArcaneTypeInfo& MshParallelMeshReader::
1936mshToArcaneTypeInfo(Int32 msh_type) const
1937{
1938 if (msh_type < m_msh_to_arcane_type_infos.size()) {
1939 const MshToArcaneTypeInfo& tx = m_msh_to_arcane_type_infos[msh_type];
1940 if (tx.m_arcane_type_info)
1941 return tx;
1942 }
1943 ARCANE_THROW(NotSupportedException, "MSH type '{0}' is not supported in Arcane", msh_type);
1944}
1945
1946/*---------------------------------------------------------------------------*/
1947/*---------------------------------------------------------------------------*/
1948
1953readMeshFromMshFile(IMesh* mesh, const String& filename, bool use_internal_partition)
1954{
1955 m_mesh_info = impl::MshMeshGenerationInfo::getReference(mesh, true);
1956 info() << "Trying to read in parallel 'msh' file '" << filename << "'"
1957 << " use_internal_partition=" << use_internal_partition;
1958 m_mesh = mesh;
1959 IParallelMng* pm = mesh->parallelMng();
1960 // Reads sequentially if the files are already partitioned
1961 if (!use_internal_partition)
1962 pm = pm->sequentialParallelMng();
1963 m_parallel_mng = pm;
1964 const Int32 nb_rank = pm->commSize();
1965
1966 // Determines the ranks that will keep the data.
1967 // It is not mandatory that all ranks participate
1968 // in keeping the data. Ideally, with a
1969 // large number of ranks, one in 2 or 4 would participate.
1970 // However, this then generates empty partitions (for
1971 // the ranks that do not participate) and this can
1972 // crash certain partitioners (like ParMetis)
1973 // when there are empty partitions. This problem should first
1974 // be corrected.
1975 m_nb_part = nb_rank;
1976 m_parts_rank.resize(m_nb_part);
1977 for (Int32 i = 0; i < m_nb_part; ++i) {
1978 m_parts_rank[i] = i % nb_rank;
1979 }
1980
1981 bool is_master_io = pm->isMasterIO();
1982 Int32 master_io_rank = pm->masterIORank();
1983 m_is_parallel = pm->isParallel();
1984 m_master_io_rank = master_io_rank;
1985 FixedArray<Int32, 1> file_readable;
1986 // Only the master rank will read the file.
1987 // We first check if it is readable
1988 if (is_master_io) {
1989 bool is_readable = platform::isFileReadable(filename);
1990 info() << "Is file readable ?=" << is_readable;
1991 file_readable[0] = is_readable ? 1 : 0;
1992 if (!is_readable)
1993 error() << "Unable to read file '" << filename << "'";
1994 }
1995 pm->broadcast(file_readable.view(), master_io_rank);
1996 if (file_readable[0] == 0) {
1997 return IMeshReader::RTError;
1998 }
1999
2000 std::ifstream ifile;
2001 Ref<IosFile> ios_file;
2002 if (is_master_io) {
2003 // Always open the file in binary because we
2004 // do not know in advance if it is in text or binary mode.
2005 ifile.open(filename.localstr(), ios::binary);
2006 ios_file = makeRef<IosFile>(new IosFile(&ifile));
2007 }
2008 m_ios_file = ios_file;
2009 String mesh_format_str = _getNextLineAndBroadcast();
2010 if (IosFile::isEqualString(mesh_format_str, "$MeshFormat")) {
2011 _readMeshFromFile();
2012 if (!use_internal_partition) {
2013 info() << "Synchronize groups and variables";
2014 mesh->synchronizeGroupsAndVariables();
2015 }
2016 return IMeshReader::RTOk;
2017 }
2018
2019 info() << "The file does not begin with '$MeshFormat' returning RTError";
2020 return IMeshReader::RTError;
2021}
2022
2023/*---------------------------------------------------------------------------*/
2024/*---------------------------------------------------------------------------*/
2025
2026extern "C++" Ref<IMshMeshReader>
2027createMshParallelMeshReader(ITraceMng* tm)
2028{
2030}
2031
2032/*---------------------------------------------------------------------------*/
2033/*---------------------------------------------------------------------------*/
2034
2035} // namespace Arcane
2036
2037/*---------------------------------------------------------------------------*/
2038/*---------------------------------------------------------------------------*/
#define ARCANE_CHECK_POINTER(ptr)
Macro returning the pointer ptr if it is not null or throwing an exception if it is null.
#define ARCANE_THROW(exception_class,...)
Macro for throwing an exception with formatting.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Utility functions for the mesh.
Integer size() const
Number of elements in the vector.
Modifiable view of an array of type T.
void addRange(ConstReferenceType val, Int64 n)
Adds n elements of value val to the end of the array.
void resize(Int64 s)
Changes the number of elements in the array to s.
void add(ConstReferenceType val)
Adds element val to the end of the array.
void reserve(Int64 new_capacity)
Reserves memory for new_capacity elements.
ArrayView< T > view() const
Mutable view of this array.
Constant view of an array of type T.
constexpr Integer size() const noexcept
Number of elements in the array.
static std::optional< Int32 > tryParseFromEnvironment(StringView s, bool throw_if_invalid)
Template class for converting a type.
constexpr __host__ __device__ ArrayView< T > view()
Modifiable view of the array.
constexpr __host__ __device__ SmallSpan< T, NbElement > span()
Modifiable view of the array.
Information about the floating-point type.
Definition Limits.h:49
Interface of an entity family.
Definition IItemFamily.h:83
virtual ItemGroup findGroup(const String &name) const =0
Searches for a group.
virtual String name() const =0
Family name.
virtual void itemsUniqueIdToLocalId(Int32ArrayView local_ids, Int64ConstArrayView unique_ids, bool do_fatal=true) const =0
Converts an array of unique numbers to local numbers.
virtual Integer dimension()=0
Mesh dimension (1D, 2D, or 3D).
eReturnType
Types of return codes for a read or write operation.
Definition IMeshReader.h:38
@ RTError
Error during the operation.
Definition IMeshReader.h:40
@ RTOk
Operation successfully performed.
Definition IMeshReader.h:39
virtual const MeshKind meshKind() const =0
Mesh characteristics.
virtual IPrimaryMesh * toPrimaryMesh()=0
Returns the instance in the form of an IPrimaryMesh.
Exception when an input/output error is detected.
Definition IOException.h:34
Interface of the parallelism manager for a subdomain.
virtual Int32 commRank() const =0
Rank of this instance in the communicator.
virtual IParallelMng * sequentialParallelMng()=0
Returns a sequential parallelism manager.
virtual void recv(ArrayView< char > values, Int32 rank)=0
virtual bool isMasterIO() const =0
true if the instance is a master I/O manager.
virtual Int32 commSize() const =0
Number of instances in the communicator.
virtual Integer masterIORank() const =0
Rank of the instance managing I/O (for which isMasterIO() is true).
virtual bool isParallel() const =0
Returns true if the execution is parallel.
virtual char reduce(eReduceType rt, char v)=0
Performs a reduction of type rt on the real v and returns the value.
virtual void endAllocate()=0
Indicates the end of cell allocation.
virtual void allocateCells(Integer nb_cell, Int64ConstArrayView cells_infos, bool one_alloc=true)=0
Allocation of a mesh.
virtual void setDimension(Integer dim)=0
Positions the mesh dimension (1D, 2D, or 3D).
File Read/Write Routines.
Definition IosFile.h:33
Mesh entity group.
Definition ItemGroup.h:51
const String & name() const
Group name.
Definition ItemGroup.h:81
void addItems(Int32ConstArrayView items_local_id, bool check_if_present=true)
Adds entities.
Definition ItemGroup.cc:439
Type of an entity (Item).
Definition ItemTypeId.h:33
Info on a mesh entity type.
Integer nbLocalNode() const
Number of nodes of the entity.
String typeName() const
Type name.
ItemTypeId itemTypeId() const
Type number.
Mesh entity type manager.
Definition ItemTypeMng.h:66
ItemTypeInfo * typeFromId(Integer id) const
Type corresponding to the number id.
bool isNonManifold() const
True if the mesh structure is eMeshCellDimensionKind::NonManifold.
Definition MeshKind.h:120
Information to create entities of a certain kind.
UniqueArray< Int64 > nodes_unique_id
UniqueId() of the nodes of my part.
std::unordered_map< Int64, Int32 > nodes_rank_map
Associative array (uniqueId(),rank) to which the node will belong.
UniqueArray< Real3 > nodes_coordinates
Coordinates of the nodes of my part.
Mapping information between MSH type and Arcane type.
Mesh file reader in msh format.
bool _getIsEndOfFileAndBroadcast()
Returns true if we are at the end of the file.
void _readPeriodic()
Reading periodic information.
Integer _readElementsFromFile()
Reading of elements (cells, faces, ...).
void _addCellOrNodeGroup(ArrayView< Int64 > block_uids, Int32 block_index, const String &group_name, IItemFamily *family, bool filter_invalid)
Adds cells or nodes to the group group_name.
void _readAndCheck(const String &expected_value)
Tries to read the value value.
UniqueArray< Int32 > m_parts_rank
List of ranks participating in data conservation.
Int32 m_nb_part
Number of partitions for reading nodes and blocks.
UniqueArray< MshToArcaneTypeInfo > m_msh_to_arcane_type_infos
Conversion information between MSH and Arcane types for entities.
eReturnType readMeshFromMshFile(IMesh *mesh, const String &filename, bool use_internal_partition) override
Reads the mesh contained in the file filename and constructs it in mesh.
void _readNodesFromFile()
Reads mesh nodes.
void _setNodesCoordinates()
Positions the node coordinates.
bool m_is_binary
True if the format is binary.
void _addFaceGroup(const MshElementBlock &block, const String &group_name)
Adds faces to the group group_name.
void _readOneElementBlock(MshElementBlock &block)
Reads an 'Element' type block.
String _getNextLineAndBroadcast()
Reads the next line value and broadcasts it to other ranks.
View of node information.
Utility class to reorder the nodes of an entity.
Class managing a 3-dimensional real vector.
Definition Real3.h:132
InstanceType * get() const
Associated instance or nullptr if none.
Reference to an instance.
1D data array with pre-allocated stack buffer.
View of an array of elements of type T.
Definition Span.h:805
constexpr __host__ __device__ SizeType size() const noexcept
Returns the size of the array.
Definition Span.h:327
View of an array of elements of type T.
Definition Span.h:635
const char * localstr() const
Returns the conversion of the instance into UTF-8 encoding.
Definition String.cc:229
Span< const Byte > bytes() const
Returns the conversion of the instance into UTF-8 encoding.
Definition String.cc:293
static String collapseWhiteSpace(const String &rhs)
Performs whitespace character normalization.
Definition String.cc:454
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
TraceMessage info() const
Flow for an information message.
TraceMessage error() const
Flow for an error message.
1D data vector with value semantics (STL style).
UniqueArray< double > m_affine_values
List of affine values.
UniqueArray< Int64 > m_corresponding_nodes
List of pairs (slave node uniqueId, master node unique()).
Brief information about a mesh derived from the 'msh' format.
void resize(Int64 s)
Changes the number of elements in the array to s.
__host__ __device__ Real2 min(Real2 a, Real2 b)
Returns the minimum of two Real2.
Definition MathUtils.h:346
T max(const T &a, const T &b, const T &c)
Returns the maximum of three elements.
Definition MathUtils.h:407
ItemGroupT< Face > FaceGroup
Group of faces.
Definition ItemTypes.h:179
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Coordinate type quantity at node.
@ ReduceMin
Minimum of values.
@ ReduceMax
Maximum of values.
constexpr __host__ __device__ bool isNearlyEqual(const _Type &a, const _Type &b)
Tests if two values are approximately equal. For integer types, this function is equivalent to IsEqua...
Definition Numeric.h:219
bool isFileReadable(const String &file_name)
Checks if the file file_name is accessible and readable.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
ConstArrayView< Int64 > Int64ConstArrayView
C equivalent of a 1D array of 64-bit integers.
Definition UtilsTypes.h:480
std::int16_t Int16
Signed integer type of 16 bits.
double Real
Type representing a real number.
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Creates a reference on a pointer.
std::int32_t Int32
Signed integer type of 32 bits.
Info of a block for $Elements for version 4.
ItemTypeId item_type
Arcane type of the entity.
UniqueArray< Int64 > connectivities
< List of uniqueId() of the block
Int64 nb_entity
Number of entities in the block.
Int32 item_nb_node
Number of nodes of the entity.
SmallSpan< const Int16 > reorder_infos
If not empty, contains the indirections for renumbering.
Int32 entity_dim
Dimension of the associated entity.
Int64 index_in_allocation_info
Index in MshMeshAllocateInfo of the nodes of this block.
Int32 nb_node
Number of entities in the block.
Real x
first component of the triplet
Definition Real3.h:35