Arcane  v3.14.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
GhostLayerBuilder2.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2024 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/* GhostLayerBuilder2.cc (C) 2000-2024 */
9/* */
10/* Construction des couches fantômes. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/HashTableMap.h"
15#include "arcane/utils/ITraceMng.h"
16#include "arcane/utils/CheckedConvert.h"
17#include "arcane/utils/ValueConvert.h"
18
19#include "arcane/core/parallel/BitonicSortT.H"
20
21#include "arcane/core/IParallelExchanger.h"
22#include "arcane/core/ISerializeMessage.h"
23#include "arcane/core/SerializeBuffer.h"
24#include "arcane/core/ISerializer.h"
25#include "arcane/core/ItemPrinter.h"
26#include "arcane/core/Timer.h"
27#include "arcane/core/IGhostLayerMng.h"
28#include "arcane/core/IItemFamilyPolicyMng.h"
29#include "arcane/core/IItemFamilySerializer.h"
30#include "arcane/core/ParallelMngUtils.h"
31
32#include "arcane/mesh/DynamicMesh.h"
33#include "arcane/mesh/DynamicMeshIncrementalBuilder.h"
34
35#include <algorithm>
36#include <set>
37
38/*---------------------------------------------------------------------------*/
39/*---------------------------------------------------------------------------*/
40
41namespace Arcane::mesh
42{
43
44/*---------------------------------------------------------------------------*/
45/*---------------------------------------------------------------------------*/
50: public TraceAccessor
51{
52 class BoundaryNodeInfo;
55
56 public:
57
60
61 public:
62
65
66 public:
67
68 void addGhostLayers();
69
70 private:
71
72 DynamicMesh* m_mesh = nullptr;
73 DynamicMeshIncrementalBuilder* m_mesh_builder = nullptr;
74 IParallelMng* m_parallel_mng = nullptr;
75 bool m_is_verbose = false;
76 bool m_is_allocate = false;
77 Int32 m_version = -1;
78 bool m_use_optimized_node_layer = true;
79 bool m_use_only_minimal_cell_uid = true;
80
81 private:
82
83 void _printItem(ItemInternal* ii,std::ostream& o);
84 void _markBoundaryItems();
85 void _sendAndReceiveCells(SubDomainItemMap& cells_to_send);
87 void _addGhostLayer(Integer current_layer,Int32ConstArrayView node_layer);
89};
90
91/*---------------------------------------------------------------------------*/
92/*---------------------------------------------------------------------------*/
93
96: TraceAccessor(mesh_builder->mesh()->traceMng())
97, m_mesh(mesh_builder->mesh())
98, m_mesh_builder(mesh_builder)
99, m_parallel_mng(m_mesh->parallelMng())
100, m_is_allocate(is_allocate)
101, m_version(version)
102{
103 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_GHOSTLAYER_USE_OPTIMIZED_LAYER", true)) {
104 Int32 vv = v.value();
105 m_use_optimized_node_layer = (vv == 1 || vv == 3);
106 m_use_only_minimal_cell_uid = (v == 2 || vv == 3);
107 }
108 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_GHOSTLAYER_VERBOSE", true)) {
109 m_is_verbose = (v.value()!=0);
110 }
111}
112
113/*---------------------------------------------------------------------------*/
114/*---------------------------------------------------------------------------*/
115
116void GhostLayerBuilder2::
117_printItem(ItemInternal* ii,std::ostream& o)
118{
119 o << ItemPrinter(ii);
120}
121
122/*---------------------------------------------------------------------------*/
123/*---------------------------------------------------------------------------*/
124
125/*---------------------------------------------------------------------------*/
126/*---------------------------------------------------------------------------*/
136{
137 public:
138
139 using BasicType = Int64;
140 static constexpr Int64 nbBasicTypeSize() { return 3; }
141
142 public:
143
145 {
146 Int32 message_size = messageSize(values);
147 const BoundaryNodeInfo* fsi_base = values.data();
148 auto* ptr = reinterpret_cast<const Int64*>(fsi_base);
150 }
151
152 static ArrayView<BasicType> asBasicBuffer(ArrayView<BoundaryNodeInfo> values)
153 {
154 Int32 message_size = messageSize(values);
155 BoundaryNodeInfo* fsi_base = values.data();
156 auto* ptr = reinterpret_cast<Int64*>(fsi_base);
158 }
159
160 static Int32 messageSize(ConstArrayView<BoundaryNodeInfo> values)
161 {
162 static_assert((sizeof(Int64) * nbBasicTypeSize()) == sizeof(BoundaryNodeInfo));
163 Int64 message_size_i64 = values.size() * nbBasicTypeSize();
165 return message_size;
166 }
167
168 static Int32 nbElement(Int32 message_size)
169 {
170 if ((message_size % nbBasicTypeSize()) != 0)
171 ARCANE_FATAL("Message size '{0}' is not a multiple of basic size '{1}'", message_size, nbBasicTypeSize());
172 Int32 nb_element = message_size / nbBasicTypeSize();
173 return nb_element;
174 }
175
176 public:
177
179 {
180 size_t operator()(const BoundaryNodeInfo& a) const
181 {
182 size_t h1 = std::hash<Int64>{}(a.node_uid);
183 size_t h2 = std::hash<Int64>{}(a.cell_uid);
184 size_t h3 = std::hash<Int32>{}(a.cell_owner);
185 return h1 ^ h2 ^ h3;
186 }
187 };
188 friend bool operator==(const BoundaryNodeInfo& a, const BoundaryNodeInfo& b)
189 {
190 return (a.node_uid == b.node_uid && a.cell_uid == b.cell_uid && a.cell_owner == b.cell_owner);
191 }
192
193 public:
194
195 Int64 node_uid = NULL_ITEM_UNIQUE_ID;
196 Int64 cell_uid = NULL_ITEM_UNIQUE_ID;
197 Int32 cell_owner = -1;
198 Int32 padding = 0;
199};
200
201/*---------------------------------------------------------------------------*/
202/*---------------------------------------------------------------------------*/
207{
208 public:
209 static bool compareLess(const BoundaryNodeInfo& k1,const BoundaryNodeInfo& k2)
210 {
211 Int64 k1_node_uid = k1.node_uid;
212 Int64 k2_node_uid = k2.node_uid;
214 return true;
216 return false;
217
218 Int64 k1_cell_uid = k1.cell_uid;
219 Int64 k2_cell_uid = k2.cell_uid;
221 return true;
223 return false;
224
225 return (k1.cell_owner<k2.cell_owner);
226 }
227
228 static Parallel::Request send(IParallelMng* pm,Int32 rank,ConstArrayView<BoundaryNodeInfo> values)
229 {
230 auto buf_view = BoundaryNodeInfo::asBasicBuffer(values);
231 return pm->send(buf_view, rank, false);
232 }
233
234 static Parallel::Request recv(IParallelMng* pm,Int32 rank,ArrayView<BoundaryNodeInfo> values)
235 {
236 auto buf_view = BoundaryNodeInfo::asBasicBuffer(values);
237 return pm->recv(buf_view, rank, false);
238 }
239
240 static Integer messageSize(ConstArrayView<BoundaryNodeInfo> values)
241 {
242 return BoundaryNodeInfo::messageSize(values);
243 }
244
245 static BoundaryNodeInfo maxValue()
246 {
248 bni.node_uid = INT64_MAX;
249 bni.cell_uid = INT64_MAX;
250 bni.cell_owner = -1;
251 return bni;
252 }
253
254 static bool isValid(const BoundaryNodeInfo& bni)
255 {
256 return bni.node_uid!=INT64_MAX;
257 }
258};
259
260/*---------------------------------------------------------------------------*/
261/*---------------------------------------------------------------------------*/
262
264{
265 public:
266 Integer m_index;
267 Integer m_nb_cell;
268};
269
270/*---------------------------------------------------------------------------*/
271/*---------------------------------------------------------------------------*/
296{
297 IParallelMng* pm = m_parallel_mng;
298 if (!pm->isParallel())
299 return;
300 Integer nb_ghost_layer = m_mesh->ghostLayerMng()->nbGhostLayer();
301 info() << "** GHOST LAYER BUILDER V" << m_version << " with sort (nb_ghost_layer=" << nb_ghost_layer << ")";
302 if (nb_ghost_layer==0)
303 return;
304 const Int32 my_rank = pm->commRank();
305
306 ItemInternalMap& cells_map = m_mesh->cellsMap();
307 ItemInternalMap& nodes_map = m_mesh->nodesMap();
308
309 // Marque les noeuds frontières
311
312 Integer boundary_nodes_uid_count = 0;
313
314 // Vérifie qu'il n'y a pas de mailles fantômes avec la version 3.
315 // Si c'est le cas, affiche un avertissement et indique de passer à la version 4.
316 if (m_version==3){
317 Integer nb_ghost = 0;
318 cells_map.eachItem([&](Item cell) {
319 if (!cell.isOwn())
320 ++nb_ghost;
321 });
322 if (nb_ghost!=0)
323 warning() << "Invalid call to addGhostLayers() with version 3 because mesh "
324 << " already has '" << nb_ghost << "' ghost cells. The computed ghost cells"
325 << " may be wrong. Use version 4 of ghost layer builder if you want to handle this case";
326 }
327
328 // Couche fantôme à laquelle appartient le noeud.
330
331 // Couche fantôme à laquelle appartient la maille.
333
334 if (m_version>=4){
336 nodes_map.eachItem([&](Item node) {
337 if (node_layer[node.localId()] == 1)
339 });
340 }
341 else{
342 // Parcours les nœuds et calcule le nombre de nœuds frontières
343 // et marque la première couche
344 nodes_map.eachItem([&](Item node) {
345 Int32 f = node.itemBase().flags();
346 if (f & ItemFlags::II_Shared){
347 node_layer[node.localId()] = 1;
349 }
350 });
351 }
352
353 info() << "NB BOUNDARY NODE=" << boundary_nodes_uid_count;
354
356 //Integer current_layer = 1;
357 info() << "Processing layer " << current_layer;
358 cells_map.eachItem([&](Cell cell) {
359 // Ne traite pas les mailles qui ne m'appartiennent pas
360 if (m_version>=4 && cell.owner()!=my_rank)
361 return;
362 //Int64 cell_uid = cell->uniqueId();
363 Int32 cell_lid = cell.localId();
364 if (cell_layer[cell_lid]!=(-1))
365 return;
366 bool is_current_layer = false;
367 for( Int32 inode_local_id : cell.nodeIds() ){
369 //info() << "NODE_LAYER lid=" << i_node->localId() << " layer=" << layer;
370 if (layer==current_layer){
371 is_current_layer = true;
372 break;
373 }
374 }
375 if (is_current_layer){
377 //info() << "Current layer celluid=" << cell_uid;
378 // Si non marqué, initialise à la couche courante + 1.
379 for( Int32 inode_local_id : cell.nodeIds() ){
381 if (layer==(-1)){
382 //info() << "Marque node uid=" << i_node->uniqueId();
384 }
385 }
386 }
387 });
388 }
389
390 // Marque les nœuds pour lesquels on n'a pas encore assigné la couche fantôme.
391 // Pour eux, on indique qu'on est sur la couche 'nb_ghost_layer+1'.
392 // Le but est de ne jamais transférer ces noeuds.
393 // NOTE: Ce mécanisme a été ajouté en juillet 2024 pour la version 3.14.
394 // S'il fonctionne bien on pourra ne conserver que cette méthode.
395 if (m_use_optimized_node_layer) {
396 Integer nb_no_layer = 0;
397 nodes_map.eachItem([&](Node node) {
398 Int32 lid = node.localId();
399 Int32 layer = node_layer[lid];
400 if (layer <= 0) {
402 ++nb_no_layer;
403 }
404 });
405 info() << "Mark remaining nodes nb=" << nb_no_layer;
406 }
407
408 for( Integer i=1; i<=nb_ghost_layer; ++i )
409 _addGhostLayer(i,node_layer);
410}
411
412/*---------------------------------------------------------------------------*/
413/*---------------------------------------------------------------------------*/
428{
429 IParallelMng* pm = m_mesh->parallelMng();
430 const Int32 my_rank = pm->commRank();
431 ItemInternalMap& faces_map = m_mesh->facesMap();
432 // TODO: regarder s'il est correcte de modifier ItemFlags::II_SubDomainBoundary
434 // Parcours les faces et marque les nœuds, arêtes et faces frontières
435 faces_map.eachItem([&](Face face) {
436 Int32 nb_own = 0;
437 for( Integer i=0, n=face.nbCell(); i<n; ++i )
438 if (face.cell(i).owner()==my_rank)
439 ++nb_own;
440 if (nb_own==1){
442 //++nb_sub_domain_boundary_face;
443 for( Item inode : face.nodes() ){
444 inode.mutableItemBase().addFlags(shared_and_boundary_flags);
445 node_layer[inode.localId()] = 1;
446 }
447 for( Item iedge : face.edges() )
448 iedge.mutableItemBase().addFlags(shared_and_boundary_flags);
449 }
450 });
451}
452
453/*---------------------------------------------------------------------------*/
454/*---------------------------------------------------------------------------*/
455
456void GhostLayerBuilder2::
457_addGhostLayer(Integer current_layer,Int32ConstArrayView node_layer)
458{
459 info() << "Processing ghost layer " << current_layer;
460
462 //boundary_node_list.reserve(boundary_nodes_uid_count);
463
464 IParallelMng* pm = m_parallel_mng;
465 Int32 my_rank = pm->commRank();
466 Int32 nb_rank = pm->commSize();
467
468 bool is_verbose = m_is_verbose;
469
470 ItemInternalMap& cells_map = m_mesh->cellsMap();
471 ItemInternalMap& nodes_map = m_mesh->nodesMap();
472
474 Int64 nb_added_for_in_layer = 0;
475
476 const Int32 max_local_id = m_mesh->nodeFamily()->maxLocalId();
477
478 // Tableaux contenant pour chaque nœud le uid de la plus petite maille connectée
479 // et le rang associé. Si le uid est A_NULL_UNIQUE_ID il ne faut pas ajouter ce nœud.
480 UniqueArray<Int64> node_cell_uids(max_local_id, NULL_ITEM_UNIQUE_ID);
481
482 const bool do_only_minimal_uid = m_use_only_minimal_cell_uid;
483 // On doit envoyer tous les nœuds dont le numéro de couche est différent de (-1).
484 // NOTE: pour la couche au dessus de 1, il ne faut envoyer qu'une seule valeur.
485 cells_map.eachItem([&](Cell cell) {
486 // Ne traite pas les mailles qui ne m'appartiennent pas
487 if (m_version>=4 && cell.owner()!=my_rank)
488 return;
489 Int64 cell_uid = cell.uniqueId();
490 for( Node node : cell.nodes() ){
491 Int32 node_lid = node.localId();
492 bool do_it = false;
493 if (cell.owner()!=my_rank){
494 do_it = true;
496 }
497 else{
498 Integer layer = node_layer[node_lid];
500 if (do_it)
502 }
503 if (do_it){
504 Int32 node_lid = node.localId();
505 if (do_only_minimal_uid) {
506 Int64 current_uid = node_cell_uids[node_lid];
507 if ((current_uid == NULL_ITEM_UNIQUE_ID) || cell_uid < current_uid) {
508 node_cell_uids[node_lid] = cell_uid;
509 if (is_verbose)
510 info() << "AddNode node_uid=" << node.uniqueId() << " cell=" << cell_uid;
511 }
512 else
513 if (is_verbose)
514 info() << "AddNode node_uid=" << node.uniqueId() << " cell=" << cell_uid << " not done current=" << current_uid;
515 }
516 else {
517 Int64 node_uid = node.uniqueId();
518 BoundaryNodeInfo nci;
519 nci.node_uid = node_uid;
520 nci.cell_uid = cell_uid;
521 nci.cell_owner = my_rank;
522 boundary_node_list.add(nci);
523 if (is_verbose)
524 info() << "AddNode node_uid=" << node.uniqueId() << " cell=" << cell_uid;
525 }
526 }
527 }
528 });
529
530 if (do_only_minimal_uid) {
531 nodes_map.eachItem([&](Node node) {
532 Int32 lid = node.localId();
533 Int64 cell_uid = node_cell_uids[lid];
534 if (cell_uid != NULL_ITEM_UNIQUE_ID) {
535 Int64 node_uid = node.uniqueId();
536 BoundaryNodeInfo nci;
537 nci.node_uid = node_uid;
538 nci.cell_uid = cell_uid;
539 nci.cell_owner = my_rank;
540 boundary_node_list.add(nci);
541 }
542 });
543 }
544
545 info() << "NB BOUNDARY NODE LIST=" << boundary_node_list.size()
546 << " nb_added_for_different_rank=" << nb_added_for_different_rank
547 << " nb_added_for_in_layer=" << nb_added_for_in_layer
548 << " do_only_minimal=" << do_only_minimal_uid;
549
550 _sortBoundaryNodeList(boundary_node_list);
551 SharedArray<BoundaryNodeInfo> all_boundary_node_info = boundary_node_list;
552
553 UniqueArray<BoundaryNodeToSendInfo> node_list_to_send;
554 {
555 ConstArrayView<BoundaryNodeInfo> all_bni = all_boundary_node_info;
556 Integer bi_n = all_bni.size();
557 for( Integer i=0; i<bi_n; ++i ){
558 const BoundaryNodeInfo& bni = all_bni[i];
559 // Recherche tous les éléments de all_bni qui ont le même noeud.
560 // Cela représente toutes les mailles connectées à ce noeud.
561 Int64 node_uid = bni.node_uid;
562 Integer last_i = i;
563 for( ; last_i<bi_n; ++last_i )
564 if (all_bni[last_i].node_uid!=node_uid)
565 break;
566 Integer nb_same_node = (last_i - i);
567 if (is_verbose)
568 info() << "NB_SAME_NODE uid=" << node_uid << " n=" << nb_same_node << " last_i=" << last_i;
569 // Maintenant, regarde si les mailles connectées à ce noeud ont le même propriétaire.
570 // Si c'est le cas, il s'agit d'un vrai noeud frontière et il n'y a donc rien à faire.
571 // Sinon, il faudra envoyer la liste des mailles à tous les PE dont les rangs apparaissent dans cette liste
572 Int32 owner = bni.cell_owner;
573 bool has_ghost = false;
574 for( Integer z=0; z<nb_same_node; ++z )
575 if (all_bni[i+z].cell_owner!=owner){
576 has_ghost = true;
577 break;
578 }
579 if (has_ghost){
580 BoundaryNodeToSendInfo si;
581 si.m_index = i;
582 si.m_nb_cell = nb_same_node;
583 node_list_to_send.add(si);
584 if (is_verbose)
585 info() << "Add ghost uid=" << node_uid << " index=" << i << " nb_same_node=" << nb_same_node;
586 }
587 i = last_i-1;
588 }
589 }
590
591 IntegerUniqueArray nb_info_to_send(nb_rank,0);
592 {
593 ConstArrayView<BoundaryNodeInfo> all_bni = all_boundary_node_info;
594 Integer nb_node_to_send = node_list_to_send.size();
595 std::set<Int32> ranks_done;
596 for( Integer i=0; i<nb_node_to_send; ++i ){
597 Integer index = node_list_to_send[i].m_index;
598 Integer nb_cell = node_list_to_send[i].m_nb_cell;
599
600 ranks_done.clear();
601
602 for( Integer kz=0; kz<nb_cell; ++kz ){
603 Int32 krank = all_bni[index+kz].cell_owner;
604 if (ranks_done.find(krank)==ranks_done.end()){
605 ranks_done.insert(krank);
606 // Pour chacun, il faudra envoyer
607 // - le nombre de mailles (1*Int64)
608 // - le uid du noeud (1*Int64)
609 // - le uid et le rank de chaque maille (2*Int64*nb_cell)
610 //TODO: il est possible de stocker les rangs sur Int32
611 nb_info_to_send[krank] += (nb_cell*2) + 2;
612 }
613 }
614 }
615 }
616
617 if (is_verbose){
618 for( Integer i=0; i<nb_rank; ++i ){
619 Integer nb_to_send = nb_info_to_send[i];
620 if (nb_to_send!=0)
621 info() << "NB_TO_SEND rank=" << i << " n=" << nb_to_send;
622 }
623 }
624
625 Integer total_nb_to_send = 0;
626 IntegerUniqueArray nb_info_to_send_indexes(nb_rank,0);
627 for( Integer i=0; i<nb_rank; ++i ){
628 nb_info_to_send_indexes[i] = total_nb_to_send;
629 total_nb_to_send += nb_info_to_send[i];
630 }
631 info() << "TOTAL_NB_TO_SEND=" << total_nb_to_send;
632
633 UniqueArray<Int64> resend_infos(total_nb_to_send);
634 {
635 ConstArrayView<BoundaryNodeInfo> all_bni = all_boundary_node_info;
636 Integer nb_node_to_send = node_list_to_send.size();
637 std::set<Int32> ranks_done;
638 for( Integer i=0; i<nb_node_to_send; ++i ){
639 Integer node_index = node_list_to_send[i].m_index;
640 Integer nb_cell = node_list_to_send[i].m_nb_cell;
641 Int64 node_uid = all_bni[node_index].node_uid;
642
643 ranks_done.clear();
644
645 for( Integer kz=0; kz<nb_cell; ++kz ){
646 Int32 krank = all_bni[node_index+kz].cell_owner;
647 if (ranks_done.find(krank)==ranks_done.end()){
648 ranks_done.insert(krank);
649 Integer send_index = nb_info_to_send_indexes[krank];
650 resend_infos[send_index] = node_uid;
651 ++send_index;
652 resend_infos[send_index] = nb_cell;
653 ++send_index;
654 for( Integer zz=0; zz<nb_cell; ++zz ){
655 resend_infos[send_index] = all_bni[node_index+zz].cell_uid;
656 ++send_index;
657 resend_infos[send_index] = all_bni[node_index+zz].cell_owner;
658 ++send_index;
659 }
660 nb_info_to_send_indexes[krank] = send_index;
661 }
662 }
663 }
664 }
665
666 IntegerUniqueArray nb_info_to_recv(nb_rank,0);
667 {
668 Timer::SimplePrinter sp(traceMng(),"Sending size with AllToAll");
669 pm->allToAll(nb_info_to_send,nb_info_to_recv,1);
670 }
671
672 if (is_verbose)
673 for( Integer i=0; i<nb_rank; ++i )
674 info() << "NB_TO_RECV: I=" << i << " n=" << nb_info_to_recv[i];
675
676 Integer total_nb_to_recv = 0;
677 for( Integer i=0; i<nb_rank; ++i )
678 total_nb_to_recv += nb_info_to_recv[i];
679
680 // Il y a de fortes chances que cela ne marche pas si le tableau est trop grand,
681 // il faut proceder avec des tableaux qui ne depassent pas 2Go a cause des
682 // Int32 de MPI.
683 // TODO: Faire le AllToAll en plusieurs fois si besoin.
684 // TOOD: Fusionner ce code avec celui de FaceUniqueIdBuilder2.
685 UniqueArray<Int64> recv_infos;
686 {
687 Int32 vsize = sizeof(Int64) / sizeof(Int64);
688 Int32UniqueArray send_counts(nb_rank);
689 Int32UniqueArray send_indexes(nb_rank);
690 Int32UniqueArray recv_counts(nb_rank);
691 Int32UniqueArray recv_indexes(nb_rank);
692 Int32 total_send = 0;
693 Int32 total_recv = 0;
694 for( Integer i=0; i<nb_rank; ++i ){
695 send_counts[i] = (Int32)(nb_info_to_send[i] * vsize);
696 recv_counts[i] = (Int32)(nb_info_to_recv[i] * vsize);
697 send_indexes[i] = total_send;
698 recv_indexes[i] = total_recv;
699 total_send += send_counts[i];
700 total_recv += recv_counts[i];
701 }
702 recv_infos.resize(total_nb_to_recv);
703
704 Int64ConstArrayView send_buf(total_nb_to_send*vsize,(Int64*)resend_infos.data());
705 Int64ArrayView recv_buf(total_nb_to_recv*vsize,(Int64*)recv_infos.data());
706
707 info() << "BUF_SIZES: send=" << send_buf.size() << " recv=" << recv_buf.size();
708 {
709 Timer::SimplePrinter sp(traceMng(),"Send values with AllToAll");
710 pm->allToAllVariable(send_buf,send_counts,send_indexes,recv_buf,recv_counts,recv_indexes);
711 }
712 }
713
714 SubDomainItemMap cells_to_send(50,true);
715
716 // TODO: il n'y a a priori pas besoin d'avoir les mailles ici mais
717 // seulement la liste des procs a qui il faut envoyer. Ensuite,
718 // si le proc connait a qui il doit envoyer, il peut envoyer les mailles
719 // à ce moment la. Cela permet d'envoyer moins d'infos dans le AllToAll précédent
720
721 {
722 Integer index = 0;
723 UniqueArray<Int32> my_cells;
724 SharedArray<Int32> ranks_to_send;
725 std::set<Int32> ranks_done;
726 while (index<total_nb_to_recv){
727 Int64 node_uid = recv_infos[index];
728 ++index;
729 Int64 nb_cell = recv_infos[index];
730 ++index;
731 Node current_node(nodes_map.findItem(node_uid));
732 if (is_verbose)
733 info() << "NODE uid=" << node_uid << " nb_cell=" << nb_cell << " idx=" << (index-2);
734 my_cells.clear();
735 ranks_to_send.clear();
736 ranks_done.clear();
737 for( Integer kk=0; kk<nb_cell; ++kk ){
738 Int64 cell_uid = recv_infos[index];
739 ++index;
740 Int32 cell_owner = CheckedConvert::toInt32(recv_infos[index]);
741 ++index;
742 if (kk==0 && current_layer==1 && m_is_allocate)
743 // Je suis la maille de plus petit uid et donc je
744 // positionne le propriétaire du noeud.
745 // TODO: ne pas faire cela ici, mais le faire dans une routine à part.
746 nodes_map.findItem(node_uid).toMutable().setOwner(cell_owner, my_rank);
747 if (is_verbose)
748 info() << " CELL=" << cell_uid << " owner=" << cell_owner;
749 if (cell_owner==my_rank){
750 impl::ItemBase dcell = cells_map.tryFind(cell_uid);
751 if (dcell.null())
752 ARCANE_FATAL("Internal error: cell uid={0} is not in our mesh", cell_uid);
753 if (do_only_minimal_uid){
754 // Ajoute toutes les mailles autour de mon noeud
755 for( CellLocalId c : current_node.cellIds() )
756 my_cells.add(c);
757 }
758 else
759 my_cells.add(dcell.localId());
760 }
761 else{
762 if (ranks_done.find(cell_owner)==ranks_done.end()){
763 ranks_to_send.add(cell_owner);
764 ranks_done.insert(cell_owner);
765 }
766 }
767 }
768
769 if (is_verbose){
770 info() << "CELLS TO SEND: node_uid=" << node_uid
771 << " nb_rank=" << ranks_to_send.size()
772 << " nb_cell=" << my_cells.size();
773 info(4) << "CELLS TO SEND: node_uid=" << node_uid
774 << " rank=" << ranks_to_send
775 << " cell=" << my_cells;
776 }
777
778 for( Integer zrank=0, zn=ranks_to_send.size(); zrank<zn; ++zrank ){
779 Int32 send_rank = ranks_to_send[zrank];
780 SubDomainItemMap::Data* d = cells_to_send.lookupAdd(send_rank);
781 Int32Array& c = d->value();
782 for( Integer zid=0, zid_size=my_cells.size(); zid<zid_size; ++zid ){
783 // TODO: regarder si maille pas déjà présente et ne pas l'ajouter si ce n'est pas nécessaire.
784 c.add(my_cells[zid]);
785 }
786 }
787 }
788 }
789
790 info() << "GHOST V3 SERIALIZE CELLS";
791 _sendAndReceiveCells(cells_to_send);
792}
793
794/*---------------------------------------------------------------------------*/
795/*---------------------------------------------------------------------------*/
805{
806 IParallelMng* pm = m_parallel_mng;
807 Int32 my_rank = pm->commRank();
808 Int32 nb_rank = pm->commSize();
809 bool is_verbose = m_is_verbose;
810
812 boundary_node_sorter.setNeedIndexAndRank(false);
813
814 {
815 Timer::SimplePrinter sp(traceMng(),"Sorting boundary nodes");
817 }
818
819 if (is_verbose){
821 Integer n = all_bni.size();
822 for( Integer i=0; i<n; ++i ){
823 const BoundaryNodeInfo& bni = all_bni[i];
824 info() << "NODES_KEY i=" << i
825 << " node=" << bni.node_uid
826 << " cell=" << bni.cell_uid
827 << " rank=" << bni.cell_owner;
828 }
829 }
830
831 // TODO: il n'y a pas besoin d'envoyer toutes les mailles.
832 // pour déterminer le propriétaire d'un noeud, il suffit
833 // que chaque PE envoie sa maille de plus petit UID.
834 // Ensuite, chaque noeud a besoin de savoir la liste
835 // des sous-domaines connectés pour renvoyer l'info. Chaque
836 // sous-domaine en sachant cela saura a qui il doit envoyer
837 // les mailles fantomes.
838
839 {
841 Integer n = all_bni.size();
842 // Comme un même noeud peut être présent dans la liste du proc précédent, chaque PE
843 // (sauf le 0) envoie au proc précédent le début sa liste qui contient les même noeuds.
844
846 Integer begin_own_list_index = 0;
847 if (n!=0 && my_rank!=0){
848 if (BoundaryNodeBitonicSortTraits::isValid(all_bni[0])){
849 Int64 node_uid = all_bni[0].node_uid;
850 for( Integer i=0; i<n; ++i ){
851 if (all_bni[i].node_uid!=node_uid){
853 break;
854 }
855 else
856 end_node_list.add(all_bni[i]);
857 }
858 }
859 }
860 info() << "BEGIN_OWN_LIST_INDEX=" << begin_own_list_index << " end_node_list_size=" << end_node_list.size();
861 if (is_verbose){
862 for( Integer k=0, kn=end_node_list.size(); k<kn; ++k )
863 info() << " SEND node_uid=" << end_node_list[k].node_uid
864 << " cell_uid=" << end_node_list[k].cell_uid;
865 }
866
868
870 Integer recv_message_size = 0;
871 Integer send_message_size = BoundaryNodeBitonicSortTraits::messageSize(end_node_list);
872
873 // Envoie et réceptionne d'abord les tailles.
874 if (my_rank!=(nb_rank-1)){
875 requests.add(pm->recv(IntegerArrayView(1,&recv_message_size),my_rank+1,false));
876 }
877 if (my_rank!=0){
878 requests.add(pm->send(IntegerConstArrayView(1,&send_message_size),my_rank-1,false));
879 }
880 info() << "Send size=" << send_message_size << " Recv size=" << recv_message_size;
881 pm->waitAllRequests(requests);
882 requests.clear();
883
884 if (recv_message_size!=0){
885 Int32 nb_element = BoundaryNodeInfo::nbElement(recv_message_size);
887 requests.add(BoundaryNodeBitonicSortTraits::recv(pm,my_rank+1,end_node_list_recv));
888 }
889 if (send_message_size!=0)
890 requests.add(BoundaryNodeBitonicSortTraits::send(pm,my_rank-1,end_node_list));
891
892 pm->waitAllRequests(requests);
893
894 boundary_node_list.clear();
897 }
898}
899
900/*---------------------------------------------------------------------------*/
901/*---------------------------------------------------------------------------*/
902
903void GhostLayerBuilder2::
904_sendAndReceiveCells(SubDomainItemMap& cells_to_send)
905{
906 auto exchanger { ParallelMngUtils::createExchangerRef(m_parallel_mng) };
907
908 const bool is_verbose = m_is_verbose;
909
910 // Envoie et réceptionne les mailles fantômes
911 for( SubDomainItemMap::Enumerator i_map(cells_to_send); ++i_map; ){
912 Int32 sd = i_map.data()->key();
913 Int32Array& items = i_map.data()->value();
914
915 // Comme la liste par sous-domaine peut contenir plusieurs
916 // fois la même maille, on trie la liste et on supprime les
917 // doublons
918 std::sort(std::begin(items),std::end(items));
919 auto new_end = std::unique(std::begin(items),std::end(items));
920 items.resize(CheckedConvert::toInteger(new_end-std::begin(items)));
921 if (is_verbose)
922 info(4) << "CELLS TO SEND SD=" << sd << " Items=" << items;
923 else
924 info(4) << "CELLS TO SEND SD=" << sd << " nb=" << items.size();
925 exchanger->addSender(sd);
926 }
927 exchanger->initializeCommunicationsMessages();
928 for( Integer i=0, ns=exchanger->nbSender(); i<ns; ++i ){
929 ISerializeMessage* sm = exchanger->messageToSend(i);
930 Int32 rank = sm->destination().value();
931 ISerializer* s = sm->serializer();
932 Int32ConstArrayView items_to_send = cells_to_send[rank];
933 m_mesh->serializeCells(s,items_to_send);
934 }
935 exchanger->processExchange();
936 info(4) << "END EXCHANGE CELLS";
937 for( Integer i=0, ns=exchanger->nbReceiver(); i<ns; ++i ){
938 ISerializeMessage* sm = exchanger->messageToReceive(i);
939 ISerializer* s = sm->serializer();
940 m_mesh->addCells(s);
941 }
942 m_mesh_builder->printStats();
943}
944
945/*---------------------------------------------------------------------------*/
946/*---------------------------------------------------------------------------*/
956{
957 IParallelMng* pm = m_mesh->parallelMng();
958 Int32 my_rank = pm->commRank();
959 ItemInternalMap& faces_map = m_mesh->facesMap();
960
962
963 // Parcours les faces et marque les nœuds, arêtes et faces frontières
964 faces_map.eachItem([&](Face face) {
965 bool is_sub_domain_boundary_face = false;
966 if (face.itemBase().flags() & ItemFlags::II_Boundary){
967 is_sub_domain_boundary_face = true;
968 }
969 else{
970 if (face.nbCell()==2 && (face.cell(0).owner()!=my_rank || face.cell(1).owner()!=my_rank))
971 is_sub_domain_boundary_face = true;
972 }
975 for( Item inode : face.nodes() )
976 inode.mutableItemBase().addFlags(shared_and_boundary_flags);
977 for( Item iedge : face.edges() )
978 iedge.mutableItemBase().addFlags(shared_and_boundary_flags);
979 }
980 });
981}
982
983/*---------------------------------------------------------------------------*/
984/*---------------------------------------------------------------------------*/
985
986extern "C++" void
987_buildGhostLayerNewVersion(DynamicMesh* mesh,bool is_allocate,Int32 version)
988{
989 GhostLayerBuilder2 glb(mesh->m_mesh_builder,is_allocate,version);
990 glb.addGhostLayers();
991}
992
993/*---------------------------------------------------------------------------*/
994/*---------------------------------------------------------------------------*/
995
996} // End namespace Arcane::mesh
997
998/*---------------------------------------------------------------------------*/
999/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Tableau d'items de types quelconques.
Maille d'un maillage.
Definition Item.h:1178
Face d'une maille.
Definition Item.h:932
Cell cell(Int32 i) const
i-ème maille de la face
Definition Item.h:1617
Int32 nbCell() const
Nombre de mailles de la face (1 ou 2)
Definition Item.h:1006
EdgeConnectedListViewType edges() const
Liste des arêtes de la face.
Definition Item.h:1123
Table de hachage pour tableaux associatifs.
virtual Integer nbGhostLayer() const =0
Nombre de couches fantômes.
virtual Int32 maxLocalId() const =0
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual void recv(ArrayView< char > values, Int32 rank)=0
virtual Int32 commSize() const =0
Nombre d'instance dans le communicateur.
virtual void waitAllRequests(ArrayView< Request > rvalues)=0
Bloque en attendant que les requêtes rvalues soient terminées.
virtual bool isParallel() const =0
Retourne true si l'exécution est parallèle.
MutableItemBase toMutable()
Interface modifiable de cette entité
Int32 flags() const
Flags de l'entité
@ II_Shared
L'entité est partagée par un autre sous-domaine.
Definition ItemFlags.h:51
@ II_SubDomainBoundary
L'entité est à la frontière de deux sous-domaines.
Definition ItemFlags.h:52
@ II_Boundary
L'entité est sur la frontière.
Definition ItemFlags.h:43
Structure interne d'une entité de maillage.
Classe utilitaire pour imprimer les infos sur une entité.
Definition ItemPrinter.h:35
NodeConnectedListViewType nodes() const
Liste des noeuds de l'entité
Definition Item.h:771
NodeLocalIdView nodeIds() const
Liste des noeuds de l'entité
Definition Item.h:774
Classe de base d'un élément de maillage.
Definition Item.h:83
impl::MutableItemBase mutableItemBase() const
Partie interne modifiable de l'entité.
Definition Item.h:365
constexpr Int32 localId() const
Identifiant local de l'entité dans le sous-domaine du processeur.
Definition Item.h:210
bool isOwn() const
true si l'entité est appartient au sous-domaine
Definition Item.h:244
Int32 owner() const
Numéro du sous-domaine propriétaire de l'entité
Definition Item.h:229
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
Definition Item.h:216
impl::ItemBase itemBase() const
Partie interne de l'entité.
Definition Item.h:354
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
void setOwner(Integer suid, Int32 current_sub_domain)
Positionne le numéro du sous-domaine propriétaire de l'entité.
void addFlags(Int32 added_flags)
Ajoute les flags \added_flags à ceux de l'entité
Noeud d'un maillage.
Definition Dom.h:204
Affiche le temps passé entre l'appel au constructeur et le destructeur.
Definition Timer.h:156
Construction d'un maillage de manière incrémentale.
Implémentation d'un maillage.
Definition DynamicMesh.h:97
IItemFamily * nodeFamily() override
Retourne la famille des noeuds.
IItemFamily * cellFamily() override
Retourne la famille des mailles.
IParallelMng * parallelMng() override
Gestionnaire de parallèlisme.
void serializeCells(ISerializer *buffer, Int32ConstArrayView cells_local_id) override
void addCells(Integer nb_cell, Int64ConstArrayView cell_infos, Int32ArrayView cells) override
Ajoute des mailles.
IGhostLayerMng * ghostLayerMng() const override
Gestionnare de couche fantômes associé
Fonctor pour trier les BoundaryNodeInfo via le tri bitonic.
Structure contenant les informations des noeuds frontières.
Construction des couches fantômes.
void _sortBoundaryNodeList(Array< BoundaryNodeInfo > &boundary_node_list)
Trie parallèle de la liste des infos sur les noeuds frontières.
void _markBoundaryItems()
Marque les entitées au bord du sous-domaine.
GhostLayerBuilder2(DynamicMeshIncrementalBuilder *mesh_builder, bool is_allocate, Int32 version)
Construit une instance pour le maillage mesh.
void addGhostLayers()
Ajoute les couches de mailles fantomes.
void _markBoundaryNodes(ArrayView< Int32 > node_layer)
Détermine les noeuds frontières.
Tableau associatif de ItemInternal.
impl::ItemBase findItem(Int64 uid) const
Retourne l'entité de numéro unique uid.
void eachItem(const Lambda &lambda)
Fonction template pour itérer sur les entités de l'instance.
impl::ItemBase tryFind(Int64 key) const
Retourne l'entité associée à key si trouvé ou l'entité nulle sinon.
Vue modifiable d'un tableau d'un type T.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
Vue constante d'un tableau de type T.
Requête d'un message.
Definition Request.h:77
ITraceMng * traceMng() const
Gestionnaire de trace.
TraceMessage warning() const
Flot pour un message d'avertissement.
TraceMessage info() const
Flot pour un message d'information.
Integer toInteger(Real r)
Converti un Int64 en un Integer.
Int32 toInt32(Int64 v)
Converti un Int64 en un Int32.
Ref< IParallelExchanger > createExchangerRef(IParallelMng *pm)
Retourne une interface pour transférer des messages entre rangs.
void add(ArrayView< T > lhs, ConstArrayView< T > copy_array)
Ajoute le tableau copy_array dans l'instance.
Definition MathUtils.h:885
ConstArrayView< Int32 > Int32ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:640
ArrayView< Int64 > Int64ArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:609
UniqueArray< Int32 > Int32UniqueArray
Tableau dynamique à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:515
Array< Int32 > Int32Array
Tableau dynamique à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:327
ConstArrayView< Int64 > Int64ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:638
UniqueArray< Integer > IntegerUniqueArray
Tableau dynamique à une dimension d'entiers.
Definition UtilsTypes.h:519
Int32 Integer
Type représentant un entier.