Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
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/*---------------------------------------------------------------------------*/
113
140{
141 public:
142
143 static const Int64 BITS_CELL_UID = 39;
144 static const Int64 BITS_RANK = 20;
145 static const Int64 BITS_INDEX = 5;
146 static const Int64 ONE_INT64 = 1;
147 static const Int64 MASK_CELL_UID = (ONE_INT64 << BITS_CELL_UID) - 1;
148 static const Int64 MASK_RANK = ((ONE_INT64 << BITS_RANK) - 1) << BITS_CELL_UID;
149 static const Int64 MASK_INDEX = ((ONE_INT64 << BITS_INDEX) - 1) << (BITS_CELL_UID + BITS_RANK);
150
151 public:
152
153 NarrowCellFaceInfo()
154 {
155 setValue(NULL_ITEM_UNIQUE_ID, -1, -1);
156 }
157
158 public:
159
160 bool isMaxValue() const
161 {
162 Int64 max_id = (MASK_CELL_UID - 1);
163 return cellUid() == max_id;
164 }
165
166 void setMaxValue()
167 {
168 Int64 max_id = (MASK_CELL_UID - 1);
169 setValue(max_id, -1, -1);
170 }
171
172 void setValue(Int64 cell_uid, Int32 _rank, Int32 face_local_index)
173 {
174 Int64 v_fli = face_local_index + 1;
175 Int64 v_rank = _rank + 1;
176 Int64 v_uid = cell_uid + 1;
177 m_value = v_fli << (BITS_CELL_UID + BITS_RANK);
178 m_value += v_rank << (BITS_CELL_UID);
179 m_value += v_uid;
180 if (cellUid() != cell_uid)
181 ARCANE_FATAL("Bad uid expected='{0}' computed='{1}' v={2}", cell_uid, cellUid(), m_value);
182 if (rank() != _rank)
183 ARCANE_FATAL("Bad rank expected='{0}' computed='{1}'", _rank, rank());
184 if (faceLocalIndex() != face_local_index)
185 ARCANE_FATAL("Bad local_index expected='{0}' computed='{1}'", face_local_index, faceLocalIndex());
186 }
187 Int64 cellUid() const { return (m_value & MASK_CELL_UID) - 1; }
188 Int32 rank() const { return CheckedConvert::toInt32(((m_value & MASK_RANK) >> BITS_CELL_UID) - 1); }
189 Int32 faceLocalIndex() const { return CheckedConvert::toInt32(((m_value & MASK_INDEX) >> (BITS_CELL_UID + BITS_RANK)) - 1); }
190
191 bool isValid() const { return cellUid() != NULL_ITEM_UNIQUE_ID; }
192
193 private:
194
195 Int64 m_value = -1;
196};
197
198/*---------------------------------------------------------------------------*/
199/*---------------------------------------------------------------------------*/
200
205{
206 public:
207
208 WideCellFaceInfo()
209 : m_cell_uid(NULL_ITEM_UNIQUE_ID)
210 , m_rank(-1)
211 , m_face_local_index(-1)
212 {}
213
214 public:
215
216 bool isMaxValue() const
217 {
218 Int64 max_id = INT64_MAX;
219 return cellUid() == max_id;
220 }
221
222 void setMaxValue()
223 {
224 Int64 max_id = INT64_MAX;
225 setValue(max_id, -1, -1);
226 }
227 void setValue(Int64 cell_uid, Int32 rank, Int32 face_local_index)
228 {
229 m_cell_uid = cell_uid;
230 m_rank = rank;
231 m_face_local_index = face_local_index;
232 }
233 Int64 cellUid() const { return m_cell_uid; }
234 Int32 rank() const { return m_rank; }
235 Int32 faceLocalIndex() const { return m_face_local_index; }
236 bool isValid() const { return m_cell_uid != NULL_ITEM_UNIQUE_ID; }
237
238 private:
239
240 Int64 m_cell_uid;
241 Int32 m_rank;
242 Int32 m_face_local_index;
243};
244
245/*---------------------------------------------------------------------------*/
246/*---------------------------------------------------------------------------*/
254{
255 public:
256
257 BoundaryFaceInfo()
258 : m_node0_uid(NULL_ITEM_UNIQUE_ID)
259 , m_node1_uid(NULL_ITEM_UNIQUE_ID)
260 , m_node2_uid(NULL_ITEM_UNIQUE_ID)
261 , m_cell_uid(NULL_ITEM_UNIQUE_ID)
262 , m_rank(-1)
263 , m_face_local_index(-1)
264 {}
265 bool hasSameNodes(const BoundaryFaceInfo& fsi) const
266 {
267 return fsi.m_node0_uid == m_node0_uid && fsi.m_node1_uid == m_node1_uid && fsi.m_node2_uid == m_node2_uid;
268 }
269 void setNodes(Face face)
270 {
271 Integer nb_node = face.nbNode();
272 if (nb_node >= 1)
273 m_node0_uid = face.node(0).uniqueId();
274 if (nb_node >= 2)
275 m_node1_uid = face.node(1).uniqueId();
276 if (nb_node >= 3)
277 m_node2_uid = face.node(2).uniqueId();
278 }
279
280 public:
281
282 Int64 m_node0_uid;
283 Int64 m_node1_uid;
284 Int64 m_node2_uid;
285 Int64 m_cell_uid;
286 Int32 m_rank;
287 Int32 m_face_local_index;
288
289 public:
290};
291
292/*---------------------------------------------------------------------------*/
293/*---------------------------------------------------------------------------*/
302{
303 public:
304
305 AnyFaceInfo() = default;
306
307 public:
308
309 void setCell0(Int64 uid, Int32 rank, Int32 face_local_index)
310 {
311 m_cell0.setValue(uid, rank, face_local_index);
312 }
313 void setCell1(Int64 uid, Int32 rank, Int32 face_local_index)
314 {
315 m_cell1.setValue(uid, rank, face_local_index);
316 }
317
318 public:
319
320 CellFaceInfo m_cell0;
321 CellFaceInfo m_cell1;
322
323 public:
324};
325
326/*---------------------------------------------------------------------------*/
327/*---------------------------------------------------------------------------*/
328
329// Attention, this class must have a size multiple of Int64
331{
332 public:
333
334 Int64 m_cell_uid;
335 // This field contains both the local index of the face in the cell
336 // and the rank of the cell owner.
337 // m_face_local_index_and_owner_rank / nb_rank -> face_index
338 // m_face_local_index_and_owner_rank % nb_rank -> owner_rank
339 Int32 m_face_local_index_and_owner_rank;
340 Int32 m_index_in_rank_list;
341};
342
343/*---------------------------------------------------------------------------*/
344/*---------------------------------------------------------------------------*/
345
346/*---------------------------------------------------------------------------*/
347/*---------------------------------------------------------------------------*/
348
349/*---------------------------------------------------------------------------*/
350/*---------------------------------------------------------------------------*/
355{
356 public:
357
358 static bool compareLess(const BoundaryFaceInfo& k1, const BoundaryFaceInfo& k2)
359 {
360 if (k1.m_node0_uid < k2.m_node0_uid)
361 return true;
362 if (k1.m_node0_uid > k2.m_node0_uid)
363 return false;
364
365 // k1.node0_uid == k2.node0_uid
366 if (k1.m_node1_uid < k2.m_node1_uid)
367 return true;
368 if (k1.m_node1_uid > k2.m_node1_uid)
369 return false;
370
371 // k1.node1_uid == k2.node1_uid
372 if (k1.m_node2_uid < k2.m_node2_uid)
373 return true;
374 if (k1.m_node2_uid > k2.m_node2_uid)
375 return false;
376
377 // k1.node2_uid == k2.node2_uid
378 return (k1.m_cell_uid < k2.m_cell_uid);
379 }
380
382 {
383 const BoundaryFaceInfo* fsi_base = values.data();
384 return pm->send(ByteConstArrayView(messageSize(values), (const Byte*)fsi_base), rank, false);
385 }
387 {
388 BoundaryFaceInfo* fsi_base = values.data();
389 return pm->recv(ByteArrayView(messageSize(values), (Byte*)fsi_base), rank, false);
390 }
391 static Integer messageSize(ConstArrayView<BoundaryFaceInfo> values)
392 {
393 return CheckedConvert::toInteger(values.size() * sizeof(BoundaryFaceInfo));
394 }
395 static BoundaryFaceInfo maxValue()
396 {
398 fsi.m_cell_uid = INT64_MAX;
399 fsi.m_rank = INT32_MAX;
400 fsi.m_node0_uid = INT64_MAX;
401 fsi.m_node1_uid = INT64_MAX;
402 fsi.m_node2_uid = INT64_MAX;
403 return fsi;
404 }
405 static bool isValid(const BoundaryFaceInfo& fsi)
406 {
407 return fsi.m_cell_uid != INT64_MAX;
408 }
409};
410
411/*---------------------------------------------------------------------------*/
412/*---------------------------------------------------------------------------*/
413
426{
427 public:
428
429 static bool compareLess(const AnyFaceInfo& k1, const AnyFaceInfo& k2)
430 {
431 Int64 k1_cell0_uid = k1.m_cell0.cellUid();
432 Int64 k2_cell0_uid = k2.m_cell0.cellUid();
433 if (k1_cell0_uid < k2_cell0_uid)
434 return true;
435 if (k1_cell0_uid > k2_cell0_uid)
436 return false;
437
438 Int64 k1_face0_local_index = k1.m_cell0.faceLocalIndex();
439 Int64 k2_face0_local_index = k2.m_cell0.faceLocalIndex();
440 if (k1_face0_local_index < k2_face0_local_index)
441 return true;
442 if (k1_face0_local_index > k2_face0_local_index)
443 return false;
444
445 return (k1.m_cell1.cellUid() < k2.m_cell1.cellUid());
446 }
447
449 {
450 const AnyFaceInfo* fsi_base = values.data();
451 Integer message_size = CheckedConvert::toInteger(values.size() * sizeof(AnyFaceInfo));
452 return pm->send(ByteConstArrayView(message_size, (const Byte*)fsi_base), rank, false);
453 }
454
455 static Parallel::Request recv(IParallelMng* pm, Int32 rank, ArrayView<AnyFaceInfo> values)
456 {
457 AnyFaceInfo* fsi_base = values.data();
458 Integer message_size = CheckedConvert::toInteger(values.size() * sizeof(AnyFaceInfo));
459 return pm->recv(ByteArrayView(message_size, (Byte*)fsi_base), rank, false);
460 }
461
462 static AnyFaceInfo maxValue()
463 {
464 AnyFaceInfo csi;
465 csi.m_cell0.setMaxValue();
466 csi.m_cell1.setMaxValue();
467 return csi;
468 }
469
470 static bool isValid(const AnyFaceInfo& csi)
471 {
472 return !csi.m_cell0.isMaxValue();
473 }
474};
475
476/*---------------------------------------------------------------------------*/
477/*---------------------------------------------------------------------------*/
478
480{
481 public:
482
483 bool operator()(const Item& i1, const Item& i2) const
484 {
485 return i1.uniqueId() < i2.uniqueId();
486 }
487};
488
489/*---------------------------------------------------------------------------*/
490/*---------------------------------------------------------------------------*/
491
492/*---------------------------------------------------------------------------*/
493/*---------------------------------------------------------------------------*/
494
498, m_mesh(mesh)
499, m_parallel_mng(mesh->parallelMng())
500{
501}
502
503/*---------------------------------------------------------------------------*/
504/*---------------------------------------------------------------------------*/
505
506/*---------------------------------------------------------------------------*/
507/*---------------------------------------------------------------------------*/
513{
514 if (m_parallel_mng->isParallel())
516 else
518}
519
520/*---------------------------------------------------------------------------*/
521/*---------------------------------------------------------------------------*/
527{
528 info() << "Compute FacesUniqueId() Sequential V3";
529
530 //TODO: allow not to start at zero.
531 Int64 face_unique_id_counter = 0;
532
533 ItemInternalMap& cells_map = m_mesh->cellsMap();
534 Integer nb_cell = cells_map.count();
535 UniqueArray<Cell> cells;
536 cells.reserve(nb_cell);
537 // First, the cells must be sorted by their uniqueId()
538 // in ascending order
539 cells_map.eachItem([&](Cell item) {
540 cells.add(item);
541 });
542 std::sort(std::begin(cells), std::end(cells), UniqueIdSorter());
543
544 // Invalidate uids to ensure they are all positioned.
546
547 for (Integer i = 0; i < nb_cell; ++i) {
548 Cell cell = cells[i];
549 for (Face face : cell.faces()) {
550 if (face.uniqueId() == NULL_ITEM_UNIQUE_ID) {
551 face.mutableItemBase().setUniqueId(face_unique_id_counter);
552 ++face_unique_id_counter;
553 }
554 }
555 }
556}
557
558/*---------------------------------------------------------------------------*/
559/*---------------------------------------------------------------------------*/
565{
566 IParallelMng* pm = m_parallel_mng;
567 Int32 my_rank = pm->commRank();
568
569 bool is_verbose = m_is_verbose;
570
571 ItemInternalMap& cells_map = m_mesh->cellsMap();
572
573 info() << "Compute FacesUniqueId() V3 using parallel sort";
574
575 // Calculate and sort for boundary faces
576 UniqueArray<BoundaryFaceInfo> boundary_faces_info;
577 _computeAndSortBoundaryFaces(boundary_faces_info);
578
579 // Here, the boundary faces are sorted based on their nodes.
580 // Normally, in this list, 2 consecutive BoundaryFaceInfo elements that
581 // have the same nodes represent the same face. In this case, we generate
582 // an AnyFaceInfo with the information of the two cells from these two elements of
583 // the list, being careful to put the cell with the smaller uniqueId() first.
584 // If two consecutive elements of the list do not have the same nodes, it
585 // means that the face is on the edge of the global domain.
586 // We must still handle the case of two consecutive elements of the list
587 // that are located on different processors. To manage this case, each
588 // processor sends the last element of its list to the next one if it cannot
589 // be merged with the second-to-last, in the hope that it can be merged with the
590 // first one of the next processor's list.
591 UniqueArray<AnyFaceInfo> all_face_list;
592 {
593 ConstArrayView<BoundaryFaceInfo> all_fsi = boundary_faces_info;
594 Integer n = all_fsi.size();
595 bool is_last_already_done = false;
596 for (Integer i = 0; i < n; ++i) {
597 const BoundaryFaceInfo& fsi = all_fsi[i];
598 Int64 cell_uid0 = fsi.m_cell_uid;
599 bool is_inside = false;
600 //TODO: handle the case if the previous cell is on another proc
601 // For this, it is necessary to retrieve the last value of the previous proc
602 // and check if it corresponds to our first value
603 is_inside = ((i + 1) != n && fsi.hasSameNodes(all_fsi[i + 1]));
604 if (is_last_already_done) {
605 is_last_already_done = false;
606 }
607 else {
608 AnyFaceInfo csi;
609 if (is_inside) {
610 const BoundaryFaceInfo& next_fsi = all_fsi[i + 1];
611 Int64 cell_uid1 = next_fsi.m_cell_uid;
612 if (cell_uid0 < cell_uid1) {
613 csi.setCell0(cell_uid0, fsi.m_rank, fsi.m_face_local_index);
614 csi.setCell1(cell_uid1, next_fsi.m_rank, next_fsi.m_face_local_index);
615 }
616 else {
617 csi.setCell0(cell_uid1, next_fsi.m_rank, next_fsi.m_face_local_index);
618 csi.setCell1(cell_uid0, fsi.m_rank, fsi.m_face_local_index);
619 }
620 is_last_already_done = true;
621 }
622 else {
623 csi.setCell0(cell_uid0, fsi.m_rank, fsi.m_face_local_index);
624 }
625 all_face_list.add(csi);
626 }
627 if (is_verbose)
628 info() << "FACES_KEY i=" << i
629 << " n0=" << fsi.m_node0_uid
630 << " n1=" << fsi.m_node1_uid
631 << " n2=" << fsi.m_node2_uid
632 << " cell=" << fsi.m_cell_uid
633 << " rank=" << fsi.m_rank
634 << " li=" << fsi.m_face_local_index
635 << " in=" << is_inside;
636 }
637 }
638
639 // Add the faces belonging to our sub-domain.
640 // These are all faces that have 2 connected cells.
641 cells_map.eachItem([&](Cell cell) {
642 Integer cell_nb_face = cell.nbFace();
643 Int64 cell_uid = cell.uniqueId();
644 for (Integer z = 0; z < cell_nb_face; ++z) {
645 Face face = cell.face(z);
646 if (face.nbCell() != 2)
647 continue;
648 Cell cell0 = face.cell(0);
649 Cell cell1 = face.cell(1);
650 Cell next_cell = (cell0 == cell) ? cell1 : cell0;
651 Int64 next_cell_uid = next_cell.uniqueId();
652 // Only record if I am the cell with the smaller uid
653 if (cell_uid < next_cell_uid) {
654 AnyFaceInfo csi;
655 csi.m_cell0.setValue(cell_uid, my_rank, z);
656 // The face_local_index of cell 1 will not be used
657 csi.m_cell1.setValue(next_cell_uid, my_rank, -1);
658 all_face_list.add(csi);
659 }
660 }
661 });
662
663 if (is_verbose) {
664 Integer n = all_face_list.size();
665 for (Integer i = 0; i < n; ++i) {
666 const AnyFaceInfo& csi = all_face_list[i];
667 info() << "CELL_TO_SORT i=" << i
668 << " cell0=" << csi.m_cell0.cellUid()
669 << " lidx0=" << csi.m_cell0.faceLocalIndex()
670 << " cell1=" << csi.m_cell1.cellUid();
671 }
672 }
673
674 info() << "ALL_FACE_LIST memorysize=" << sizeof(AnyFaceInfo) * all_face_list.size();
676 all_face_sorter.setNeedIndexAndRank(false);
677 Real sort_begin_time = platform::getRealTime();
678 all_face_sorter.sort(all_face_list);
679 Real sort_end_time = platform::getRealTime();
680 info() << "END_ALL_FACE_SORTER time=" << (Real)(sort_end_time - sort_begin_time);
681
682 _resendCellsAndComputeFacesUniqueId(all_face_sorter.keys());
683}
684
685/*---------------------------------------------------------------------------*/
686/*---------------------------------------------------------------------------*/
693{
694 IParallelMng* pm = m_parallel_mng;
695 Int32 my_rank = pm->commRank();
696 bool is_verbose = m_is_verbose;
697 ItemInternalMap& faces_map = m_mesh->facesMap();
698
700 boundary_face_sorter.setNeedIndexAndRank(false);
701
702 //UniqueArray<BoundaryFaceInfo> boundary_face_list;
703 boundary_faces_info.clear();
704 faces_map.eachItem([&](Face face) {
706 Integer nb_cell = face.nbCell();
707 if (nb_cell == 2)
708 return;
709
710 fsi.m_rank = my_rank;
711 fsi.setNodes(face);
712 Cell cell = face.cell(0);
713 fsi.m_cell_uid = cell.uniqueId();
714 Integer face_local_index = 0;
715 for (Integer z = 0, zs = cell.nbFace(); z < zs; ++z)
716 if (cell.face(z) == face) {
717 face_local_index = z;
718 break;
719 }
720 fsi.m_face_local_index = face_local_index;
721 boundary_faces_info.add(fsi);
722 });
723
724 if (is_verbose) {
725 ConstArrayView<BoundaryFaceInfo> all_fsi = boundary_faces_info;
726 Integer n = all_fsi.size();
727 for (Integer i = 0; i < n; ++i) {
728 const BoundaryFaceInfo& fsi = all_fsi[i];
729 info() << "KEY i=" << i
730 << " n0=" << fsi.m_node0_uid
731 << " n1=" << fsi.m_node1_uid
732 << " n2=" << fsi.m_node2_uid
733 << " cell=" << fsi.m_cell_uid
734 << " rank=" << fsi.m_rank
735 << " li=" << fsi.m_face_local_index;
736 }
737 }
738
739 Real sort_begin_time = platform::getRealTime();
740 boundary_face_sorter.sort(boundary_faces_info);
741 Real sort_end_time = platform::getRealTime();
742 info() << "END_BOUNDARY_FACE_SORT time=" << (Real)(sort_end_time - sort_begin_time);
743
744 {
745 ConstArrayView<BoundaryFaceInfo> all_bfi = boundary_face_sorter.keys();
746 Integer n = all_bfi.size();
747 if (is_verbose) {
748 for (Integer i = 0; i < n; ++i) {
749 const BoundaryFaceInfo& bfi = all_bfi[i];
750 info() << " AFTER KEY i=" << i
751 << " n0=" << bfi.m_node0_uid
752 << " n1=" << bfi.m_node1_uid
753 << " n2=" << bfi.m_node2_uid
754 << " cell=" << bfi.m_cell_uid
755 << " rank=" << bfi.m_rank
756 << " li=" << bfi.m_face_local_index;
757 }
758 }
759
760 // As a single node may be present in the previous proc's list, each PE
761 // (except 0) sends to the previous process the start of its list which contains the same nodes.
762
763 // TODO: merge this code with that of GhostLayerBuilder2
764 UniqueArray<BoundaryFaceInfo> end_face_list;
765 Integer begin_own_list_index = 0;
766 if (n != 0 && my_rank != 0) {
767 if (BoundaryFaceBitonicSortTraits::isValid(all_bfi[0])) {
768 Int64 node0_uid = all_bfi[0].m_node0_uid;
769 for (Integer i = 0; i < n; ++i) {
770 if (all_bfi[i].m_node0_uid != node0_uid) {
771 begin_own_list_index = i;
772 break;
773 }
774 else
775 end_face_list.add(all_bfi[i]);
776 }
777 }
778 }
779 info() << "BEGIN_OWN_LIST_INDEX=" << begin_own_list_index;
780 if (is_verbose) {
781 for (Integer k = 0, kn = end_face_list.size(); k < kn; ++k)
782 info() << " SEND n0=" << end_face_list[k].m_node0_uid
783 << " n1=" << end_face_list[k].m_node1_uid
784 << " n2=" << end_face_list[k].m_node2_uid;
785 }
786
787 UniqueArray<BoundaryFaceInfo> end_face_list_recv;
788
790 Integer recv_message_size = 0;
791 Integer send_message_size = BoundaryFaceBitonicSortTraits::messageSize(end_face_list);
792
793 Int32 nb_rank = pm->commSize();
794
795 // First sends and receives the sizes.
796 if (my_rank != (nb_rank - 1)) {
797 requests.add(pm->recv(IntegerArrayView(1, &recv_message_size), my_rank + 1, false));
798 }
799 if (my_rank != 0) {
800 requests.add(pm->send(IntegerConstArrayView(1, &send_message_size), my_rank - 1, false));
801 }
802
803 pm->waitAllRequests(requests);
804 requests.clear();
805
806 if (recv_message_size != 0) {
807 Integer message_size = CheckedConvert::toInteger(recv_message_size / sizeof(BoundaryFaceInfo));
808 end_face_list_recv.resize(message_size);
809 requests.add(BoundaryFaceBitonicSortTraits::recv(pm, my_rank + 1, end_face_list_recv));
810 }
811 if (send_message_size != 0)
812 requests.add(BoundaryFaceBitonicSortTraits::send(pm, my_rank - 1, end_face_list));
813
814 pm->waitAllRequests(requests);
815
816 boundary_faces_info.clear();
817 boundary_faces_info.addRange(all_bfi.subConstView(begin_own_list_index, n - begin_own_list_index));
818 boundary_faces_info.addRange(end_face_list_recv);
819 }
820}
821
822/*---------------------------------------------------------------------------*/
823/*---------------------------------------------------------------------------*/
824
825void FaceUniqueIdBuilder2::
826_resendCellsAndComputeFacesUniqueId(ConstArrayView<AnyFaceInfo> all_csi)
827{
828 IParallelMng* pm = m_parallel_mng;
829 Int32 nb_rank = pm->commSize();
830 Int32 my_rank = pm->commRank();
831 bool is_verbose = m_is_verbose;
832
833 ItemInternalMap& cells_map = m_mesh->cellsMap();
834
835 Int64 nb_computed_face = all_csi.size();
836
837 if (is_verbose) {
838 for (Integer i = 0; i < nb_computed_face; ++i) {
839 const AnyFaceInfo& csi = all_csi[i];
840 info() << "CELLS_KEY i=" << i
841 << " cell0=" << csi.m_cell0.cellUid()
842 << " lidx0=" << csi.m_cell0.faceLocalIndex()
843 << " cell1=" << csi.m_cell1.cellUid()
844 << " lidx1=" << csi.m_cell1.faceLocalIndex()
845 << " rank0=" << csi.m_cell0.rank()
846 << " rank1=" << csi.m_cell1.rank();
847 }
848 }
849
850 // Calculation for each rank of the number of values to send
851 // and stores it in nb_info_to_send;
852 IntegerUniqueArray nb_info_to_send(nb_rank, 0);
853 {
854 for (Integer i = 0; i < nb_computed_face; ++i) {
855 const AnyFaceInfo& csi = all_csi[i];
856 Int32 rank0 = csi.m_cell0.rank();
857 Int32 rank1 = csi.m_cell1.rank();
858
859 ++nb_info_to_send[rank0];
860
861 // It must only be sent if the rank is different from m_rank0
862 if (csi.m_cell1.isValid() && rank1 != rank0)
863 ++nb_info_to_send[rank1];
864 }
865 }
866
867 // Array for each process indicating the uniqueId() of the first
868 // face of this process.
869 Int64UniqueArray all_first_face_uid(nb_rank);
870 {
871 // Each process retrieves the number of cells in the list.
872 // Since this list will be sorted, this corresponds to the uid of the first
873 // face of this process.
874 Int64 nb_cell_to_sort = all_csi.size();
875 pm->allGather(Int64ConstArrayView(1, &nb_cell_to_sort), all_first_face_uid);
876
877 Int64 to_add = 0;
878 for (Integer i = 0; i < nb_rank; ++i) {
879 Int64 next = all_first_face_uid[i];
880 all_first_face_uid[i] = to_add;
881 to_add += next;
882 }
883 }
884
885 Integer total_nb_to_send = 0;
886 IntegerUniqueArray nb_info_to_send_indexes(nb_rank, 0);
887 for (Integer i = 0; i < nb_rank; ++i) {
888 nb_info_to_send_indexes[i] = total_nb_to_send;
889 total_nb_to_send += nb_info_to_send[i];
890 }
891 info() << "TOTAL_NB_TO_SEND=" << total_nb_to_send;
892
893 UniqueArray<ResendCellInfo> resend_infos(total_nb_to_send);
894 {
895 for (Integer i = 0; i < nb_computed_face; ++i) {
896 const AnyFaceInfo& csi = all_csi[i];
897 Int32 rank0 = csi.m_cell0.rank();
898 Int32 rank1 = csi.m_cell1.rank();
899
900 ResendCellInfo& rci0 = resend_infos[nb_info_to_send_indexes[rank0]];
901 rci0.m_cell_uid = csi.m_cell0.cellUid();
902 rci0.m_face_local_index_and_owner_rank = (csi.m_cell0.faceLocalIndex() * nb_rank) + rank0;
903 rci0.m_index_in_rank_list = i;
904 ++nb_info_to_send_indexes[rank0];
905
906 if (csi.m_cell1.isValid() && rank1 != rank0) {
907 ResendCellInfo& rci1 = resend_infos[nb_info_to_send_indexes[rank1]];
908 rci1.m_cell_uid = csi.m_cell1.cellUid();
909 // Even if I am cell 1, the owner of the face will be cell 0.
910 rci1.m_face_local_index_and_owner_rank = (csi.m_cell1.faceLocalIndex() * nb_rank) + rank0;
911 rci1.m_index_in_rank_list = i;
912 ++nb_info_to_send_indexes[rank1];
913 }
914 }
915 }
916
917 // Perform a single reduce
918 Int64 total_nb_computed_face = pm->reduce(Parallel::ReduceSum, nb_computed_face);
919 info() << "TOTAL_NB_COMPUTED_FACE=" << total_nb_computed_face;
920
921 // Indicates to each PE how many infos I will send to it
922 if (is_verbose)
923 for (Integer i = 0; i < nb_rank; ++i)
924 info() << "NB_TO_SEND: I=" << i << " n=" << nb_info_to_send[i];
925
926 IntegerUniqueArray nb_info_to_recv(nb_rank, 0);
927 {
928 Timer::SimplePrinter sp(traceMng(), "Sending size with AllToAll");
929 pm->allToAll(nb_info_to_send, nb_info_to_recv, 1);
930 }
931
932 if (is_verbose)
933 for (Integer i = 0; i < nb_rank; ++i)
934 info() << "NB_TO_RECV: I=" << i << " n=" << nb_info_to_recv[i];
935
936 Integer total_nb_to_recv = 0;
937 for (Integer i = 0; i < nb_rank; ++i)
938 total_nb_to_recv += nb_info_to_recv[i];
939
940 // It is highly likely that this will not work if the array is too large,
941 // it must proceed with arrays that do not exceed 2Go because of the
942 // Int32 of MPI.
943 // TODO: Perform the AllToAll multiple times if necessary.
944 UniqueArray<ResendCellInfo> recv_infos;
945 {
946 Int32 vsize = sizeof(ResendCellInfo) / sizeof(Int64);
947 Int32UniqueArray send_counts(nb_rank);
948 Int32UniqueArray send_indexes(nb_rank);
949 Int32UniqueArray recv_counts(nb_rank);
950 Int32UniqueArray recv_indexes(nb_rank);
951 Int32 total_send = 0;
952 Int32 total_recv = 0;
953 for (Integer i = 0; i < nb_rank; ++i) {
954 send_counts[i] = (Int32)(nb_info_to_send[i] * vsize);
955 recv_counts[i] = (Int32)(nb_info_to_recv[i] * vsize);
956 send_indexes[i] = total_send;
957 recv_indexes[i] = total_recv;
958 total_send += send_counts[i];
959 total_recv += recv_counts[i];
960 }
961 recv_infos.resize(total_nb_to_recv);
962
963 Int64ConstArrayView send_buf(total_nb_to_send * vsize, (Int64*)resend_infos.data());
964 Int64ArrayView recv_buf(total_nb_to_recv * vsize, (Int64*)recv_infos.data());
965
966 info() << "BUF_SIZES: send=" << send_buf.size() << " recv=" << recv_buf.size();
967 {
968 Timer::SimplePrinter sp(traceMng(), "Send values with AllToAll");
969 pm->allToAllVariable(send_buf, send_counts, send_indexes, recv_buf, recv_counts, recv_indexes);
970 }
971 }
972
973 // Invalidates the uids to ensure they will all be positioned.
975
976 if (is_verbose) {
977 Integer index = 0;
978 for (Int32 rank = 0; rank < nb_rank; ++rank) {
979 for (Integer z = 0, zs = nb_info_to_recv[rank]; z < zs; ++z) {
980 const ResendCellInfo& rci = recv_infos[index];
981 ++index;
982
983 Int64 cell_uid = rci.m_cell_uid;
984 Int32 full_local_index = rci.m_face_local_index_and_owner_rank;
985 Int32 face_local_index = full_local_index / nb_rank;
986 Int32 owner_rank = full_local_index % nb_rank;
987 Int64 face_uid = all_first_face_uid[rank] + rci.m_index_in_rank_list;
988 info() << "RECV index=" << index << " uid=" << cell_uid
989 << " local_idx=" << full_local_index
990 << " face_local_idx=" << face_local_index
991 << " owner_rank=" << owner_rank
992 << " rank_idx=" << rci.m_index_in_rank_list
993 << " rank=" << rank
994 << " first_face_uid=" << all_first_face_uid[rank]
995 << " computed_uid=" << face_uid;
996 }
997 }
998 }
999
1000 // Positions the uniqueId() and the owner() of the faces.
1001 {
1002 Integer index = 0;
1003 for (Int32 i = 0; i < nb_rank; ++i) {
1004 Int32 rank = i;
1005 for (Integer z = 0, zs = nb_info_to_recv[i]; z < zs; ++z) {
1006 const ResendCellInfo& rci = recv_infos[index];
1007 ++index;
1008
1009 Int64 cell_uid = rci.m_cell_uid;
1010 Int32 full_local_index = rci.m_face_local_index_and_owner_rank;
1011 Int32 face_local_index = full_local_index / nb_rank;
1012 Int32 owner_rank = full_local_index % nb_rank;
1013
1014 Cell cell = cells_map.tryFind(cell_uid);
1015 if (cell.null())
1016 ARCANE_FATAL("Can not find cell data for '{0}'", cell_uid);
1017 Face face = cell.face(face_local_index);
1018 Int64 face_uid = all_first_face_uid[rank] + rci.m_index_in_rank_list;
1019 face.mutableItemBase().setUniqueId(face_uid);
1020 face.mutableItemBase().setOwner(owner_rank, my_rank);
1021 }
1022 }
1023 }
1024
1025 // Checks that all faces have a valid uid
1027}
1028
1029/*---------------------------------------------------------------------------*/
1030/*---------------------------------------------------------------------------*/
1036{
1037 info() << "Compute FacesUniqueId() V5 (experimental)";
1038
1039 IParallelMng* pm = m_parallel_mng;
1040 Int32 my_rank = pm->commRank();
1041 bool is_parallel = pm->isParallel();
1042
1043 ItemInternalMap& faces_map = m_mesh->facesMap();
1044 UniqueArray<Int64> nodes_uid;
1045 faces_map.eachItem([&](Face face) {
1046 Int32 nb_node = face.nbNode();
1047 nodes_uid.resize(nb_node);
1048 {
1049 Int32 index = 0;
1050 for (Node node : face.nodes()) {
1051 nodes_uid[index] = node.uniqueId();
1052 ++index;
1053 }
1054 }
1055 Int64 new_face_uid = MeshUtils::generateHashUniqueId(nodes_uid);
1056 face.mutableItemBase().setUniqueId(new_face_uid);
1057 // In parallel, indicates that the owner of this face must be positioned
1058 // if it is a boundary face.
1059 Int32 new_rank = my_rank;
1060 if (is_parallel && face.nbCell() == 1)
1061 new_rank = A_NULL_RANK;
1062 face.mutableItemBase().setOwner(new_rank, my_rank);
1063 });
1064}
1065
1066/*---------------------------------------------------------------------------*/
1067/*---------------------------------------------------------------------------*/
1073{
1074 ItemInternalMap& faces_map = m_mesh->facesMap();
1075 faces_map.eachItem([&](Item face) {
1077 });
1078}
1079
1080/*---------------------------------------------------------------------------*/
1081/*---------------------------------------------------------------------------*/
1087{
1088 ItemInternalMap& faces_map = m_mesh->facesMap();
1089 Integer nb_error = 0;
1090 faces_map.eachItem([&](Face face) {
1091 Int64 face_uid = face.uniqueId();
1092 if (face_uid == NULL_ITEM_UNIQUE_ID) {
1093 info() << "Bad face uid cell0=" << face.cell(0).uniqueId();
1094 ++nb_error;
1095 }
1096 });
1097 if (nb_error != 0)
1098 ARCANE_FATAL("Internal error in face uniqueId computation: nb_invalid={0}", nb_error);
1099}
1100
1101/*---------------------------------------------------------------------------*/
1102/*---------------------------------------------------------------------------*/
1103
1104extern "C++" void
1105_computeFaceUniqueIdVersion3(DynamicMesh* mesh)
1106{
1108 f.computeFacesUniqueIdAndOwnerVersion3();
1109}
1110
1111/*---------------------------------------------------------------------------*/
1112/*---------------------------------------------------------------------------*/
1113
1114extern "C++" void
1115_computeFaceUniqueIdVersion5(DynamicMesh* mesh)
1116{
1117 FaceUniqueIdBuilder2 f(mesh);
1118 f.computeFacesUniqueIdAndOwnerVersion5();
1119}
1120
1121/*---------------------------------------------------------------------------*/
1122/*---------------------------------------------------------------------------*/
1123
1124} // End namespace Arcane::mesh
1125
1126/*---------------------------------------------------------------------------*/
1127/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Int64 generateHashUniqueId(SmallSpan< const Int64 > nodes_unique_id)
Generates a unique identifier from a list of node identifiers.
Integer size() const
Number of elements in the vector.
Modifiable view of an array of type T.
constexpr const_pointer data() const noexcept
Pointer to the start of the view.
constexpr Integer size() const noexcept
Returns the size of the array.
Base class for 1D data vectors.
void addRange(ConstReferenceType val, Int64 n)
Adds n elements of value val to the end of the array.
void resize(Int64 s)
Changes the number of elements in the array to s.
void clear()
Removes the elements from the array.
void add(ConstReferenceType val)
Adds element val to the end of the array.
void reserve(Int64 new_capacity)
Reserves memory for new_capacity elements.
Cell of a mesh.
Definition Item.h:1300
FaceConnectedListViewType faces() const
List of faces of the cell.
Definition Item.h:1403
Face face(Int32 i) const
i-th face of the cell
Definition Item.h:1400
Int32 nbFace() const
Number of faces of the cell.
Definition Item.h:1397
Constant view of an array of type T.
constexpr const_pointer data() const noexcept
Pointer to the allocated memory.
constexpr Integer size() const noexcept
Number of elements in the array.
constexpr ConstArrayView< T > subConstView(Integer abegin, Integer asize) const noexcept
Sub-view (constant) starting from element abegin and containing asize elements.
Face of a cell.
Definition Item.h:1032
Cell cell(Int32 i) const
i-th cell of the face
Definition Item.h:1793
Int32 nbCell() const
Number of cells of the face (1 or 2).
Definition Item.h:1129
Interface of the parallelism manager for a subdomain.
virtual Int32 commRank() const =0
Rank of this instance in the communicator.
virtual void recv(ArrayView< char > values, Int32 rank)=0
virtual Int32 commSize() const =0
Number of instances in the communicator.
virtual void allGather(ConstArrayView< char > send_buf, ArrayView< char > recv_buf)=0
Performs an all-gather operation across all processors. This is a collective operation....
virtual void waitAllRequests(ArrayView< Request > rvalues)=0
Blocks while waiting for the rvalues requests to complete.
virtual bool isParallel() const =0
Returns true if the execution is parallel.
virtual char reduce(eReduceType rt, char v)=0
Performs a reduction of type rt on the real v and returns the value.
Node node(Int32 i) const
i-th node of the entity
Definition Item.h:840
NodeConnectedListViewType nodes() const
List of nodes of the entity.
Definition Item.h:843
Int32 nbNode() const
Number of nodes of the entity.
Definition Item.h:837
Base class for a mesh element.
Definition Item.h:84
impl::MutableItemBase mutableItemBase() const
Mutable internal part of the entity.
Definition Item.h:394
ItemUniqueId uniqueId() const
Unique identifier across all domains.
Definition Item.h:239
void setOwner(Integer suid, Int32 current_sub_domain)
Sets the sub-domain number of the entity owner.
void unsetUniqueId()
Nullifies the uniqueId to the value NULL_ITEM_UNIQUE_ID.
Node of a mesh.
Definition Item.h:598
Parallel bitonic sort algorithm.
ConstArrayView< KeyType > keys() const override
After a sort, returns the list of elements on this rank.
void sort(ConstArrayView< KeyType > keys) override
Parallelly sorts the elements of keys on all ranks.
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
TraceMessage info() const
Flow for an information message.
ITraceMng * traceMng() const
Trace manager.
1D data vector with value semantics (STL style).
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.
Real getRealTime()
Real time used in seconds.
ArrayView< Int64 > Int64ArrayView
C equivalent of a 1D array of 64-bit integers.
Definition UtilsTypes.h:451
UniqueArray< Int64 > Int64UniqueArray
Dynamic 1D array of 64-bit integers.
Definition UtilsTypes.h:339
ArrayView< Byte > ByteArrayView
C equivalent of a 1D array of characters.
Definition UtilsTypes.h:447
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
ArrayView< Integer > IntegerArrayView
C equivalent of a 1D array of integers.
Definition UtilsTypes.h:457
ConstArrayView< Int64 > Int64ConstArrayView
C equivalent of a 1D array of 64-bit integers.
Definition UtilsTypes.h:480
UniqueArray< Int32 > Int32UniqueArray
Dynamic 1D array of 32-bit integers.
Definition UtilsTypes.h:341
double Real
Type representing a real number.
ConstArrayView< Byte > ByteConstArrayView
C equivalent of a 1D array of characters.
Definition UtilsTypes.h:476
unsigned char Byte
Type of a byte.
Definition BaseTypes.h:43
UniqueArray< Integer > IntegerUniqueArray
Dynamic 1D array of integers.
Definition UtilsTypes.h:347
ConstArrayView< Integer > IntegerConstArrayView
C equivalent of a 1D array of integers.
Definition UtilsTypes.h:486
@ Cell
The mesh is AMR by cell.
Definition MeshKind.h:53
std::int32_t Int32
Signed integer type of 32 bits.