Arcane  v3.14.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
FaceUniqueIdBuilder2.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/* FaceUniqueIdBuilder2.cc (C) 2000-2024 */
9/* */
10/* Construction des identifiants uniques des faces. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/PlatformUtils.h"
15#include "arcane/utils/ArgumentException.h"
16#include "arcane/utils/CheckedConvert.h"
17
18#include "arcane/mesh/DynamicMesh.h"
19#include "arcane/mesh/FaceUniqueIdBuilder.h"
20
21#include "arcane/core/IParallelMng.h"
22#include "arcane/core/Timer.h"
23
24#include "arcane/parallel/BitonicSortT.H"
25
26/*---------------------------------------------------------------------------*/
27/*---------------------------------------------------------------------------*/
28
29namespace Arcane::mesh
30{
31
32/*---------------------------------------------------------------------------*/
33/*---------------------------------------------------------------------------*/
70: public TraceAccessor
71{
72 public:
73
75 class WideCellFaceInfo;
76 class AnyFaceInfo;
77 class BoundaryFaceInfo;
78 class ResendCellInfo;
81 class UniqueIdSorter;
82
83 // Choisir le bon typedef suivant le choix de la structure d'échange.
85
86 public:
87
89 explicit FaceUniqueIdBuilder2(DynamicMesh* mesh);
90
91 public:
92
95
96 private:
97
98 DynamicMesh* m_mesh = nullptr;
99 IParallelMng* m_parallel_mng = nullptr;
100 bool m_is_verbose = false;
101
102 private:
103
104 void _resendCellsAndComputeFacesUniqueId(ConstArrayView<AnyFaceInfo> all_csi);
105 void _checkFacesUniqueId();
106 void _unsetFacesUniqueId();
108 void _computeParallel();
109 void _computeSequential();
110};
111
112/*---------------------------------------------------------------------------*/
113/*---------------------------------------------------------------------------*/
140{
141 public:
142 static const Int64 BITS_CELL_UID = 39;
143 static const Int64 BITS_RANK = 20;
144 static const Int64 BITS_INDEX = 5;
145 static const Int64 ONE_INT64 = 1;
146 static const Int64 MASK_CELL_UID = (ONE_INT64 << BITS_CELL_UID) - 1;
147 static const Int64 MASK_RANK = ((ONE_INT64 << BITS_RANK) - 1) << BITS_CELL_UID;
148 static const Int64 MASK_INDEX = ((ONE_INT64 << BITS_INDEX) - 1) << (BITS_CELL_UID+BITS_RANK);
149
150 public:
152 {
153 setValue(NULL_ITEM_UNIQUE_ID,-1,-1);
154 }
155 public:
156
157 bool isMaxValue() const
158 {
159 Int64 max_id = (MASK_CELL_UID - 1);
160 return cellUid()==max_id;
161 }
162
163 void setMaxValue()
164 {
165 Int64 max_id = (MASK_CELL_UID - 1);
166 setValue(max_id,-1,-1);
167 }
168
169 void setValue(Int64 cell_uid,Int32 _rank,Int32 face_local_index)
170 {
171 Int64 v_fli = face_local_index+1;
172 Int64 v_rank = _rank+1;
173 Int64 v_uid = cell_uid+1;
174 m_value = v_fli << (BITS_CELL_UID+BITS_RANK);
175 m_value += v_rank << (BITS_CELL_UID);
176 m_value += v_uid;
177 if (cellUid()!=cell_uid)
178 ARCANE_FATAL("Bad uid expected='{0}' computed='{1}' v={2}",cell_uid,cellUid(),m_value);
179 if (rank()!=_rank)
180 ARCANE_FATAL("Bad rank expected='{0}' computed='{1}'",_rank,rank());
181 if (faceLocalIndex()!=face_local_index)
182 ARCANE_FATAL("Bad local_index expected='{0}' computed='{1}'",face_local_index,faceLocalIndex());
183 }
184 Int64 cellUid() const { return (m_value & MASK_CELL_UID) - 1; }
185 Int32 rank() const { return CheckedConvert::toInt32( ((m_value & MASK_RANK) >> BITS_CELL_UID) - 1 ); }
186 Int32 faceLocalIndex() const { return CheckedConvert::toInt32( ((m_value & MASK_INDEX) >> (BITS_CELL_UID+BITS_RANK)) - 1 ); }
187
188 bool isValid() const { return cellUid()!=NULL_ITEM_UNIQUE_ID; }
189
190 private:
191
192 Int64 m_value = -1;
193};
194
195/*---------------------------------------------------------------------------*/
196/*---------------------------------------------------------------------------*/
201{
202 public:
203 WideCellFaceInfo() : m_cell_uid(NULL_ITEM_UNIQUE_ID), m_rank(-1), m_face_local_index(-1){}
204 public:
205 bool isMaxValue() const
206 {
207 Int64 max_id = INT64_MAX;
208 return cellUid()==max_id;
209 }
210
211 void setMaxValue()
212 {
213 Int64 max_id = INT64_MAX;
214 setValue(max_id,-1,-1);
215 }
216 void setValue(Int64 cell_uid,Int32 rank,Int32 face_local_index)
217 {
218 m_cell_uid = cell_uid;
219 m_rank = rank;
220 m_face_local_index = face_local_index;
221 }
222 Int64 cellUid() const { return m_cell_uid; }
223 Int32 rank() const { return m_rank; }
224 Int32 faceLocalIndex() const { return m_face_local_index; }
225 bool isValid() const { return m_cell_uid!=NULL_ITEM_UNIQUE_ID; }
226
227 private:
228
229 Int64 m_cell_uid;
230 Int32 m_rank;
231 Int32 m_face_local_index;
232};
233
234/*---------------------------------------------------------------------------*/
235/*---------------------------------------------------------------------------*/
243{
244 public:
246 : m_node0_uid(NULL_ITEM_UNIQUE_ID), m_node1_uid(NULL_ITEM_UNIQUE_ID),
247 m_node2_uid(NULL_ITEM_UNIQUE_ID), m_cell_uid(NULL_ITEM_UNIQUE_ID),
248 m_rank(-1), m_face_local_index(-1)
249 {}
250 bool hasSameNodes(const BoundaryFaceInfo& fsi) const
251 {
252 return fsi.m_node0_uid==m_node0_uid && fsi.m_node1_uid==m_node1_uid
253 && fsi.m_node2_uid==m_node2_uid;
254 }
255 void setNodes(Face face)
256 {
257 Integer nb_node = face.nbNode();
258 if (nb_node>=1)
259 m_node0_uid = face.node(0).uniqueId();
260 if (nb_node>=2)
261 m_node1_uid = face.node(1).uniqueId();
262 if (nb_node>=3)
263 m_node2_uid = face.node(2).uniqueId();
264 }
265 public:
266 Int64 m_node0_uid;
267 Int64 m_node1_uid;
268 Int64 m_node2_uid;
269 Int64 m_cell_uid;
270 Int32 m_rank;
271 Int32 m_face_local_index;
272 public:
273};
274
275/*---------------------------------------------------------------------------*/
276/*---------------------------------------------------------------------------*/
285{
286 public:
287
288 AnyFaceInfo() = default;
289
290 public:
291 void setCell0(Int64 uid,Int32 rank,Int32 face_local_index)
292 {
293 m_cell0.setValue(uid,rank,face_local_index);
294 }
295 void setCell1(Int64 uid,Int32 rank,Int32 face_local_index)
296 {
297 m_cell1.setValue(uid,rank,face_local_index);
298 }
299 public:
300 CellFaceInfo m_cell0;
301 CellFaceInfo m_cell1;
302 public:
303};
304
305/*---------------------------------------------------------------------------*/
306/*---------------------------------------------------------------------------*/
307
308// Attention, cette classe doit avoir une taille multiple de Int64
310{
311 public:
312 Int64 m_cell_uid;
313 // Ce champs contient à la fois le numéro local de la face dans la maille
314 // et le rang du propriétaire de la maille.
315 // m_face_local_index_and_owner_rank / nb_rank -> face_index
316 // m_face_local_index_and_owner_rank % nb_rank -> owner_rank
317 Int32 m_face_local_index_and_owner_rank;
318 Int32 m_index_in_rank_list;
319};
320
321/*---------------------------------------------------------------------------*/
322/*---------------------------------------------------------------------------*/
323
324/*---------------------------------------------------------------------------*/
325/*---------------------------------------------------------------------------*/
326
327/*---------------------------------------------------------------------------*/
328/*---------------------------------------------------------------------------*/
333{
334 public:
335 static bool compareLess(const BoundaryFaceInfo& k1,const BoundaryFaceInfo& k2)
336 {
337 if (k1.m_node0_uid<k2.m_node0_uid)
338 return true;
339 if (k1.m_node0_uid>k2.m_node0_uid)
340 return false;
341
342 // ke.node0_uid == k2.node0_uid
343 if (k1.m_node1_uid<k2.m_node1_uid)
344 return true;
345 if (k1.m_node1_uid>k2.m_node1_uid)
346 return false;
347
348 // ke.node1_uid == k2.node1_uid
349 if (k1.m_node2_uid<k2.m_node2_uid)
350 return true;
351 if (k1.m_node2_uid>k2.m_node2_uid)
352 return false;
353
354 // ke.node2_uid == k2.node2_uid
355 return (k1.m_cell_uid<k2.m_cell_uid);
356 }
357
358 static Parallel::Request send(IParallelMng* pm,Int32 rank,ConstArrayView<BoundaryFaceInfo> values)
359 {
360 const BoundaryFaceInfo* fsi_base = values.data();
361 return pm->send(ByteConstArrayView(messageSize(values),(const Byte*)fsi_base),rank,false);
362 }
363 static Parallel::Request recv(IParallelMng* pm,Int32 rank,ArrayView<BoundaryFaceInfo> values)
364 {
365 BoundaryFaceInfo* fsi_base = values.data();
366 return pm->recv(ByteArrayView(messageSize(values),(Byte*)fsi_base),rank,false);
367 }
368 static Integer messageSize(ConstArrayView<BoundaryFaceInfo> values)
369 {
370 return CheckedConvert::toInteger( values.size()*sizeof(BoundaryFaceInfo) );
371 }
372 static BoundaryFaceInfo maxValue()
373 {
375 fsi.m_cell_uid = INT64_MAX;
376 fsi.m_rank = INT32_MAX;
377 fsi.m_node0_uid = INT64_MAX;
378 fsi.m_node1_uid = INT64_MAX;
379 fsi.m_node2_uid = INT64_MAX;
380 return fsi;
381 }
382 static bool isValid(const BoundaryFaceInfo& fsi)
383 {
384 return fsi.m_cell_uid!=INT64_MAX;
385 }
386};
387
388/*---------------------------------------------------------------------------*/
389/*---------------------------------------------------------------------------*/
402{
403 public:
404 static bool compareLess(const AnyFaceInfo& k1,const AnyFaceInfo& k2)
405 {
406 Int64 k1_cell0_uid = k1.m_cell0.cellUid();
407 Int64 k2_cell0_uid = k2.m_cell0.cellUid();
409 return true;
411 return false;
412
413 Int64 k1_face0_local_index = k1.m_cell0.faceLocalIndex();
414 Int64 k2_face0_local_index = k2.m_cell0.faceLocalIndex();
416 return true;
418 return false;
419
420 return (k1.m_cell1.cellUid()<k2.m_cell1.cellUid());
421 }
422
423 static Parallel::Request send(IParallelMng* pm,Int32 rank,ConstArrayView<AnyFaceInfo> values)
424 {
425 const AnyFaceInfo* fsi_base = values.data();
426 Integer message_size = CheckedConvert::toInteger(values.size()*sizeof(AnyFaceInfo));
427 return pm->send(ByteConstArrayView(message_size,(const Byte*)fsi_base),rank,false);
428 }
429
430 static Parallel::Request recv(IParallelMng* pm,Int32 rank,ArrayView<AnyFaceInfo> values)
431 {
432 AnyFaceInfo* fsi_base = values.data();
433 Integer message_size = CheckedConvert::toInteger(values.size()*sizeof(AnyFaceInfo));
434 return pm->recv(ByteArrayView(message_size,(Byte*)fsi_base),rank,false);
435 }
436
437 static AnyFaceInfo maxValue()
438 {
440 csi.m_cell0.setMaxValue();
441 csi.m_cell1.setMaxValue();
442 return csi;
443 }
444
445 static bool isValid(const AnyFaceInfo& csi)
446 {
447 return !csi.m_cell0.isMaxValue();
448 }
449};
450
451/*---------------------------------------------------------------------------*/
452/*---------------------------------------------------------------------------*/
453
455{
456 public:
457
458 bool operator()(const Item& i1, const Item& i2) const
459 {
460 return i1.uniqueId() < i2.uniqueId();
461 }
462};
463
464/*---------------------------------------------------------------------------*/
465/*---------------------------------------------------------------------------*/
466
467/*---------------------------------------------------------------------------*/
468/*---------------------------------------------------------------------------*/
469
472: TraceAccessor(mesh->traceMng())
473, m_mesh(mesh)
474, m_parallel_mng(mesh->parallelMng())
475{
476}
477
478/*---------------------------------------------------------------------------*/
479/*---------------------------------------------------------------------------*/
480
481/*---------------------------------------------------------------------------*/
482/*---------------------------------------------------------------------------*/
488{
489 if (m_parallel_mng->isParallel())
491 else
493}
494
495/*---------------------------------------------------------------------------*/
496/*---------------------------------------------------------------------------*/
502{
503 info() << "Compute FacesUniqueId() Sequential V3";
504
505 //TODO: permettre de ne pas commencer a zero.
506 Int64 face_unique_id_counter = 0;
507
508 ItemInternalMap& cells_map = m_mesh->cellsMap();
509 Integer nb_cell = cells_map.count();
510 UniqueArray<Cell> cells;
511 cells.reserve(nb_cell);
512 // D'abord, il faut trier les mailles par leur uniqueId()
513 // en ordre croissant
514 cells_map.eachItem([&](Cell item) {
515 cells.add(item);
516 });
517 std::sort(std::begin(cells),std::end(cells),UniqueIdSorter());
518
519 // Invalide les uid pour être certain qu'ils seront tous positionnés.
521
522 for( Integer i=0; i<nb_cell; ++i ){
523 Cell cell = cells[i];
524 for( Face face : cell.faces()){
525 if (face.uniqueId()==NULL_ITEM_UNIQUE_ID){
526 face.mutableItemBase().setUniqueId(face_unique_id_counter);
528 }
529 }
530 }
531}
532
533/*---------------------------------------------------------------------------*/
534/*---------------------------------------------------------------------------*/
540{
541 IParallelMng* pm = m_parallel_mng;
542 Int32 my_rank = pm->commRank();
543
544 bool is_verbose = m_is_verbose;
545
546 ItemInternalMap& cells_map = m_mesh->cellsMap();
547
548 info() << "Compute FacesUniqueId() V3 using parallel sort";
549
550 // Calcule et trie pour les faces frontières
553
554 // Ici, les faces de bord sont triées en fonction de leur noeuds.
555 // Normalement, dans cette liste, 2 éléments consécutifs BoundaryFaceInfo qui
556 // ont les même noeuds représentent la même face. Dans ce cas, on génère
557 // un AnyFaceInfo avec les infos des deux mailles issus de ces deux éléments de
558 // la liste en faisant bien attention de mettre en premier la maille
559 // de plus petit uniqueId().
560 // Si deux éléments consécutifs de la liste n'ont pas les mêmes noeuds, cela
561 // signifie que la face est au bord du domaine global.
562 // Il faut tout de même traiter le cas des deux éléments consécutifs de la liste
563 // qui se trouvent sur des processeurs différents. Pour gérer ce cas, chaque
564 // processeur envoie au suivant le dernier élément de sa liste s'il ne peut pas
565 // être fusionné avec l'avant dernier, dans l'espoir qu'il pourra l'être avec le
566 // premier de la liste du processeur suivant.
568 {
570 Integer n = all_fsi.size();
571 bool is_last_already_done = false;
572 for( Integer i=0; i<n; ++i ){
573 const BoundaryFaceInfo& fsi = all_fsi[i];
574 Int64 cell_uid0 = fsi.m_cell_uid;
575 bool is_inside = false;
576 //TODO: traiter le cas si la maille d'avant est sur un autre proc
577 // Pour cela, il faut recupérer la dernière valeur du proc précédent
578 // et regarder si elle correspond à notre première valeur
579 is_inside = ((i+1)!=n && fsi.hasSameNodes(all_fsi[i+1]));
581 is_last_already_done = false;
582 }
583 else{
585 if (is_inside){
586 const BoundaryFaceInfo& next_fsi = all_fsi[i+1];
587 Int64 cell_uid1 = next_fsi.m_cell_uid;
588 if (cell_uid0<cell_uid1){
589 csi.setCell0(cell_uid0,fsi.m_rank,fsi.m_face_local_index);
590 csi.setCell1(cell_uid1,next_fsi.m_rank,next_fsi.m_face_local_index);
591 }
592 else{
593 csi.setCell0(cell_uid1,next_fsi.m_rank,next_fsi.m_face_local_index);
594 csi.setCell1(cell_uid0,fsi.m_rank,fsi.m_face_local_index);
595 }
597 }
598 else{
599 csi.setCell0(cell_uid0,fsi.m_rank,fsi.m_face_local_index);
600 }
601 all_face_list.add(csi);
602 }
603 if (is_verbose)
604 info() << "FACES_KEY i=" << i
605 << " n0=" << fsi.m_node0_uid
606 << " n1=" << fsi.m_node1_uid
607 << " n2=" << fsi.m_node2_uid
608 << " cell=" << fsi.m_cell_uid
609 << " rank=" << fsi.m_rank
610 << " li=" << fsi.m_face_local_index
611 << " in=" << is_inside;
612 }
613 }
614
615 // Ajoute les faces propres a notre sous-domaine.
616 // Il s'agit de toutes les faces qui ont 2 mailles connectées.
617 cells_map.eachItem([&](Cell cell) {
618 Integer cell_nb_face = cell.nbFace();
619 Int64 cell_uid = cell.uniqueId();
620 for( Integer z=0; z<cell_nb_face; ++z ){
621 Face face = cell.face(z);
622 if (face.nbCell()!=2)
623 continue;
624 Cell cell0 = face.cell(0);
625 Cell cell1 = face.cell(1);
626 Cell next_cell = (cell0==cell) ? cell1 : cell0;
627 Int64 next_cell_uid = next_cell.uniqueId();
628 // N'enregistre que si je suis la maille de plus petit uid
629 if (cell_uid<next_cell_uid){
631 csi.m_cell0.setValue(cell_uid,my_rank,z);
632 // Le face_local_index de la maille 1 ne sera pas utilisé
633 csi.m_cell1.setValue(next_cell_uid,my_rank,-1);
634 all_face_list.add(csi);
635 }
636 }
637 });
638
639 if (is_verbose){
640 Integer n = all_face_list.size();
641 for( Integer i=0; i<n; ++i ){
642 const AnyFaceInfo& csi = all_face_list[i];
643 info() << "CELL_TO_SORT i=" << i
644 << " cell0=" << csi.m_cell0.cellUid()
645 << " lidx0=" << csi.m_cell0.faceLocalIndex()
646 << " cell1=" << csi.m_cell1.cellUid();
647 }
648 }
649
650 info() << "ALL_FACE_LIST memorysize=" << sizeof(AnyFaceInfo)*all_face_list.size();
652 all_face_sorter.setNeedIndexAndRank(false);
653 Real sort_begin_time = platform::getRealTime();
655 Real sort_end_time = platform::getRealTime();
656 info() << "END_ALL_FACE_SORTER time=" << (Real)(sort_end_time - sort_begin_time);
657
658 _resendCellsAndComputeFacesUniqueId(all_face_sorter.keys());
659}
660
661/*---------------------------------------------------------------------------*/
662/*---------------------------------------------------------------------------*/
669{
670 IParallelMng* pm = m_parallel_mng;
671 Int32 my_rank = pm->commRank();
672 bool is_verbose = m_is_verbose;
673 ItemInternalMap& faces_map = m_mesh->facesMap();
674
676 boundary_face_sorter.setNeedIndexAndRank(false);
677
678 //UniqueArray<BoundaryFaceInfo> boundary_face_list;
679 boundary_faces_info.clear();
680 faces_map.eachItem([&](Face face) {
682 Integer nb_cell = face.nbCell();
683 if (nb_cell==2)
684 return;
685
686 fsi.m_rank = my_rank;
687 fsi.setNodes(face);
688 Cell cell = face.cell(0);
689 fsi.m_cell_uid = cell.uniqueId();
690 Integer face_local_index = 0;
691 for( Integer z=0, zs=cell.nbFace(); z<zs; ++z )
692 if (cell.face(z)==face){
694 break;
695 }
696 fsi.m_face_local_index = face_local_index;
698 });
699
700 if (is_verbose){
702 Integer n = all_fsi.size();
703 for( Integer i=0; i<n; ++i ){
704 const BoundaryFaceInfo& fsi = all_fsi[i];
705 info() << "KEY i=" << i
706 << " n0=" << fsi.m_node0_uid
707 << " n1=" << fsi.m_node1_uid
708 << " n2=" << fsi.m_node2_uid
709 << " cell=" << fsi.m_cell_uid
710 << " rank=" << fsi.m_rank
711 << " li=" << fsi.m_face_local_index;
712 }
713 }
714
715 Real sort_begin_time = platform::getRealTime();
717 Real sort_end_time = platform::getRealTime();
718 info() << "END_BOUNDARY_FACE_SORT time=" << (Real)(sort_end_time - sort_begin_time);
719
720 {
722 Integer n = all_bfi.size();
723 if (is_verbose){
724 for( Integer i=0; i<n; ++i ){
725 const BoundaryFaceInfo& bfi = all_bfi[i];
726 info() << " AFTER KEY i=" << i
727 << " n0=" << bfi.m_node0_uid
728 << " n1=" << bfi.m_node1_uid
729 << " n2=" << bfi.m_node2_uid
730 << " cell=" << bfi.m_cell_uid
731 << " rank=" << bfi.m_rank
732 << " li=" << bfi.m_face_local_index;
733 }
734 }
735
736 // Comme un même noeud peut être présent dans la liste du proc précédent, chaque PE
737 // (sauf le 0) envoie au proc précédent le début sa liste qui contient les même noeuds.
738
739 // TODO: fusionner ce code avec celui de GhostLayerBuilder2
741 Integer begin_own_list_index = 0;
742 if (n!=0 && my_rank!=0){
743 if (BoundaryFaceBitonicSortTraits::isValid(all_bfi[0])){
744 Int64 node0_uid = all_bfi[0].m_node0_uid;
745 for( Integer i=0; i<n; ++i ){
746 if (all_bfi[i].m_node0_uid!=node0_uid){
748 break;
749 }
750 else
751 end_face_list.add(all_bfi[i]);
752 }
753 }
754 }
755 info() << "BEGIN_OWN_LIST_INDEX=" << begin_own_list_index;
756 if (is_verbose){
757 for( Integer k=0, kn=end_face_list.size(); k<kn; ++k )
758 info() << " SEND n0=" << end_face_list[k].m_node0_uid
759 << " n1=" << end_face_list[k].m_node1_uid
760 << " n2=" << end_face_list[k].m_node2_uid;
761 }
762
764
766 Integer recv_message_size = 0;
767 Integer send_message_size = BoundaryFaceBitonicSortTraits::messageSize(end_face_list);
768
769 Int32 nb_rank = pm->commSize();
770
771 // Envoie et réceptionne d'abord les tailles.
772 if (my_rank!=(nb_rank-1)){
773 requests.add(pm->recv(IntegerArrayView(1,&recv_message_size),my_rank+1,false));
774 }
775 if (my_rank!=0){
776 requests.add(pm->send(IntegerConstArrayView(1,&send_message_size),my_rank-1,false));
777 }
778
779 pm->waitAllRequests(requests);
780 requests.clear();
781
782 if (recv_message_size!=0){
785 requests.add(BoundaryFaceBitonicSortTraits::recv(pm,my_rank+1,end_face_list_recv));
786 }
787 if (send_message_size!=0)
788 requests.add(BoundaryFaceBitonicSortTraits::send(pm,my_rank-1,end_face_list));
789
790 pm->waitAllRequests(requests);
791
792 boundary_faces_info.clear();
795 }
796
797}
798
799/*---------------------------------------------------------------------------*/
800/*---------------------------------------------------------------------------*/
801
802void FaceUniqueIdBuilder2::
803_resendCellsAndComputeFacesUniqueId(ConstArrayView<AnyFaceInfo> all_csi)
804{
805 IParallelMng* pm = m_parallel_mng;
806 Int32 nb_rank = pm->commSize();
807 Int32 my_rank = pm->commRank();
808 bool is_verbose = m_is_verbose;
809
810 ItemInternalMap& cells_map = m_mesh->cellsMap();
811
812 Int64 nb_computed_face = all_csi.size();
813
814 if (is_verbose){
815 for( Integer i=0; i<nb_computed_face; ++i ){
816 const AnyFaceInfo& csi = all_csi[i];
817 info() << "CELLS_KEY i=" << i
818 << " cell0=" << csi.m_cell0.cellUid()
819 << " lidx0=" << csi.m_cell0.faceLocalIndex()
820 << " cell1=" << csi.m_cell1.cellUid()
821 << " lidx1=" << csi.m_cell1.faceLocalIndex()
822 << " rank0=" << csi.m_cell0.rank()
823 << " rank1=" << csi.m_cell1.rank();
824 }
825 }
826
827 // Calcul pour chaque rang le nombre de valeurs à envoyer
828 // et le stocke dans nb_info_to_send;
829 IntegerUniqueArray nb_info_to_send(nb_rank,0);
830 {
831 for( Integer i=0; i<nb_computed_face; ++i ){
832 const AnyFaceInfo& csi = all_csi[i];
833 Int32 rank0 = csi.m_cell0.rank();
834 Int32 rank1 = csi.m_cell1.rank();
835
836 ++nb_info_to_send[rank0];
837
838 // Il ne faut l'envoyer que si le rang est différent de m_rank0
839 if (csi.m_cell1.isValid() && rank1!=rank0)
840 ++nb_info_to_send[rank1];
841 }
842 }
843
844 // Tableau pour chaque proc indiquant le uniqueId() de la première
845 // face de ce proc.
846 Int64UniqueArray all_first_face_uid(nb_rank);
847 {
848 // Chaque proc récupère le nombre de mailles dans la liste.
849 // Comme cette liste sera triée, cela correspond aux uid de la première
850 // face de ce proc.
851 Int64 nb_cell_to_sort = all_csi.size();
852 pm->allGather(Int64ConstArrayView(1,&nb_cell_to_sort),all_first_face_uid);
853
854 Int64 to_add = 0;
855 for( Integer i=0; i<nb_rank; ++i ){
856 Int64 next = all_first_face_uid[i];
857 all_first_face_uid[i] = to_add;
858 to_add += next;
859 }
860 }
861
862 Integer total_nb_to_send = 0;
863 IntegerUniqueArray nb_info_to_send_indexes(nb_rank,0);
864 for( Integer i=0; i<nb_rank; ++i ){
865 nb_info_to_send_indexes[i] = total_nb_to_send;
866 total_nb_to_send += nb_info_to_send[i];
867 }
868 info() << "TOTAL_NB_TO_SEND=" << total_nb_to_send;
869
870 UniqueArray<ResendCellInfo> resend_infos(total_nb_to_send);
871 {
872 for( Integer i=0; i<nb_computed_face; ++i ){
873 const AnyFaceInfo& csi = all_csi[i];
874 Int32 rank0 = csi.m_cell0.rank();
875 Int32 rank1 = csi.m_cell1.rank();
876
877 ResendCellInfo& rci0 = resend_infos[nb_info_to_send_indexes[rank0]];
878 rci0.m_cell_uid = csi.m_cell0.cellUid();
879 rci0.m_face_local_index_and_owner_rank = (csi.m_cell0.faceLocalIndex() * nb_rank) + rank0;
880 rci0.m_index_in_rank_list = i;
881 ++nb_info_to_send_indexes[rank0];
882
883 if (csi.m_cell1.isValid() && rank1!=rank0){
884 ResendCellInfo& rci1 = resend_infos[nb_info_to_send_indexes[rank1]];
885 rci1.m_cell_uid = csi.m_cell1.cellUid();
886 // Meme si je suis la maille 1, le proprietaire de la face sera la maille 0.
887 rci1.m_face_local_index_and_owner_rank = (csi.m_cell1.faceLocalIndex() * nb_rank) + rank0;
888 rci1.m_index_in_rank_list = i;
889 ++nb_info_to_send_indexes[rank1];
890 }
891
892 }
893 }
894
895 // Faire un seul reduce
896 Int64 total_nb_computed_face = pm->reduce(Parallel::ReduceSum,nb_computed_face);
897 info() << "TOTAL_NB_COMPUTED_FACE=" << total_nb_computed_face;
898
899 // Indique a chaque PE combien d'infos je vais lui envoyer
900 if (is_verbose)
901 for( Integer i=0; i<nb_rank; ++i )
902 info() << "NB_TO_SEND: I=" << i << " n=" << nb_info_to_send[i];
903
904 IntegerUniqueArray nb_info_to_recv(nb_rank,0);
905 {
906 Timer::SimplePrinter sp(traceMng(),"Sending size with AllToAll");
907 pm->allToAll(nb_info_to_send,nb_info_to_recv,1);
908 }
909
910 if (is_verbose)
911 for( Integer i=0; i<nb_rank; ++i )
912 info() << "NB_TO_RECV: I=" << i << " n=" << nb_info_to_recv[i];
913
914 Integer total_nb_to_recv = 0;
915 for( Integer i=0; i<nb_rank; ++i )
916 total_nb_to_recv += nb_info_to_recv[i];
917
918 // Il y a de fortes chances que cela ne marche pas si le tableau est trop grand,
919 // il faut proceder avec des tableaux qui ne depassent pas 2Go a cause des
920 // Int32 de MPI.
921 // TODO: Faire le AllToAll en plusieurs fois si besoin.
922 UniqueArray<ResendCellInfo> recv_infos;
923 {
924 Int32 vsize = sizeof(ResendCellInfo) / sizeof(Int64);
925 Int32UniqueArray send_counts(nb_rank);
926 Int32UniqueArray send_indexes(nb_rank);
927 Int32UniqueArray recv_counts(nb_rank);
928 Int32UniqueArray recv_indexes(nb_rank);
929 Int32 total_send = 0;
930 Int32 total_recv = 0;
931 for( Integer i=0; i<nb_rank; ++i ){
932 send_counts[i] = (Int32)(nb_info_to_send[i] * vsize);
933 recv_counts[i] = (Int32)(nb_info_to_recv[i] * vsize);
934 send_indexes[i] = total_send;
935 recv_indexes[i] = total_recv;
936 total_send += send_counts[i];
937 total_recv += recv_counts[i];
938 }
939 recv_infos.resize(total_nb_to_recv);
940
941 Int64ConstArrayView send_buf(total_nb_to_send*vsize,(Int64*)resend_infos.data());
942 Int64ArrayView recv_buf(total_nb_to_recv*vsize,(Int64*)recv_infos.data());
943
944 info() << "BUF_SIZES: send=" << send_buf.size() << " recv=" << recv_buf.size();
945 {
946 Timer::SimplePrinter sp(traceMng(),"Send values with AllToAll");
947 pm->allToAllVariable(send_buf,send_counts,send_indexes,recv_buf,recv_counts,recv_indexes);
948 }
949 }
950
951 // Invalide les uid pour être certain qu'ils seront tous positionnés.
953
954 if (is_verbose){
955 Integer index = 0;
956 for( Int32 rank=0; rank<nb_rank; ++rank ){
957 for( Integer z=0, zs=nb_info_to_recv[rank]; z<zs; ++z ){
958 const ResendCellInfo& rci = recv_infos[index];
959 ++index;
960
961 Int64 cell_uid = rci.m_cell_uid;
962 Int32 full_local_index = rci.m_face_local_index_and_owner_rank;
963 Int32 face_local_index = full_local_index / nb_rank;
964 Int32 owner_rank = full_local_index % nb_rank;
965 Int64 face_uid = all_first_face_uid[rank] + rci.m_index_in_rank_list;
966 info() << "RECV index=" << index << " uid=" << cell_uid
967 << " local_idx=" << full_local_index
968 << " face_local_idx=" << face_local_index
969 << " owner_rank=" << owner_rank
970 << " rank_idx=" << rci.m_index_in_rank_list
971 << " rank="<< rank
972 << " first_face_uid=" << all_first_face_uid[rank]
973 << " computed_uid=" << face_uid;
974 }
975 }
976 }
977
978 // Positionne les uniqueId() et les owner() des faces.
979 {
980 Integer index = 0;
981 for( Int32 i=0; i<nb_rank; ++i ){
982 Int32 rank = i;
983 for( Integer z=0, zs=nb_info_to_recv[i]; z<zs; ++z ){
984 const ResendCellInfo& rci = recv_infos[index];
985 ++index;
986
987 Int64 cell_uid = rci.m_cell_uid;
988 Int32 full_local_index = rci.m_face_local_index_and_owner_rank;
989 Int32 face_local_index = full_local_index / nb_rank;
990 Int32 owner_rank = full_local_index % nb_rank;
991
992 Cell cell = cells_map.tryFind(cell_uid);
993 if (cell.null())
994 ARCANE_FATAL("Can not find cell data for '{0}'",cell_uid);
995 Face face = cell.face(face_local_index);
996 Int64 face_uid = all_first_face_uid[rank] + rci.m_index_in_rank_list;
997 face.mutableItemBase().setUniqueId(face_uid);
998 face.mutableItemBase().setOwner(owner_rank,my_rank);
999 }
1000 }
1001 }
1002
1003 // Vérifie que toutes les faces ont un uid valide
1005}
1006
1007/*---------------------------------------------------------------------------*/
1008/*---------------------------------------------------------------------------*/
1014{
1015 info() << "Compute FacesUniqueId() V5 (experimental)";
1016
1017 IParallelMng* pm = m_parallel_mng;
1018 Int32 my_rank = pm->commRank();
1019 bool is_parallel = pm->isParallel();
1020
1021 ItemInternalMap& faces_map = m_mesh->facesMap();
1023 faces_map.eachItem([&](Face face) {
1024 Int32 nb_node = face.nbNode();
1025 nodes_uid.resize(nb_node);
1026 {
1027 Int32 index = 0;
1028 for (Node node : face.nodes()) {
1029 nodes_uid[index] = node.uniqueId();
1030 ++index;
1031 }
1032 }
1033 Int64 new_face_uid = MeshUtils::generateHashUniqueId(nodes_uid);
1034 face.mutableItemBase().setUniqueId(new_face_uid);
1035 // En parallèle, indique qu'il faudra positionner le owner de cette face
1036 // si elle est frontière.
1037 Int32 new_rank = my_rank;
1038 if (is_parallel && face.nbCell()==1)
1039 new_rank = A_NULL_RANK;
1041 });
1042}
1043
1044/*---------------------------------------------------------------------------*/
1045/*---------------------------------------------------------------------------*/
1051{
1052 ItemInternalMap& faces_map = m_mesh->facesMap();
1053 faces_map.eachItem([&](Item face) {
1054 face.mutableItemBase().unsetUniqueId();
1055 });
1056}
1057
1058/*---------------------------------------------------------------------------*/
1059/*---------------------------------------------------------------------------*/
1065{
1066 ItemInternalMap& faces_map = m_mesh->facesMap();
1067 Integer nb_error = 0;
1068 faces_map.eachItem([&](Face face) {
1069 Int64 face_uid = face.uniqueId();
1070 if (face_uid==NULL_ITEM_UNIQUE_ID){
1071 info() << "Bad face uid cell0=" << face.cell(0).uniqueId();
1072 ++nb_error;
1073 }
1074 });
1075 if (nb_error!=0)
1076 ARCANE_FATAL("Internal error in face uniqueId computation: nb_invalid={0}", nb_error);
1077}
1078
1079/*---------------------------------------------------------------------------*/
1080/*---------------------------------------------------------------------------*/
1081
1082extern "C++" void
1083_computeFaceUniqueIdVersion3(DynamicMesh* mesh)
1084{
1085 FaceUniqueIdBuilder2 f(mesh);
1086 f.computeFacesUniqueIdAndOwnerVersion3();
1087}
1088
1089/*---------------------------------------------------------------------------*/
1090/*---------------------------------------------------------------------------*/
1091
1092extern "C++" void
1093_computeFaceUniqueIdVersion5(DynamicMesh* mesh)
1094{
1095 FaceUniqueIdBuilder2 f(mesh);
1096 f.computeFacesUniqueIdAndOwnerVersion5();
1097}
1098
1099/*---------------------------------------------------------------------------*/
1100/*---------------------------------------------------------------------------*/
1101
1102} // End namespace Arcane::mesh
1103
1104/*---------------------------------------------------------------------------*/
1105/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Maille d'un maillage.
Definition Item.h:1178
FaceConnectedListViewType faces() const
Liste des faces de la maille.
Definition Item.h:1258
Face face(Int32 i) const
i-ème face de la maille
Definition Item.h:1255
Int32 nbFace() const
Nombre de faces de la maille.
Definition Item.h:1252
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
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 allGather(ConstArrayView< char > send_buf, ArrayView< char > recv_buf)=0
Effectue un regroupement sur tous les processeurs. Il s'agit d'une opération collective....
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.
virtual char reduce(eReduceType rt, char v)=0
Effectue la réduction de type rt sur le réel v et retourne la valeur.
Node node(Int32 i) const
i-ème noeud de l'entité
Definition Item.h:768
NodeConnectedListViewType nodes() const
Liste des noeuds de l'entité
Definition Item.h:771
Int32 nbNode() const
Nombre de noeuds de l'entité
Definition Item.h:765
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
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
Definition Item.h:216
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é.
Noeud d'un maillage.
Definition Dom.h:204
Implémentation d'un maillage.
Definition DynamicMesh.h:97
Fonctor pour trier les AnyFaceInfo via le tri bitonic.
Infos pour gérer les faces des sous-domaines.
Fonctor pour trier les BoundaryFaceInfo via le tri bitonic.
Infos pour gérer les faces frontières des sous-domaines.
Stocke les infos sur une face d'une maille.
Stocke les infos sur une face d'une maille.
Construction des uniqueId() des faces.
void _checkFacesUniqueId()
Vérifie que toutes les faces ont un uid valide.
void _unsetFacesUniqueId()
Invalide les uid pour être certain qu'ils seront tous positionnés.
void _computeAndSortBoundaryFaces(Array< BoundaryFaceInfo > &boundary_faces_info)
Détermine la liste des faces frontières de chaque sous-domaine et les trie sur tous les procs.
void _computeParallel()
Calcul les numéros uniques de chaque face en parallèle.
void computeFacesUniqueIdAndOwnerVersion3()
Calcul les numéros uniques de chaque face en parallèle.
void _computeSequential()
Calcul les numéros uniques de chaque face en sequentiel.
FaceUniqueIdBuilder2(DynamicMesh *mesh)
Construit une instance pour le maillage mesh.
void computeFacesUniqueIdAndOwnerVersion5()
Calcule les uniqueId() via un hash généré par les uniqueId() des noeuds.
Tableau associatif de ItemInternal.
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.
Vue constante d'un tableau de type T.
Requête d'un message.
Definition Request.h:77
ITraceMng * traceMng() const
Gestionnaire de trace.
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.
UniqueArray< Int64 > Int64UniqueArray
Tableau dynamique à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:513
ArrayView< Int64 > Int64ArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:609
ConstArrayView< Byte > ByteConstArrayView
Equivalent C d'un tableau à une dimension de caractères.
Definition UtilsTypes.h:634
UniqueArray< Int32 > Int32UniqueArray
Tableau dynamique à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:515
ArrayView< Byte > ByteArrayView
Equivalent C d'un tableau à une dimension de caractères.
Definition UtilsTypes.h:605
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.