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