47
47
* l'option '-save-all' pour sauver un fichier '.msh' à partir d'un '.geo'
48
48
*
49
49
* TODO:
50
- * - lire les tags des noeuds(uniqueId())
51
50
* - supporter les partitions
52
51
* - pouvoir utiliser la bibliothèque 'gmsh' directement.
53
- * - améliorer la lecture parallèle en évitant que tous les sous-domaines
54
- * lisent le fichier (même si seul le sous-domaine 0 alloue les entités)
55
52
*/
56
53
57
54
/* ---------------------------------------------------------------------------*/
@@ -209,6 +206,10 @@ class MshParallelMeshReader
209
206
UniqueArray<Real3> nodes_coordinates;
210
207
// ! UniqueId() des noeuds de ma partie.
211
208
UniqueArray<Int64> nodes_unique_id;
209
+ // ! Rang auquel le noeud appartiendra
210
+ std::unordered_map<Int64, Int32> nodes_rank_map;
211
+ Real3 m_node_min_bounding_box;
212
+ Real3 m_node_max_bounding_box;
212
213
MeshPhysicalNameList physical_name_list;
213
214
UniqueArray<MeshV4EntitiesNodes> entities_nodes_list;
214
215
UniqueArray<MeshV4EntitiesWithNodes> entities_with_nodes_list[3 ];
@@ -238,7 +239,7 @@ class MshParallelMeshReader
238
239
239
240
private:
240
241
241
- eReturnType _readNodesFromFileAscii (IosFile* ios_file, MeshInfo& mesh_info);
242
+ void _readNodesFromFileAscii (MeshInfo& mesh_info);
242
243
Integer _readElementsFromFileAscii (IosFile* ios_file, MeshInfo& mesh_info);
243
244
eReturnType _readMeshFromNewMshFile (IosFile* iso_file);
244
245
void _setNodesCoordinates (MeshInfo& mesh_info);
@@ -258,6 +259,8 @@ class MshParallelMeshReader
258
259
Int32 _getIntegerAndBroadcast ();
259
260
void _getInt64ArrayAndBroadcast (ArrayView<Int64> values);
260
261
void _readOneElementBlock (MeshV4ElementsBlock& block);
262
+ void _computeNodesPartition (MeshInfo& mesh_info);
263
+ void _computeOwnCells (MeshInfo& mesh_info, MeshV4ElementsBlock& block);
261
264
};
262
265
263
266
/* ---------------------------------------------------------------------------*/
@@ -400,6 +403,63 @@ _switchMshType(Int64 mshElemType, Int32& nNodes)
400
403
return IT_NullType;
401
404
}
402
405
406
+ /* ---------------------------------------------------------------------------*/
407
+ /* ---------------------------------------------------------------------------*/
408
+
409
+ void MshParallelMeshReader::
410
+ _computeNodesPartition (MeshInfo& mesh_info)
411
+ {
412
+ // Détermine la bounding box de la maille
413
+ Real max_value = FloatInfo<Real>::maxValue ();
414
+ Real min_value = -max_value;
415
+ Real3 min_box (max_value, max_value, max_value);
416
+ Real3 max_box (min_value, min_value, min_value);
417
+ const Int64 nb_node = mesh_info.nodes_coordinates .largeSize ();
418
+ for (Real3 pos : mesh_info.nodes_coordinates ) {
419
+ min_box = math::min (min_box, pos);
420
+ max_box = math::max (max_box, pos);
421
+ }
422
+ mesh_info.m_node_min_bounding_box = min_box;
423
+ mesh_info.m_node_max_bounding_box = max_box;
424
+
425
+ // ! Rank auquel appartient les noeuds de ma partie.
426
+ UniqueArray<Int32> nodes_part (nb_node, 0 );
427
+
428
+ // Pour la partition, on ne prend en compte que la coordonnée X.
429
+ // On est sur qu'elle est valable pour toutes les dimensions du maillage.
430
+ // On partitionne avec des intervalles de même longueur.
431
+ // NOTE: Cela fonctionne bien si l'ensemble des noeuds est bien réparti.
432
+ // Si ce n'est pas le cas on pourrait utiliser une bisection en coupant
433
+ // à chaque fois sur la moyenne.
434
+ Real min_x = min_box.x ;
435
+ Real max_x = max_box.x ;
436
+ IParallelMng* pm = m_parallel_mng;
437
+ Real global_min_x = pm->reduce (Parallel::ReduceMin, min_x);
438
+ Real global_max_x = pm->reduce (Parallel::ReduceMax, max_x);
439
+ info () << " MIN_MAX_X=" << global_min_x << " " << global_max_x;
440
+
441
+ Real diff_v = (global_max_x - global_min_x) / static_cast <Real>(m_nb_part);
442
+ // Ne devrait pas arriver mais c'est nécessaire pour éviter d'éventuelles
443
+ // divisions par zéro.
444
+ if (!math::isNearlyEqual (global_min_x, global_max_x)) {
445
+ for (Int64 i = 0 ; i < nb_node; ++i) {
446
+ Int32 part = static_cast <Int32>((mesh_info.nodes_coordinates [i].x - global_min_x) / diff_v);
447
+ part = std::clamp (part, 0 , m_nb_part - 1 );
448
+ nodes_part[i] = part;
449
+ }
450
+ }
451
+ UniqueArray<Int32> nb_node_per_rank (m_nb_part, 0 );
452
+ // Construit la table de hashage des rangs
453
+ for (Int64 i = 0 ; i < nb_node; ++i) {
454
+ Int32 rank = m_parts_rank[nodes_part[i]];
455
+ Int64 uid = mesh_info.nodes_unique_id [i];
456
+ ++nb_node_per_rank[rank];
457
+ mesh_info.nodes_rank_map .insert (std::make_pair (uid, rank));
458
+ }
459
+ pm->reduce (Parallel::ReduceSum, nb_node_per_rank);
460
+ info () << " NB_NODE_PER_RANK=" << nb_node_per_rank;
461
+ }
462
+
403
463
/* ---------------------------------------------------------------------------*/
404
464
/* ---------------------------------------------------------------------------*/
405
465
/* !
@@ -426,9 +486,10 @@ _switchMshType(Int64 mshElemType, Int32& nNodes)
426
486
*$EndNodes
427
487
* \endcode
428
488
*/
429
- IMeshReader::eReturnType MshParallelMeshReader::
430
- _readNodesFromFileAscii (IosFile* ios_file, MeshInfo& mesh_info)
489
+ void MshParallelMeshReader::
490
+ _readNodesFromFileAscii (MeshInfo& mesh_info)
431
491
{
492
+ IosFile* ios_file = m_ios_file.get ();
432
493
IParallelMng* pm = m_parallel_mng;
433
494
const Int32 my_rank = pm->commRank ();
434
495
@@ -454,6 +515,7 @@ _readNodesFromFileAscii(IosFile* ios_file, MeshInfo& mesh_info)
454
515
455
516
UniqueArray<Int64> nodes_uids;
456
517
UniqueArray<Real3> nodes_coordinates;
518
+
457
519
for (Integer i_entity = 0 ; i_entity < nb_entity; ++i_entity) {
458
520
459
521
FixedArray<Int64, 4 > entity_infos;
@@ -551,7 +613,8 @@ _readNodesFromFileAscii(IosFile* ios_file, MeshInfo& mesh_info)
551
613
if (ios_file)
552
614
ios_file->getNextLine (); // Skip current \n\r
553
615
}
554
- return IMeshReader::RTOk;
616
+
617
+ _computeNodesPartition (mesh_info);
555
618
}
556
619
557
620
/* ---------------------------------------------------------------------------*/
@@ -733,28 +796,88 @@ _readElementsFromFileAscii(IosFile* ios_file, MeshInfo& mesh_info)
733
796
ARCANE_THROW (NotSupportedException, " mesh dimension '{0}'. Only 2D or 3D meshes are supported" , mesh_dimension);
734
797
info () << " Computed mesh dimension = " << mesh_dimension;
735
798
736
- // On ne conserve que les blocs de notre dimension pour créér les mailles.
737
- // On divise chaque bloc en N partie (avec N le nombre de rangs MPI) et
738
- // chaque rang ne conserve qu'une partie. Ainsi chaque sous-domaine aura une
739
- // partie du maillage afin de garantir un équilibrage sur le nombre de mailles.
740
799
for (MeshV4ElementsBlock& block : blocks) {
741
- if (block.dimension != mesh_dimension)
742
- continue ;
800
+ if (block.dimension == mesh_dimension)
801
+ _computeOwnCells (mesh_info, block);
802
+ }
743
803
744
- Integer item_type = block.item_type ;
745
- Integer item_nb_node = block.item_nb_node ;
804
+ return mesh_dimension;
805
+ }
806
+
807
+ /* ---------------------------------------------------------------------------*/
808
+ /* ---------------------------------------------------------------------------*/
746
809
747
- const Int64 block_nb_item = block.uids .size ();
748
- for (Int64 i = 0 ; i < block_nb_item; ++i) {
810
+ void MshParallelMeshReader::
811
+ _computeOwnCells (MeshInfo& mesh_info, MeshV4ElementsBlock& block)
812
+ {
813
+ // On ne conserve que les mailles dont le premier noeud appartient à notre rang.
814
+
815
+ IParallelMng* pm = m_parallel_mng;
816
+ const Int32 my_rank = pm->commRank ();
817
+
818
+ const Int32 item_type = block.item_type ;
819
+ const Int32 item_nb_node = block.item_nb_node ;
820
+
821
+ UniqueArray<Int64> connectivities;
822
+ UniqueArray<Int64> uids;
823
+ UniqueArray<Int32> nodes_rank;
824
+
825
+ const Int32 nb_part = m_parts_rank.size ();
826
+ for (Int32 i_part = 0 ; i_part < nb_part; ++i_part) {
827
+ const Int32 dest_rank = m_parts_rank[i_part];
828
+ ArrayView<Int64> connectivities_view;
829
+ ArrayView<Int64> uids_view;
830
+
831
+ // Broadcast la i_part-ème partie des uids et connectivités des mailles
832
+ {
833
+ FixedArray<Int64, 2 > nb_connectivity_and_uid;
834
+ if (my_rank == dest_rank) {
835
+ nb_connectivity_and_uid[0 ] = block.connectivities .size ();
836
+ nb_connectivity_and_uid[1 ] = block.uids .size ();
837
+ connectivities_view = block.connectivities ;
838
+ uids_view = block.uids ;
839
+ }
840
+ pm->broadcast (nb_connectivity_and_uid.view (), dest_rank);
841
+ if (my_rank != dest_rank) {
842
+ connectivities.resize (nb_connectivity_and_uid[0 ]);
843
+ uids.resize (nb_connectivity_and_uid[1 ]);
844
+ connectivities_view = connectivities;
845
+ uids_view = uids;
846
+ }
847
+ pm->broadcast (connectivities_view, dest_rank);
848
+ pm->broadcast (uids_view, dest_rank);
849
+ }
850
+ Int32 nb_item = uids_view.size ();
851
+ nodes_rank.resize (nb_item);
852
+ nodes_rank.fill (-1 );
853
+
854
+ // Parcours les mailles. Chaque maille appartiendra au rang
855
+ // de son premier noeud. Si cette partie correspond à mon rang, alors
856
+ // on conserve la maille.
857
+ for (Int32 i = 0 ; i < nb_item; ++i) {
858
+ Int64 first_node_uid = connectivities_view[i * item_nb_node];
859
+ auto x = mesh_info.nodes_rank_map .find (first_node_uid);
860
+ if (x == mesh_info.nodes_rank_map .end ())
861
+ // Le noeud n'est pas dans ma liste
862
+ continue ;
863
+ Int32 rank = x->second ;
864
+ nodes_rank[i] = rank;
865
+ }
866
+ pm->reduce (Parallel::ReduceMax, nodes_rank);
867
+ for (Int32 i = 0 ; i < nb_item; ++i) {
868
+ const Int32 rank = nodes_rank[i];
869
+ if (rank != my_rank)
870
+ // Le noeud n'est pas dans ma partie
871
+ continue ;
872
+ // Le noeud est chez moi, j'ajoute ma maille à la liste des
873
+ // mailles que je vais créer.
749
874
mesh_info.cells_type .add (item_type);
750
875
mesh_info.cells_nb_node .add (item_nb_node);
751
- mesh_info.cells_uid .add (block. uids [i]);
752
- auto v = block. connectivities .subView (i * item_nb_node, item_nb_node);
876
+ mesh_info.cells_uid .add (uids_view [i]);
877
+ auto v = connectivities_view .subView (i * item_nb_node, item_nb_node);
753
878
mesh_info.cells_connectivity .addRange (v);
754
879
}
755
880
}
756
-
757
- return mesh_dimension;
758
881
}
759
882
760
883
/* ---------------------------------------------------------------------------*/
@@ -842,7 +965,7 @@ _allocateCells(MeshInfo& mesh_info)
842
965
// 1 pour son type,
843
966
// 1 pour chaque noeud
844
967
UniqueArray<Int64> cells_infos;
845
- Integer connectivity_index = 0 ;
968
+ Int32 connectivity_index = 0 ;
846
969
UniqueArray<Real3> local_coords;
847
970
for (Integer i = 0 ; i < nb_elements; ++i) {
848
971
Integer current_cell_nb_node = mesh_info.cells_nb_node [i];
@@ -1305,8 +1428,7 @@ _readMeshFromNewMshFile(IosFile* ios_file)
1305
1428
ARCANE_THROW (IOException, " Unexpected string '{0}'. Valid values are '$Nodes'" , next_line);
1306
1429
1307
1430
// Fetch nodes number and the coordinates
1308
- if (_readNodesFromFileAscii (ios_file, mesh_info) != IMeshReader::RTOk)
1309
- ARCANE_THROW (IOException, " Ascii nodes coords error" );
1431
+ _readNodesFromFileAscii (mesh_info);
1310
1432
1311
1433
if (ios_file) {
1312
1434
// $EndNodes
@@ -1354,7 +1476,15 @@ readMeshFromMshFile(IMesh* mesh, const String& filename)
1354
1476
const Int32 nb_rank = pm->commSize ();
1355
1477
1356
1478
// Détermine les rangs qui vont conserver les données
1357
- m_nb_part = math::min (m_nb_part, nb_rank);
1479
+ m_nb_part = nb_rank;
1480
+ if (nb_rank > 64 )
1481
+ m_nb_part = nb_rank / 2 ;
1482
+ if (nb_rank > 128 )
1483
+ m_nb_part = nb_rank / 4 ;
1484
+ if (nb_rank > 512 )
1485
+ m_nb_part = nb_rank / 8 ;
1486
+ if (nb_rank > 2048 )
1487
+ m_nb_part = nb_rank / 16 ;
1358
1488
m_parts_rank.resize (m_nb_part);
1359
1489
for (Int32 i = 0 ; i < m_nb_part; ++i) {
1360
1490
m_parts_rank[i] = i % nb_rank;
0 commit comments