Arcane  4.1.11.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-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* FaceUniqueIdBuilder2.cc (C) 2000-2024 */
9/* */
10/* Construction of unique face identifiers. */
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/*---------------------------------------------------------------------------*/
69: public TraceAccessor
70{
71 public:
72
74 class WideCellFaceInfo;
75 class AnyFaceInfo;
76 class BoundaryFaceInfo;
77 class ResendCellInfo;
80 class UniqueIdSorter;
81
82 // Choose the correct typedef depending on the exchange structure choice.
83 typedef NarrowCellFaceInfo CellFaceInfo;
84
85 public:
86
89
90 public:
91
94
95 private:
96
97 DynamicMesh* m_mesh = nullptr;
98 IParallelMng* m_parallel_mng = nullptr;
99 bool m_is_verbose = false;
100
101 private:
102
103 void _resendCellsAndComputeFacesUniqueId(ConstArrayView<AnyFaceInfo> all_csi);
104 void _checkFacesUniqueId();
105 void _unsetFacesUniqueId();
106 void _computeAndSortBoundaryFaces(Array<BoundaryFaceInfo>& boundary_faces_info);
107 void _computeParallel();
108 void _computeSequential();
109};
110
111/*---------------------------------------------------------------------------*/
112/*---------------------------------------------------------------------------*/
139{
140 public:
141
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:
151
152 NarrowCellFaceInfo()
153 {
154 setValue(NULL_ITEM_UNIQUE_ID, -1, -1);
155 }
156
157 public:
158
159 bool isMaxValue() const
160 {
161 Int64 max_id = (MASK_CELL_UID - 1);
162 return cellUid() == max_id;
163 }
164
165 void setMaxValue()
166 {
167 Int64 max_id = (MASK_CELL_UID - 1);
168 setValue(max_id, -1, -1);
169 }
170
171 void setValue(Int64 cell_uid, Int32 _rank, Int32 face_local_index)
172 {
173 Int64 v_fli = face_local_index + 1;
174 Int64 v_rank = _rank + 1;
175 Int64 v_uid = cell_uid + 1;
176 m_value = v_fli << (BITS_CELL_UID + BITS_RANK);
177 m_value += v_rank << (BITS_CELL_UID);
178 m_value += v_uid;
179 if (cellUid() != cell_uid)
180 ARCANE_FATAL("Bad uid expected='{0}' computed='{1}' v={2}", cell_uid, cellUid(), m_value);
181 if (rank() != _rank)
182 ARCANE_FATAL("Bad rank expected='{0}' computed='{1}'", _rank, rank());
183 if (faceLocalIndex() != face_local_index)
184 ARCANE_FATAL("Bad local_index expected='{0}' computed='{1}'", face_local_index, faceLocalIndex());
185 }
186 Int64 cellUid() const { return (m_value & MASK_CELL_UID) - 1; }
187 Int32 rank() const { return CheckedConvert::toInt32(((m_value & MASK_RANK) >> BITS_CELL_UID) - 1); }
188 Int32 faceLocalIndex() const { return CheckedConvert::toInt32(((m_value & MASK_INDEX) >> (BITS_CELL_UID + BITS_RANK)) - 1); }
189
190 bool isValid() const { return cellUid() != NULL_ITEM_UNIQUE_ID; }
191
192 private:
193
194 Int64 m_value = -1;
195};
196
197/*---------------------------------------------------------------------------*/
198/*---------------------------------------------------------------------------*/
203{
204 public:
205
206 WideCellFaceInfo()
207 : m_cell_uid(NULL_ITEM_UNIQUE_ID)
208 , m_rank(-1)
209 , m_face_local_index(-1)
210 {}
211
212 public:
213
214 bool isMaxValue() const
215 {
216 Int64 max_id = INT64_MAX;
217 return cellUid() == max_id;
218 }
219
220 void setMaxValue()
221 {
222 Int64 max_id = INT64_MAX;
223 setValue(max_id, -1, -1);
224 }
225 void setValue(Int64 cell_uid, Int32 rank, Int32 face_local_index)
226 {
227 m_cell_uid = cell_uid;
228 m_rank = rank;
229 m_face_local_index = face_local_index;
230 }
231 Int64 cellUid() const { return m_cell_uid; }
232 Int32 rank() const { return m_rank; }
233 Int32 faceLocalIndex() const { return m_face_local_index; }
234 bool isValid() const { return m_cell_uid != NULL_ITEM_UNIQUE_ID; }
235
236 private:
237
238 Int64 m_cell_uid;
239 Int32 m_rank;
240 Int32 m_face_local_index;
241};
242
243/*---------------------------------------------------------------------------*/
244/*---------------------------------------------------------------------------*/
252{
253 public:
254
255 BoundaryFaceInfo()
256 : m_node0_uid(NULL_ITEM_UNIQUE_ID)
257 , m_node1_uid(NULL_ITEM_UNIQUE_ID)
258 , m_node2_uid(NULL_ITEM_UNIQUE_ID)
259 , m_cell_uid(NULL_ITEM_UNIQUE_ID)
260 , m_rank(-1)
261 , m_face_local_index(-1)
262 {}
263 bool hasSameNodes(const BoundaryFaceInfo& fsi) const
264 {
265 return fsi.m_node0_uid == m_node0_uid && fsi.m_node1_uid == m_node1_uid && fsi.m_node2_uid == m_node2_uid;
266 }
267 void setNodes(Face face)
268 {
269 Integer nb_node = face.nbNode();
270 if (nb_node >= 1)
271 m_node0_uid = face.node(0).uniqueId();
272 if (nb_node >= 2)
273 m_node1_uid = face.node(1).uniqueId();
274 if (nb_node >= 3)
275 m_node2_uid = face.node(2).uniqueId();
276 }
277
278 public:
279
280 Int64 m_node0_uid;
281 Int64 m_node1_uid;
282 Int64 m_node2_uid;
283 Int64 m_cell_uid;
284 Int32 m_rank;
285 Int32 m_face_local_index;
286
287 public:
288};
289
290/*---------------------------------------------------------------------------*/
291/*---------------------------------------------------------------------------*/
300{
301 public:
302
303 AnyFaceInfo() = default;
304
305 public:
306
307 void setCell0(Int64 uid, Int32 rank, Int32 face_local_index)
308 {
309 m_cell0.setValue(uid, rank, face_local_index);
310 }
311 void setCell1(Int64 uid, Int32 rank, Int32 face_local_index)
312 {
313 m_cell1.setValue(uid, rank, face_local_index);
314 }
315
316 public:
317
318 CellFaceInfo m_cell0;
319 CellFaceInfo m_cell1;
320
321 public:
322};
323
324/*---------------------------------------------------------------------------*/
325/*---------------------------------------------------------------------------*/
326
327// Attention, this class must have a size multiple of Int64
329{
330 public:
331
332 Int64 m_cell_uid;
333 // This field contains both the local index of the face in the cell
334 // and the rank of the cell owner.
335 // m_face_local_index_and_owner_rank / nb_rank -> face_index
336 // m_face_local_index_and_owner_rank % nb_rank -> owner_rank
337 Int32 m_face_local_index_and_owner_rank;
338 Int32 m_index_in_rank_list;
339};
340
341/*---------------------------------------------------------------------------*/
342/*---------------------------------------------------------------------------*/
343
344/*---------------------------------------------------------------------------*/
345/*---------------------------------------------------------------------------*/
346
347/*---------------------------------------------------------------------------*/
348/*---------------------------------------------------------------------------*/
353{
354 public:
355
356 static bool compareLess(const BoundaryFaceInfo& k1, const BoundaryFaceInfo& k2)
357 {
358 if (k1.m_node0_uid < k2.m_node0_uid)
359 return true;
360 if (k1.m_node0_uid > k2.m_node0_uid)
361 return false;
362
363 // k1.node0_uid == k2.node0_uid
364 if (k1.m_node1_uid < k2.m_node1_uid)
365 return true;
366 if (k1.m_node1_uid > k2.m_node1_uid)
367 return false;
368
369 // k1.node1_uid == k2.node1_uid
370 if (k1.m_node2_uid < k2.m_node2_uid)
371 return true;
372 if (k1.m_node2_uid > k2.m_node2_uid)
373 return false;
374
375 // k1.node2_uid == k2.node2_uid
376 return (k1.m_cell_uid < k2.m_cell_uid);
377 }
378
380 {
381 const BoundaryFaceInfo* fsi_base = values.data();
382 return pm->send(ByteConstArrayView(messageSize(values), (const Byte*)fsi_base), rank, false);
383 }
385 {
386 BoundaryFaceInfo* fsi_base = values.data();
387 return pm->recv(ByteArrayView(messageSize(values), (Byte*)fsi_base), rank, false);
388 }
389 static Integer messageSize(ConstArrayView<BoundaryFaceInfo> values)
390 {
391 return CheckedConvert::toInteger(values.size() * sizeof(BoundaryFaceInfo));
392 }
393 static BoundaryFaceInfo maxValue()
394 {
396 fsi.m_cell_uid = INT64_MAX;
397 fsi.m_rank = INT32_MAX;
398 fsi.m_node0_uid = INT64_MAX;
399 fsi.m_node1_uid = INT64_MAX;
400 fsi.m_node2_uid = INT64_MAX;
401 return fsi;
402 }
403 static bool isValid(const BoundaryFaceInfo& fsi)
404 {
405 return fsi.m_cell_uid != INT64_MAX;
406 }
407};
408
409/*---------------------------------------------------------------------------*/
410/*---------------------------------------------------------------------------*/
422{
423 public:
424
425 static bool compareLess(const AnyFaceInfo& k1, const AnyFaceInfo& k2)
426 {
427 Int64 k1_cell0_uid = k1.m_cell0.cellUid();
428 Int64 k2_cell0_uid = k2.m_cell0.cellUid();
429 if (k1_cell0_uid < k2_cell0_uid)
430 return true;
431 if (k1_cell0_uid > k2_cell0_uid)
432 return false;
433
434 Int64 k1_face0_local_index = k1.m_cell0.faceLocalIndex();
435 Int64 k2_face0_local_index = k2.m_cell0.faceLocalIndex();
436 if (k1_face0_local_index < k2_face0_local_index)
437 return true;
438 if (k1_face0_local_index > k2_face0_local_index)
439 return false;
440
441 return (k1.m_cell1.cellUid() < k2.m_cell1.cellUid());
442 }
443
445 {
446 const AnyFaceInfo* fsi_base = values.data();
447 Integer message_size = CheckedConvert::toInteger(values.size() * sizeof(AnyFaceInfo));
448 return pm->send(ByteConstArrayView(message_size, (const Byte*)fsi_base), rank, false);
449 }
450
451 static Parallel::Request recv(IParallelMng* pm, Int32 rank, ArrayView<AnyFaceInfo> values)
452 {
453 AnyFaceInfo* fsi_base = values.data();
454 Integer message_size = CheckedConvert::toInteger(values.size() * sizeof(AnyFaceInfo));
455 return pm->recv(ByteArrayView(message_size, (Byte*)fsi_base), rank, false);
456 }
457
458 static AnyFaceInfo maxValue()
459 {
460 AnyFaceInfo csi;
461 csi.m_cell0.setMaxValue();
462 csi.m_cell1.setMaxValue();
463 return csi;
464 }
465
466 static bool isValid(const AnyFaceInfo& csi)
467 {
468 return !csi.m_cell0.isMaxValue();
469 }
470};
471
472/*---------------------------------------------------------------------------*/
473/*---------------------------------------------------------------------------*/
474
476{
477 public:
478
479 bool operator()(const Item& i1, const Item& i2) const
480 {
481 return i1.uniqueId() < i2.uniqueId();
482 }
483};
484
485/*---------------------------------------------------------------------------*/
486/*---------------------------------------------------------------------------*/
487
488/*---------------------------------------------------------------------------*/
489/*---------------------------------------------------------------------------*/
490
494, m_mesh(mesh)
495, m_parallel_mng(mesh->parallelMng())
496{
497}
498
499/*---------------------------------------------------------------------------*/
500/*---------------------------------------------------------------------------*/
501
502/*---------------------------------------------------------------------------*/
503/*---------------------------------------------------------------------------*/
509{
510 if (m_parallel_mng->isParallel())
512 else
514}
515
516/*---------------------------------------------------------------------------*/
517/*---------------------------------------------------------------------------*/
523{
524 info() << "Compute FacesUniqueId() Sequential V3";
525
526 //TODO: allow not to start at zero.
527 Int64 face_unique_id_counter = 0;
528
529 ItemInternalMap& cells_map = m_mesh->cellsMap();
530 Integer nb_cell = cells_map.count();
531 UniqueArray<Cell> cells;
532 cells.reserve(nb_cell);
533 // First, the meshes must be sorted by their uniqueId()
534 // in ascending order
535 cells_map.eachItem([&](Cell item) {
536 cells.add(item);
537 });
538 std::sort(std::begin(cells), std::end(cells), UniqueIdSorter());
539
540 // Invalidate uids to ensure they are all positioned.
542
543 for (Integer i = 0; i < nb_cell; ++i) {
544 Cell cell = cells[i];
545 for (Face face : cell.faces()) {
546 if (face.uniqueId() == NULL_ITEM_UNIQUE_ID) {
547 face.mutableItemBase().setUniqueId(face_unique_id_counter);
548 ++face_unique_id_counter;
549 }
550 }
551 }
552}
553
554/*---------------------------------------------------------------------------*/
555/*---------------------------------------------------------------------------*/
561{
562 IParallelMng* pm = m_parallel_mng;
563 Int32 my_rank = pm->commRank();
564
565 bool is_verbose = m_is_verbose;
566
567 ItemInternalMap& cells_map = m_mesh->cellsMap();
568
569 info() << "Compute FacesUniqueId() V3 using parallel sort";
570
571 // Calculate and sort for boundary faces
572 UniqueArray<BoundaryFaceInfo> boundary_faces_info;
573 _computeAndSortBoundaryFaces(boundary_faces_info);
574
575 // Here, the boundary faces are sorted based on their nodes.
576 // Normally, in this list, 2 consecutive BoundaryFaceInfo elements that
577 // have the same nodes represent the same face. In this case, we generate
578 // an AnyFaceInfo with the information of the two meshes from these two elements of
579 // the list, being careful to put the mesh with the smaller uniqueId() first.
580 // If two consecutive elements of the list do not have the same nodes, it
581 // means that the face is on the edge of the global domain.
582 // We must still handle the case of two consecutive elements of the list
583 // that are located on different processors. To manage this case, each
584 // processor sends the last element of its list to the next one if it cannot
585 // be merged with the second-to-last, in the hope that it can be merged with the
586 // first one of the next processor's list.
587 UniqueArray<AnyFaceInfo> all_face_list;
588 {
589 ConstArrayView<BoundaryFaceInfo> all_fsi = boundary_faces_info;
590 Integer n = all_fsi.size();
591 bool is_last_already_done = false;
592 for (Integer i = 0; i < n; ++i) {
593 const BoundaryFaceInfo& fsi = all_fsi[i];
594 Int64 cell_uid0 = fsi.m_cell_uid;
595 bool is_inside = false;
596 //TODO: handle the case if the previous mesh is on another proc
597 // For this, it is necessary to retrieve the last value of the previous proc
598 // and check if it corresponds to our first value
599 is_inside = ((i + 1) != n && fsi.hasSameNodes(all_fsi[i + 1]));
600 if (is_last_already_done) {
601 is_last_already_done = false;
602 }
603 else {
604 AnyFaceInfo csi;
605 if (is_inside) {
606 const BoundaryFaceInfo& next_fsi = all_fsi[i + 1];
607 Int64 cell_uid1 = next_fsi.m_cell_uid;
608 if (cell_uid0 < cell_uid1) {
609 csi.setCell0(cell_uid0, fsi.m_rank, fsi.m_face_local_index);
610 csi.setCell1(cell_uid1, next_fsi.m_rank, next_fsi.m_face_local_index);
611 }
612 else {
613 csi.setCell0(cell_uid1, next_fsi.m_rank, next_fsi.m_face_local_index);
614 csi.setCell1(cell_uid0, fsi.m_rank, fsi.m_face_local_index);
615 }
616 is_last_already_done = true;
617 }
618 else {
619 csi.setCell0(cell_uid0, fsi.m_rank, fsi.m_face_local_index);
620 }
621 all_face_list.add(csi);
622 }
623 if (is_verbose)
624 info() << "FACES_KEY i=" << i
625 << " n0=" << fsi.m_node0_uid
626 << " n1=" << fsi.m_node1_uid
627 << " n2=" << fsi.m_node2_uid
628 << " cell=" << fsi.m_cell_uid
629 << " rank=" << fsi.m_rank
630 << " li=" << fsi.m_face_local_index
631 << " in=" << is_inside;
632 }
633 }
634
635 // Add the faces belonging to our sub-domain.
636 // These are all faces that have 2 connected meshes.
637 cells_map.eachItem([&](Cell cell) {
638 Integer cell_nb_face = cell.nbFace();
639 Int64 cell_uid = cell.uniqueId();
640 for (Integer z = 0; z < cell_nb_face; ++z) {
641 Face face = cell.face(z);
642 if (face.nbCell() != 2)
643 continue;
644 Cell cell0 = face.cell(0);
645 Cell cell1 = face.cell(1);
646 Cell next_cell = (cell0 == cell) ? cell1 : cell0;
647 Int64 next_cell_uid = next_cell.uniqueId();
648 // Only record if I am the mesh with the smaller uid
649 if (cell_uid < next_cell_uid) {
650 AnyFaceInfo csi;
651 csi.m_cell0.setValue(cell_uid, my_rank, z);
652 // The face_local_index of mesh 1 will not be used
653 csi.m_cell1.setValue(next_cell_uid, my_rank, -1);
654 all_face_list.add(csi);
655 }
656 }
657 });
658
659 if (is_verbose) {
660 Integer n = all_face_list.size();
661 for (Integer i = 0; i < n; ++i) {
662 const AnyFaceInfo& csi = all_face_list[i];
663 info() << "CELL_TO_SORT i=" << i
664 << " cell0=" << csi.m_cell0.cellUid()
665 << " lidx0=" << csi.m_cell0.faceLocalIndex()
666 << " cell1=" << csi.m_cell1.cellUid();
667 }
668 }
669
670 info() << "ALL_FACE_LIST memorysize=" << sizeof(AnyFaceInfo) * all_face_list.size();
672 all_face_sorter.setNeedIndexAndRank(false);
673 Real sort_begin_time = platform::getRealTime();
674 all_face_sorter.sort(all_face_list);
675 Real sort_end_time = platform::getRealTime();
676 info() << "END_ALL_FACE_SORTER time=" << (Real)(sort_end_time - sort_begin_time);
677
678 _resendCellsAndComputeFacesUniqueId(all_face_sorter.keys());
679}
680
681/*---------------------------------------------------------------------------*/
682/*---------------------------------------------------------------------------*/
689{
690 IParallelMng* pm = m_parallel_mng;
691 Int32 my_rank = pm->commRank();
692 bool is_verbose = m_is_verbose;
693 ItemInternalMap& faces_map = m_mesh->facesMap();
694
696 boundary_face_sorter.setNeedIndexAndRank(false);
697
698 //UniqueArray<BoundaryFaceInfo> boundary_face_list;
699 boundary_faces_info.clear();
700 faces_map.eachItem([&](Face face) {
702 Integer nb_cell = face.nbCell();
703 if (nb_cell == 2)
704 return;
705
706 fsi.m_rank = my_rank;
707 fsi.setNodes(face);
708 Cell cell = face.cell(0);
709 fsi.m_cell_uid = cell.uniqueId();
710 Integer face_local_index = 0;
711 for (Integer z = 0, zs = cell.nbFace(); z < zs; ++z)
712 if (cell.face(z) == face) {
713 face_local_index = z;
714 break;
715 }
716 fsi.m_face_local_index = face_local_index;
717 boundary_faces_info.add(fsi);
718 });
719
720 if (is_verbose) {
721 ConstArrayView<BoundaryFaceInfo> all_fsi = boundary_faces_info;
722 Integer n = all_fsi.size();
723 for (Integer i = 0; i < n; ++i) {
724 const BoundaryFaceInfo& fsi = all_fsi[i];
725 info() << "KEY i=" << i
726 << " n0=" << fsi.m_node0_uid
727 << " n1=" << fsi.m_node1_uid
728 << " n2=" << fsi.m_node2_uid
729 << " cell=" << fsi.m_cell_uid
730 << " rank=" << fsi.m_rank
731 << " li=" << fsi.m_face_local_index;
732 }
733 }
734
735 Real sort_begin_time = platform::getRealTime();
736 boundary_face_sorter.sort(boundary_faces_info);
737 Real sort_end_time = platform::getRealTime();
738 info() << "END_BOUNDARY_FACE_SORT time=" << (Real)(sort_end_time - sort_begin_time);
739
740 {
741 ConstArrayView<BoundaryFaceInfo> all_bfi = boundary_face_sorter.keys();
742 Integer n = all_bfi.size();
743 if (is_verbose) {
744 for (Integer i = 0; i < n; ++i) {
745 const BoundaryFaceInfo& bfi = all_bfi[i];
746 info() << " AFTER KEY i=" << i
747 << " n0=" << bfi.m_node0_uid
748 << " n1=" << bfi.m_node1_uid
749 << " n2=" << bfi.m_node2_uid
750 << " cell=" << bfi.m_cell_uid
751 << " rank=" << bfi.m_rank
752 << " li=" << bfi.m_face_local_index;
753 }
754 }
755
756 // As a single node may be present in the previous proc's list, each PE
757 // (except 0) sends to the previous process the start of its list which contains the same nodes.
758
759 // TODO: merge this code with that of GhostLayerBuilder2
760 UniqueArray<BoundaryFaceInfo> end_face_list;
761 Integer begin_own_list_index = 0;
762 if (n != 0 && my_rank != 0) {
763 if (BoundaryFaceBitonicSortTraits::isValid(all_bfi[0])) {
764 Int64 node0_uid = all_bfi[0].m_node0_uid;
765 for (Integer i = 0; i < n; ++i) {
766 if (all_bfi[i].m_node0_uid != node0_uid) {
767 begin_own_list_index = i;
768 break;
769 }
770 else
771 end_face_list.add(all_bfi[i]);
772 }
773 }
774 }
775 info() << "BEGIN_OWN_LIST_INDEX=" << begin_own_list_index;
776 if (is_verbose) {
777 for (Integer k = 0, kn = end_face_list.size(); k < kn; ++k)
778 info() << " SEND n0=" << end_face_list[k].m_node0_uid
779 << " n1=" << end_face_list[k].m_node1_uid
780 << " n2=" << end_face_list[k].m_node2_uid;
781 }
782
783 UniqueArray<BoundaryFaceInfo> end_face_list_recv;
784
786 Integer recv_message_size = 0;
787 Integer send_message_size = BoundaryFaceBitonicSortTraits::messageSize(end_face_list);
788
789 Int32 nb_rank = pm->commSize();
790
791 // First sends and receives the sizes.
792 if (my_rank != (nb_rank - 1)) {
793 requests.add(pm->recv(IntegerArrayView(1, &recv_message_size), my_rank + 1, false));
794 }
795 if (my_rank != 0) {
796 requests.add(pm->send(IntegerConstArrayView(1, &send_message_size), my_rank - 1, false));
797 }
798
799 pm->waitAllRequests(requests);
800 requests.clear();
801
802 if (recv_message_size != 0) {
803 Integer message_size = CheckedConvert::toInteger(recv_message_size / sizeof(BoundaryFaceInfo));
804 end_face_list_recv.resize(message_size);
805 requests.add(BoundaryFaceBitonicSortTraits::recv(pm, my_rank + 1, end_face_list_recv));
806 }
807 if (send_message_size != 0)
808 requests.add(BoundaryFaceBitonicSortTraits::send(pm, my_rank - 1, end_face_list));
809
810 pm->waitAllRequests(requests);
811
812 boundary_faces_info.clear();
813 boundary_faces_info.addRange(all_bfi.subConstView(begin_own_list_index, n - begin_own_list_index));
814 boundary_faces_info.addRange(end_face_list_recv);
815 }
816}
817
818/*---------------------------------------------------------------------------*/
819/*---------------------------------------------------------------------------*/
820
821void FaceUniqueIdBuilder2::
822_resendCellsAndComputeFacesUniqueId(ConstArrayView<AnyFaceInfo> all_csi)
823{
824 IParallelMng* pm = m_parallel_mng;
825 Int32 nb_rank = pm->commSize();
826 Int32 my_rank = pm->commRank();
827 bool is_verbose = m_is_verbose;
828
829 ItemInternalMap& cells_map = m_mesh->cellsMap();
830
831 Int64 nb_computed_face = all_csi.size();
832
833 if (is_verbose) {
834 for (Integer i = 0; i < nb_computed_face; ++i) {
835 const AnyFaceInfo& csi = all_csi[i];
836 info() << "CELLS_KEY i=" << i
837 << " cell0=" << csi.m_cell0.cellUid()
838 << " lidx0=" << csi.m_cell0.faceLocalIndex()
839 << " cell1=" << csi.m_cell1.cellUid()
840 << " lidx1=" << csi.m_cell1.faceLocalIndex()
841 << " rank0=" << csi.m_cell0.rank()
842 << " rank1=" << csi.m_cell1.rank();
843 }
844 }
845
846 // Calculation for each rank of the number of values to send
847 // and stores it in nb_info_to_send;
848 IntegerUniqueArray nb_info_to_send(nb_rank, 0);
849 {
850 for (Integer i = 0; i < nb_computed_face; ++i) {
851 const AnyFaceInfo& csi = all_csi[i];
852 Int32 rank0 = csi.m_cell0.rank();
853 Int32 rank1 = csi.m_cell1.rank();
854
855 ++nb_info_to_send[rank0];
856
857 // It must only be sent if the rank is different from m_rank0
858 if (csi.m_cell1.isValid() && rank1 != rank0)
859 ++nb_info_to_send[rank1];
860 }
861 }
862
863 // Array for each process indicating the uniqueId() of the first
864 // face of this process.
865 Int64UniqueArray all_first_face_uid(nb_rank);
866 {
867 // Each process retrieves the number of meshes in the list.
868 // Since this list will be sorted, this corresponds to the uid of the first
869 // face of this process.
870 Int64 nb_cell_to_sort = all_csi.size();
871 pm->allGather(Int64ConstArrayView(1, &nb_cell_to_sort), all_first_face_uid);
872
873 Int64 to_add = 0;
874 for (Integer i = 0; i < nb_rank; ++i) {
875 Int64 next = all_first_face_uid[i];
876 all_first_face_uid[i] = to_add;
877 to_add += next;
878 }
879 }
880
881 Integer total_nb_to_send = 0;
882 IntegerUniqueArray nb_info_to_send_indexes(nb_rank, 0);
883 for (Integer i = 0; i < nb_rank; ++i) {
884 nb_info_to_send_indexes[i] = total_nb_to_send;
885 total_nb_to_send += nb_info_to_send[i];
886 }
887 info() << "TOTAL_NB_TO_SEND=" << total_nb_to_send;
888
889 UniqueArray<ResendCellInfo> resend_infos(total_nb_to_send);
890 {
891 for (Integer i = 0; i < nb_computed_face; ++i) {
892 const AnyFaceInfo& csi = all_csi[i];
893 Int32 rank0 = csi.m_cell0.rank();
894 Int32 rank1 = csi.m_cell1.rank();
895
896 ResendCellInfo& rci0 = resend_infos[nb_info_to_send_indexes[rank0]];
897 rci0.m_cell_uid = csi.m_cell0.cellUid();
898 rci0.m_face_local_index_and_owner_rank = (csi.m_cell0.faceLocalIndex() * nb_rank) + rank0;
899 rci0.m_index_in_rank_list = i;
900 ++nb_info_to_send_indexes[rank0];
901
902 if (csi.m_cell1.isValid() && rank1 != rank0) {
903 ResendCellInfo& rci1 = resend_infos[nb_info_to_send_indexes[rank1]];
904 rci1.m_cell_uid = csi.m_cell1.cellUid();
905 // Even if I am mesh 1, the owner of the face will be mesh 0.
906 rci1.m_face_local_index_and_owner_rank = (csi.m_cell1.faceLocalIndex() * nb_rank) + rank0;
907 rci1.m_index_in_rank_list = i;
908 ++nb_info_to_send_indexes[rank1];
909 }
910 }
911 }
912
913 // Perform a single reduce
914 Int64 total_nb_computed_face = pm->reduce(Parallel::ReduceSum, nb_computed_face);
915 info() << "TOTAL_NB_COMPUTED_FACE=" << total_nb_computed_face;
916
917 // Indicates to each PE how many infos I will send to it
918 if (is_verbose)
919 for (Integer i = 0; i < nb_rank; ++i)
920 info() << "NB_TO_SEND: I=" << i << " n=" << nb_info_to_send[i];
921
922 IntegerUniqueArray nb_info_to_recv(nb_rank, 0);
923 {
924 Timer::SimplePrinter sp(traceMng(), "Sending size with AllToAll");
925 pm->allToAll(nb_info_to_send, nb_info_to_recv, 1);
926 }
927
928 if (is_verbose)
929 for (Integer i = 0; i < nb_rank; ++i)
930 info() << "NB_TO_RECV: I=" << i << " n=" << nb_info_to_recv[i];
931
932 Integer total_nb_to_recv = 0;
933 for (Integer i = 0; i < nb_rank; ++i)
934 total_nb_to_recv += nb_info_to_recv[i];
935
936 // It is highly likely that this will not work if the array is too large,
937 // it must proceed with arrays that do not exceed 2Go because of the
938 // Int32 of MPI.
939 // TODO: Perform the AllToAll multiple times if necessary.
940 UniqueArray<ResendCellInfo> recv_infos;
941 {
942 Int32 vsize = sizeof(ResendCellInfo) / sizeof(Int64);
943 Int32UniqueArray send_counts(nb_rank);
944 Int32UniqueArray send_indexes(nb_rank);
945 Int32UniqueArray recv_counts(nb_rank);
946 Int32UniqueArray recv_indexes(nb_rank);
947 Int32 total_send = 0;
948 Int32 total_recv = 0;
949 for (Integer i = 0; i < nb_rank; ++i) {
950 send_counts[i] = (Int32)(nb_info_to_send[i] * vsize);
951 recv_counts[i] = (Int32)(nb_info_to_recv[i] * vsize);
952 send_indexes[i] = total_send;
953 recv_indexes[i] = total_recv;
954 total_send += send_counts[i];
955 total_recv += recv_counts[i];
956 }
957 recv_infos.resize(total_nb_to_recv);
958
959 Int64ConstArrayView send_buf(total_nb_to_send * vsize, (Int64*)resend_infos.data());
960 Int64ArrayView recv_buf(total_nb_to_recv * vsize, (Int64*)recv_infos.data());
961
962 info() << "BUF_SIZES: send=" << send_buf.size() << " recv=" << recv_buf.size();
963 {
964 Timer::SimplePrinter sp(traceMng(), "Send values with AllToAll");
965 pm->allToAllVariable(send_buf, send_counts, send_indexes, recv_buf, recv_counts, recv_indexes);
966 }
967 }
968
969 // Invalidates the uids to ensure they will all be positioned.
971
972 if (is_verbose) {
973 Integer index = 0;
974 for (Int32 rank = 0; rank < nb_rank; ++rank) {
975 for (Integer z = 0, zs = nb_info_to_recv[rank]; z < zs; ++z) {
976 const ResendCellInfo& rci = recv_infos[index];
977 ++index;
978
979 Int64 cell_uid = rci.m_cell_uid;
980 Int32 full_local_index = rci.m_face_local_index_and_owner_rank;
981 Int32 face_local_index = full_local_index / nb_rank;
982 Int32 owner_rank = full_local_index % nb_rank;
983 Int64 face_uid = all_first_face_uid[rank] + rci.m_index_in_rank_list;
984 info() << "RECV index=" << index << " uid=" << cell_uid
985 << " local_idx=" << full_local_index
986 << " face_local_idx=" << face_local_index
987 << " owner_rank=" << owner_rank
988 << " rank_idx=" << rci.m_index_in_rank_list
989 << " rank=" << rank
990 << " first_face_uid=" << all_first_face_uid[rank]
991 << " computed_uid=" << face_uid;
992 }
993 }
994 }
995
996 // Positions the uniqueId() and the owner() of the faces.
997 {
998 Integer index = 0;
999 for (Int32 i = 0; i < nb_rank; ++i) {
1000 Int32 rank = i;
1001 for (Integer z = 0, zs = nb_info_to_recv[i]; z < zs; ++z) {
1002 const ResendCellInfo& rci = recv_infos[index];
1003 ++index;
1004
1005 Int64 cell_uid = rci.m_cell_uid;
1006 Int32 full_local_index = rci.m_face_local_index_and_owner_rank;
1007 Int32 face_local_index = full_local_index / nb_rank;
1008 Int32 owner_rank = full_local_index % nb_rank;
1009
1010 Cell cell = cells_map.tryFind(cell_uid);
1011 if (cell.null())
1012 ARCANE_FATAL("Can not find cell data for '{0}'", cell_uid);
1013 Face face = cell.face(face_local_index);
1014 Int64 face_uid = all_first_face_uid[rank] + rci.m_index_in_rank_list;
1015 face.mutableItemBase().setUniqueId(face_uid);
1016 face.mutableItemBase().setOwner(owner_rank, my_rank);
1017 }
1018 }
1019 }
1020
1021 // Checks that all faces have a valid uid
1023}
1024
1025/*---------------------------------------------------------------------------*/
1026/*---------------------------------------------------------------------------*/
1032{
1033 info() << "Compute FacesUniqueId() V5 (experimental)";
1034
1035 IParallelMng* pm = m_parallel_mng;
1036 Int32 my_rank = pm->commRank();
1037 bool is_parallel = pm->isParallel();
1038
1039 ItemInternalMap& faces_map = m_mesh->facesMap();
1040 UniqueArray<Int64> nodes_uid;
1041 faces_map.eachItem([&](Face face) {
1042 Int32 nb_node = face.nbNode();
1043 nodes_uid.resize(nb_node);
1044 {
1045 Int32 index = 0;
1046 for (Node node : face.nodes()) {
1047 nodes_uid[index] = node.uniqueId();
1048 ++index;
1049 }
1050 }
1051 Int64 new_face_uid = MeshUtils::generateHashUniqueId(nodes_uid);
1052 face.mutableItemBase().setUniqueId(new_face_uid);
1053 // In parallel, indicates that the owner of this face must be positioned
1054 // if it is a boundary face.
1055 Int32 new_rank = my_rank;
1056 if (is_parallel && face.nbCell() == 1)
1057 new_rank = A_NULL_RANK;
1058 face.mutableItemBase().setOwner(new_rank, my_rank);
1059 });
1060}
1061
1062/*---------------------------------------------------------------------------*/
1063/*---------------------------------------------------------------------------*/
1069{
1070 ItemInternalMap& faces_map = m_mesh->facesMap();
1071 faces_map.eachItem([&](Item face) {
1073 });
1074}
1075
1076/*---------------------------------------------------------------------------*/
1077/*---------------------------------------------------------------------------*/
1083{
1084 ItemInternalMap& faces_map = m_mesh->facesMap();
1085 Integer nb_error = 0;
1086 faces_map.eachItem([&](Face face) {
1087 Int64 face_uid = face.uniqueId();
1088 if (face_uid == NULL_ITEM_UNIQUE_ID) {
1089 info() << "Bad face uid cell0=" << face.cell(0).uniqueId();
1090 ++nb_error;
1091 }
1092 });
1093 if (nb_error != 0)
1094 ARCANE_FATAL("Internal error in face uniqueId computation: nb_invalid={0}", nb_error);
1095}
1096
1097/*---------------------------------------------------------------------------*/
1098/*---------------------------------------------------------------------------*/
1099
1100extern "C++" void
1101_computeFaceUniqueIdVersion3(DynamicMesh* mesh)
1102{
1104 f.computeFacesUniqueIdAndOwnerVersion3();
1105}
1106
1107/*---------------------------------------------------------------------------*/
1108/*---------------------------------------------------------------------------*/
1109
1110extern "C++" void
1111_computeFaceUniqueIdVersion5(DynamicMesh* mesh)
1112{
1113 FaceUniqueIdBuilder2 f(mesh);
1114 f.computeFacesUniqueIdAndOwnerVersion5();
1115}
1116
1117/*---------------------------------------------------------------------------*/
1118/*---------------------------------------------------------------------------*/
1119
1120} // End namespace Arcane::mesh
1121
1122/*---------------------------------------------------------------------------*/
1123/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Int64 generateHashUniqueId(SmallSpan< const Int64 > nodes_unique_id)
Génère un identifiant unique à partir d'une liste d'identifiants de noeuds.
Integer size() const
Nombre d'éléments du vecteur.
Vue modifiable d'un tableau d'un type T.
constexpr const_pointer data() const noexcept
Pointeur sur le début de la vue.
constexpr Integer size() const noexcept
Retourne la taille du tableau.
Tableau d'items de types quelconques.
void clear()
Supprime les éléments du tableau.
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.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
Maille d'un maillage.
Definition Item.h:1214
FaceConnectedListViewType faces() const
Liste des faces de la maille.
Definition Item.h:1298
Face face(Int32 i) const
i-ème face de la maille
Definition Item.h:1295
Int32 nbFace() const
Nombre de faces de la maille.
Definition Item.h:1292
Vue constante d'un tableau de type T.
constexpr const_pointer data() const noexcept
Pointeur sur la mémoire allouée.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
constexpr ConstArrayView< T > subConstView(Integer abegin, Integer asize) const noexcept
Sous-vue (constante) à partir de l'élément abegin et contenant asize éléments.
Face d'une maille.
Definition Item.h:964
Cell cell(Int32 i) const
i-ème maille de la face
Definition Item.h:1665
Int32 nbCell() const
Nombre de mailles de la face (1 ou 2).
Definition Item.h:1042
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:791
NodeConnectedListViewType nodes() const
Liste des noeuds de l'entité
Definition Item.h:794
Int32 nbNode() const
Nombre de noeuds de l'entité
Definition Item.h:788
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:380
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
Definition Item.h:225
Requête d'un message.
Definition Request.h:77
void setOwner(Integer suid, Int32 current_sub_domain)
Positionne le numéro du sous-domaine propriétaire de l'entité.
void unsetUniqueId()
Annule l'uniqueId a la valeur NULL_ITEM_UNIQUE_ID.
Noeud d'un maillage.
Definition Item.h:582
Algorithme de tri bi-tonique parallèle.
ConstArrayView< KeyType > keys() const override
Après un tri, retourne la liste des éléments de ce rang.
void sort(ConstArrayView< KeyType > keys) override
Trie en parallèle les éléments de keys sur tous les rangs.
TraceAccessor(ITraceMng *m)
Construit un accesseur via le gestionnaire de trace m.
TraceMessage info() const
Flot pour un message d'information.
ITraceMng * traceMng() const
Gestionnaire de trace.
Vecteur 1D de données avec sémantique par valeur (style STL).
Implementation of a mesh.
Definition DynamicMesh.h:98
Functor for sorting AnyFaceInfo using bitonic sort.
Info for managing faces of sub-domains.
Functor for sorting BoundaryFaceInfo via bitonic sort.
Info for managing boundary faces of sub-domains.
Construction of the uniqueId() for faces.
void _checkFacesUniqueId()
Checks that all faces have a valid uid.
void _unsetFacesUniqueId()
Invalidates the uids to ensure they are all positioned.
void _computeAndSortBoundaryFaces(Array< BoundaryFaceInfo > &boundary_faces_info)
Determines the list of boundary faces for each subdomain and sorts them across all procs.
void _computeParallel()
Calculates the unique IDs of each face in parallel.
void computeFacesUniqueIdAndOwnerVersion3()
Calculates the unique IDs of each face in parallel.
void _computeSequential()
Calculates the unique IDs of each face sequentially.
FaceUniqueIdBuilder2(DynamicMesh *mesh)
Constructs an instance for the mesh mesh.
void computeFacesUniqueIdAndOwnerVersion5()
Calculates uniqueId() via a hash generated by the uniqueId() of the nodes.
Associative array of ItemInternal.
void eachItem(const Lambda &lambda)
Template function to iterate over the instance's entities.
impl::ItemBase tryFind(Int64 key) const
Returns the entity associated with key if found, or the null entity otherwise.
Int32 count() const
Number of elements in the table.
@ ReduceSum
Somme des valeurs.
Real getRealTime()
Temps Real utilisé en secondes.
ArrayView< Int64 > Int64ArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:451
UniqueArray< Int64 > Int64UniqueArray
Tableau dynamique à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:339
ArrayView< Byte > ByteArrayView
Equivalent C d'un tableau à une dimension de caractères.
Definition UtilsTypes.h:447
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
ArrayView< Integer > IntegerArrayView
Equivalent C d'un tableau à une dimension d'entiers.
Definition UtilsTypes.h:457
ConstArrayView< Int64 > Int64ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:480
UniqueArray< Int32 > Int32UniqueArray
Tableau dynamique à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:341
double Real
Type représentant un réel.
ConstArrayView< Byte > ByteConstArrayView
Equivalent C d'un tableau à une dimension de caractères.
Definition UtilsTypes.h:476
unsigned char Byte
Type d'un octet.
Definition BaseTypes.h:43
UniqueArray< Integer > IntegerUniqueArray
Tableau dynamique à une dimension d'entiers.
Definition UtilsTypes.h:347
ConstArrayView< Integer > IntegerConstArrayView
Equivalent C d'un tableau à une dimension d'entiers.
Definition UtilsTypes.h:486
@ Cell
Le maillage est AMR par maille.
Definition MeshKind.h:52
std::int32_t Int32
Type entier signé sur 32 bits.