14#include "arcane/utils/PlatformUtils.h"
15#include "arcane/utils/ScopedPtr.h"
16#include "arcane/utils/ITraceMng.h"
17#include "arcane/utils/OStringStream.h"
18#include "arcane/utils/CheckedConvert.h"
20#include "arcane/core/IMeshUniqueIdMng.h"
21#include "arcane/core/IParallelExchanger.h"
22#include "arcane/core/IParallelMng.h"
23#include "arcane/core/IParallelNonBlockingCollective.h"
24#include "arcane/core/ISerializeMessage.h"
25#include "arcane/core/ISerializer.h"
26#include "arcane/core/ParallelMngUtils.h"
28#include "arcane/mesh/DynamicMesh.h"
29#include "arcane/mesh/OneMeshItemAdder.h"
30#include "arcane/mesh/GhostLayerBuilder.h"
31#include "arcane/mesh/FaceUniqueIdBuilder.h"
32#include "arcane/mesh/ItemTools.h"
33#include "arcane/mesh/ItemsOwnerBuilder.h"
34#include "arcane/mesh/internal/Int64AllToAll.h"
36#include <unordered_set>
56arcaneComputeCartesianFaceUniqueId(
DynamicMesh* mesh);
64, m_mesh(mesh_builder->
mesh())
65, m_mesh_builder(mesh_builder)
76void FaceUniqueIdBuilder::
77computeFacesUniqueIds()
83 info() <<
"Using version=" << face_version <<
" to compute faces unique ids"
84 <<
" mesh=" << m_mesh->
name() <<
" is_parallel=" << is_parallel;
86 if (face_version > 5 || face_version < 0)
87 ARCANE_FATAL(
"Invalid value '{0}' for compute face unique ids versions: v>=0 && v<=6", face_version);
89 if (face_version == 5)
90 _computeFaceUniqueIdVersion5(m_mesh);
91 else if (face_version == 4)
92 arcaneComputeCartesianFaceUniqueId(m_mesh);
93 else if (face_version == 3)
94 _computeFaceUniqueIdVersion3(m_mesh);
95 else if (face_version == 0) {
96 info() <<
"No face renumbering";
101 if (face_version == 2) {
103 info() <<
"Use new mesh init in FaceUniqueIdBuilder";
117 Real diff = (
Real)(end_time - begin_time);
118 info() <<
"TIME to compute face unique ids=" << diff;
123 ItemInternalMap& faces_map = m_mesh->facesMap();
127 if (face_version != 0)
128 m_mesh->faceFamily()->notifyItemsUniqueIdChanged();
130 bool is_verbose = m_mesh_builder->isVerbose();
132 info() <<
"NEW FACES_MAP after re-indexing";
133 faces_map.eachItem([&](Item face) {
134 info() <<
"Face uid=" << face.uniqueId() <<
" lid=" << face.localId();
139 if (face_version == 0 || face_version == 5) {
140 ItemsOwnerBuilder owner_builder(m_mesh);
141 owner_builder.computeFacesOwner();
153 info() <<
"Check no duplicate face uniqueId";
155 std::unordered_set<Int64> checked_faces_map;
158 auto p = checked_faces_map.find(uid);
159 if (p != checked_faces_map.end()) {
160 pwarning() <<
"Duplicate Face UniqueId=" << uid;
163 checked_faces_map.insert(uid);
182 , m_nb_back_face(nb_back_face)
183 , m_nb_true_boundary_face(nb_true_boundary_face)
188 : m_unique_id(NULL_ITEM_ID)
190 , m_nb_true_boundary_face(0)
196 bool operator<(
const T_CellFaceInfo& ci)
const
198 return m_unique_id < ci.m_unique_id;
204 Int64 m_nb_back_face;
205 Int64 m_nb_true_boundary_face;
219 uint64_t h =
static_cast<uint64_t
>(key);
220 h = (h ^ (h >> 30)) * 0xbf58476d1ce4e5b9ULL;
221 h = (h ^ (h >> 27)) * 0x94d049bb133111ebULL;
223 return static_cast<Int32>(h %
static_cast<uint64_t
>(nb_rank));
244 const Int64 nb_bucket_per_slice = 4;
252 auto split = [](Array<Bucket>& out, Int64 lo, Int64 width, Int64 nb) {
253 const Int64 w = (width - 1) / nb + 1;
254 for (Int64 a = lo; a < lo + width; a += w)
255 out.add(Bucket{ a, std::min(w, lo + width - a), -1 });
258 auto count = [&](Array<Bucket>& buckets) {
259 UniqueArray<Int32> todo;
260 for (
Int32 i = 0; i < buckets.size(); ++i) {
261 if (buckets[i].count < 0)
264 UniqueArray<Int64> c(todo.size());
267 for (
Int32 i = 0; i < todo.size(); ++i) {
268 const Bucket& b = buckets[todo[i]];
269 c[i] = std::lower_bound(k, k_end, b.lo + b.width) - std::lower_bound(k, k_end, b.lo);
272 for (
Int32 i = 0; i < todo.size(); ++i)
273 buckets[todo[i]].count = c[i];
276 UniqueArray<Bucket> buckets;
277 split(buckets, g_lo, g_hi - g_lo + 1, nb_bucket_per_slice * nb_rank);
280 for (
const Bucket& b : buckets)
287 UniqueArray<Bucket> next;
289 for (
const Bucket& b : buckets) {
290 if (b.width > 1 && b.count * nb_rank > total) {
291 split(next, b.lo, b.width, (nb_bucket_per_slice * b.count * nb_rank + total - 1) / total);
303 UniqueArray<Int64> bounds(nb_rank + 1, g_hi + 1);
307 for (
const Bucket& b : buckets) {
308 const Int32 s =
static_cast<Int32>(std::min<Int64>(nb_rank - 1, before * nb_rank / total));
309 for (
Int32 t = last + 1; t <= s; ++t)
311 last = std::max(last, s);
319_sliceOf(ConstArrayView<Int64> bounds,
Int64 uid)
322 return static_cast<Int32>(std::upper_bound(bounds.begin(), bounds.end(), uid) - bounds.begin()) - 1;
357 Integer nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
360 faces_opposite_cell_uid.
fill(NULL_ITEM_ID);
367 _v1ByAllGather(faces_opposite_cell_uid, faces_opposite_cell_index, faces_opposite_cell_owner,
368 cells_first_face_uid, my_cells_nb_back_face, my_cells_faces_info);
370 cells_first_face_uid, my_cells_nb_back_face);
421 info() <<
"Computing FaceUniqueIds using distributed version 1";
429 const Int32 nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
433 Int32 max_nb_node = 0;
437 max_nb_node = std::max(max_nb_node, face.
nbNode());
444 Int32 has_foreign_cell = 0;
447 if (cell.
owner() != my_rank)
448 has_foreign_cell = 1;
450 std::sort(cells.
begin(), cells.
end());
456 Int64 v[4] = { max_nb_node, (nb_cell > 0) ? -cells[0].first : INT64_MIN,
457 (nb_cell > 0) ? cells[nb_cell - 1].first : INT64_MIN, has_foreign_cell };
459 max_nb_node = CheckedConvert::toInt32(v[0]);
460 has_foreign_cell =
static_cast<Int32>(v[3]);
461 if (v[2] == INT64_MIN)
470 const Int32 s1 = max_nb_node + 1;
475 for (
Int32 i = 0; i < nb_bface; ++i) {
476 Face face(faces[bfaces[i]]);
480 nodes_uid.
add(node.uniqueId().asInt64());
481 std::sort(nodes_uid.
begin(), nodes_uid.
end());
483 for (
Int32 z = 0; z < max_nb_node; ++z)
484 k[z] = (z < nodes_uid.
size()) ? nodes_uid[z] : -1;
485 dest[i] = _bucketOfHash(k[0], nb_rank);
486 e1_count[dest[i]] += s1;
488 auto key_of = [&](
Int32 i) {
return keys.
data() +
static_cast<Int64>(i) * max_nb_node; };
490 auto key_less = [max_nb_node](
const Int64* ka,
const Int64* kb) {
491 for (
Int32 z = 0; z < max_nb_node; ++z) {
493 return ka[z] < kb[z];
500 for (
Int32 r = 0; r < nb_rank; ++r)
501 e1_index[r + 1] = e1_index[r] + e1_count[r] / s1;
507 for (
Int32 i = 0; i < nb_bface; ++i) {
508 const Int64 p = at[dest[i]]++;
509 sent[CheckedConvert::toInt32(p)] = i;
511 const Int64* k = key_of(i);
512 for (
Int32 z = 0; z < max_nb_node; ++z)
514 r[max_nb_node] = is_back(i) ? -1 : faces[bfaces[i]].cell(0).uniqueId().asInt64();
520 e1.
start(pm, e1_send, e1_count, e1_recv_count, e1_round);
525 for (
Int32 c = 0; c < nb_cell; ++c) {
526 Cell cell(cells_of[cells[c].second]);
533 if (c == 0 || cells[c].first != cells[c - 1].first + 1)
534 run_starts.
add(cells[c].first);
545 for (
Int32 c = 0; c < nb_cell; ++c) {
546 const Int64 uid = cells[c].first;
547 const Int32 old_s = s;
548 while (uid >= bounds[s + 1])
550 if (c == 0 || uid != cells[c - 1].first + 1 || s != old_s) {
554 slice_total[s] += cell_nb_back[c];
558 run_cell.
add(nb_cell);
560 for (
Int32 r = 0; r < nb_run; ++r)
561 e2_count[run_slice[r]] += 3;
563 for (
Int32 r = 0; r < nb_rank; ++r)
564 e2_index[r + 1] = e2_index[r] + e2_count[r] / 3;
569 for (
Int32 r = 0; r < nb_run; ++r) {
570 const Int64 p = at[run_slice[r]]++;
571 run_sent[CheckedConvert::toInt32(p)] = r;
573 for (
Int32 c = run_cell[r]; c < run_cell[r + 1]; ++c)
574 nb_back += cell_nb_back[c];
575 e2_send[p * 3 + 0] = cells[run_cell[r]].first;
576 e2_send[p * 3 + 1] = run_cell[r + 1] - run_cell[r];
577 e2_send[p * 3 + 2] = nb_back;
583 e2.
start(pm, e2_send, e2_count, e2_recv_count, e2_round);
590 for (
Int32 r = 0, i = 0; r < nb_rank; ++r) {
591 const Int32 n = CheckedConvert::toInt32(e1_recv_count[r] / s1);
592 for (
Int32 p = 0; p < n; ++p, ++i) {
599 for (
Int32 i = 0; i < n1; ++i)
601 std::sort(order.
begin(), order.
end(), [&](
Int32 a,
Int32 b) { return key_less(rec_of(a), rec_of(b)); });
603 const Int64* ka = rec_of(a);
604 const Int64* kb = rec_of(b);
605 for (
Int32 z = 0; z < max_nb_node; ++z) {
611 auto key_string = [&](
Int32 a) {
613 for (
Int32 z = 0; z < max_nb_node && rec_of(a)[z] >= 0; ++z)
614 o() <<
' ' << rec_of(a)[z];
622 for (
Int32 i = 0; i < n1;) {
624 while (j < n1 && same_key(order[i], order[j]))
626 const Int32 a = order[i];
628 const Int64 cell_uid = rec_of(a)[max_nb_node];
630 const Int32 s = _sliceOf(bounds, cell_uid);
632 lone_cell.
add(cell_uid);
636 else if (j - i == 2) {
637 const Int32 b = order[i + 1];
638 if (rec_src[a] == rec_src[b])
639 ARCANE_FATAL(
"Face numbering: the face of nodes ({0}) is held twice by sub-domain {1}",
640 key_string(a), rec_src[a]);
641 if ((rec_of(a)[max_nb_node] < 0) == (rec_of(b)[max_nb_node] < 0))
642 ARCANE_FATAL(
"Face numbering: the face of nodes ({0}) is {1} in sub-domains {2} and {3}",
643 key_string(a), (rec_of(a)[max_nb_node] < 0) ?
"behind its cell" :
"in front of its cell",
644 rec_src[a], rec_src[b]);
645 pair_answer.
add(rec_src[a]);
646 pair_answer.
add((
static_cast<Int64>(rec_pos[a]) << 32) | rec_src[b]);
647 pair_answer.
add(rec_src[b]);
648 pair_answer.
add((
static_cast<Int64>(rec_pos[b]) << 32) | rec_src[a]);
651 ARCANE_FATAL(
"Face numbering: the face of nodes ({0}) is held by {1} sub-domains",
652 key_string(a), j - i);
663 g_slice_total.
copy(slice_total);
670 for (
Int64 k = 0; k < pair_answer.
size(); k += 2) {
671 ++b_count[pair_answer[k]];
672 ++b_nb_answer[pair_answer[k]];
674 for (
Int64 k = 0; k < lone_cell.
size(); k += 2)
675 ++b_count[lone_cell[k]];
677 for (
Int32 r = 0; r < nb_rank; ++r)
678 b_index[r + 1] = b_index[r] + b_count[r];
682 for (
Int32 r = 0; r < nb_rank; ++r) {
683 b_send[b_index[r]] = b_nb_answer[r];
684 at[r] = b_index[r] + 1;
686 for (
Int64 k = 0; k < pair_answer.
size(); k += 2)
687 b_send[at[pair_answer[k]]++] = pair_answer[k + 1];
688 for (
Int64 k = 0; k < lone_cell.
size(); k += 2)
689 b_send[at[lone_cell[k]]++] = lone_cell[k + 1];
694 e1b.
start(pm, b_send, b_count, b_recv_count, b_round);
700 for (
Int32 r = 0; r < nb_rank; ++r) {
702 const Int64 nb_answer = m[0];
703 for (
Int64 k = 1; k <= nb_answer; ++k) {
704 const Int64 pos = m[k] >> 32;
705 const Int32 other =
static_cast<Int32>(m[k] & 0xffffffff);
706 partner[sent[CheckedConvert::toInt32(e1_index[r] + pos)]] = other;
708 for (
Int64 k = nb_answer + 1; k < m.
size(); ++k)
711 std::sort(my_lone.
begin(), my_lone.
end());
718 Int64 slice_start = 0;
719 for (
Int32 r = 0; r < my_rank; ++r)
720 slice_start += g_slice_total[r];
724 for (
Int32 i = 0; i < n2; ++i)
726 std::sort(run_order.
begin(), run_order.
end(),
727 [&](
Int32 a,
Int32 b) { return runs[a * 3] < runs[b * 3]; });
730 Int64 running = slice_start;
731 Int64 end_prev = INT64_MIN;
734 for (
Int32 i = 0; i < n2; ++i) {
735 const Int64* run = runs + run_order[i] * 3;
736 const Int64 first = run[0];
737 const Int64 end = first + run[1];
738 if (first < end_prev)
739 ARCANE_FATAL(
"Face numbering: the cell uniqueId={0} is held by two sub-domains", first);
740 if (l < nb_lone && my_lone[l] < first)
741 ARCANE_FATAL(
"Face numbering: the cell uniqueId={0} of a boundary face is held by no sub-domain", my_lone[l]);
742 a_send[run_order[i]] = running;
744 for (; l < nb_lone && my_lone[l] < end; ++l)
749 ARCANE_FATAL(
"Face numbering: the cell uniqueId={0} of a boundary face is held by no sub-domain", my_lone[l]);
750 if (running - slice_start != g_slice_total[my_rank])
751 ARCANE_FATAL(
"Face numbering: slice {0} counts {1} faces, its runs {2}",
752 my_rank, g_slice_total[my_rank], running - slice_start);
758 for (
Int32 r = 0; r < nb_rank; ++r) {
759 a_count[r] = e2_recv_count[r] / 3;
760 a_recv_count[r] = e2_count[r] / 3;
763 e2b.
start(pm, a_send, a_count, a_recv_count, e2_round);
768 faces_new_uid.
fill(NULL_ITEM_ID);
770 for (
Int32 i = 0; i < nb_bface; ++i) {
772 is_lone[bfaces[i]] = 1;
774 for (
Int32 p = 0; p < nb_run; ++p) {
775 const Int32 r = run_sent[p];
777 for (
Int32 c = run_cell[r]; c < run_cell[r + 1]; ++c) {
778 Cell cell(cells_of[cells[c].second]);
782 Int64 face_new_uid = NULL_ITEM_UNIQUE_ID;
784 face_new_uid = start + num_back;
788 face_new_uid = start + cell_nb_back[c] + num_lone;
791 if (face_new_uid != NULL_ITEM_UNIQUE_ID) {
792 faces_new_uid[face.
localId()] = face_new_uid;
797 start += cell_nb_back[c] + num_lone;
803 const Int32 s3 = has_foreign_cell ? 2 : 1;
807 for (
Int32 i = 0; i < nb_bface; ++i) {
812 if (partner[a] != partner[b])
813 return partner[a] < partner[b];
814 return key_less(key_of(a), key_of(b));
821 for (
Int32 i : shared) {
823 e3_count[partner[i]] += s3;
825 in_face[partner[i]].
add(i);
826 e3_recv_count[partner[i]] += s3;
830 for (
Int32 i : shared) {
832 e3_send.
add(faces_new_uid[bfaces[i]]);
834 e3_send.
add(faces[bfaces[i]].cell(0).owner());
838 e3.
start(pm, e3_send, e3_count, e3_recv_count, e1_round);
840 for (
Int32 p = 0; p < nb_rank; ++p) {
842 for (
Int32 k = 0; k < in_face[p].
size(); ++k) {
843 Face face(faces[bfaces[in_face[p][k]]]);
844 const Int64 uid = in[
static_cast<Int64>(k) * s3];
845 const Int32 owner = (s3 == 2) ?
static_cast<Int32>(in[
static_cast<Int64>(k) * s3 + 1]) : p;
846 faces_new_uid[face.
localId()] = uid;
856 if (m_mesh_builder->isVerbose()) {
857 faces_opposite_cell_uid.
resize(nb_local_face, NULL_ITEM_ID);
858 for (
Int32 i = 0; i < nb_bface; ++i) {
860 faces_opposite_cell_uid[bfaces[i]] = -2;
865 info() <<
"Distributed face numbering: " << nb_bface <<
" faces with one cell, "
866 << nb_run <<
" runs of cells, " << n2 <<
" runs in slice " << my_rank;
881 Int32 max_cell_local_id = 0;
883 max_cell_local_id = std::max(max_cell_local_id, cell.
localId());
885 my_cells_nb_back_face.
resize(max_cell_local_id + 1);
886 my_cells_nb_back_face.
fill(0);
887 my_cells_faces_info.
clear();
888 my_cells_faces_info.
reserve(m_mesh_builder->oneMeshItemAdder()->nbCell());
894 Integer nb_true_boundary_face = 0;
895 for (
Face face : cell.faces()) {
896 Int64 opposite_cell_uid = faces_opposite_cell_uid[face.localId()];
897 if (face.backCell() == cell)
899 else if (face.nbCell() == 1 && opposite_cell_uid == NULL_ITEM_ID) {
900 ++nb_true_boundary_face;
903 my_cells_nb_back_face[cell_local_id] = nb_back_face;
904 my_cells_faces_info.
add(
T_CellFaceInfo(cell_uid, nb_back_face, nb_true_boundary_face));
906 std::sort(std::begin(my_cells_faces_info), std::end(my_cells_faces_info));
922 Integer my_rank = m_mesh->parallelMng()->commRank();
923 Integer nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
924 bool is_verbose = m_mesh_builder->isVerbose();
930 for (
Integer i = 0, is = nb_local_face; i < is; ++i) {
931 if (faces_new_uid[i] == NULL_ITEM_UNIQUE_ID) {
934 error() <<
"The face lid=" << i <<
" has not been re-indexed.";
938 ARCANE_FATAL(
"Some ({0}) faces have not been reindexed", nb_error);
947 Int64 opposite_cell_uid = faces_opposite_cell_uid[face.localId()];
949 bool true_boundary =
false;
950 bool internal_other =
false;
951 if (face.backCell() == cell) {
953 else if (face.nbCell() == 1) {
954 if (opposite_cell_uid == NULL_ITEM_ID)
955 true_boundary =
true;
960 internal_other =
true;
961 opposite_cell_uid = face.backCell().uniqueId().asInt64();
963 ostr() <<
"NEW UNIQUE ID FOR FACE"
964 <<
" lid=" << face.localId()
965 <<
" cell=" << cell_uid
966 <<
" face=" << face.uniqueId()
967 <<
" nbcell=" << face.nbCell()
968 <<
" cellindex=" << face_index <<
" (";
969 for (
Node node : face.nodes())
970 ostr() <<
' ' << node.uniqueId();
973 ostr() <<
" internal-other";
975 ostr() <<
" true-boundary";
976 if (opposite_cell_uid >= 0) {
977 ostr() <<
" opposite " << opposite_cell_uid;
980 ostr() <<
" (shared)";
985 info() << ostr.str();
986 String file_name(
"faces_uid.");
987 file_name = file_name + my_rank;
988 std::ofstream ofile(file_name.
localstr());
1007 Integer nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
1014 faces_new_uid.
fill(NULL_ITEM_ID);
1020 Integer num_true_boundary_face = 0;
1022 Int64 opposite_cell_uid = faces_opposite_cell_uid[face.localId()];
1023 Int64 face_new_uid = NULL_ITEM_UNIQUE_ID;
1024 if (face.backCell() == cell) {
1025 if (!cells_first_face_uid.
hasKey(cell_uid))
1026 fatal() <<
"NO KEY 0 for cell_uid=" << cell_uid;
1027 face_new_uid = cells_first_face_uid[cell_uid] + num_local_face;
1028 face.mutableItemBase().setOwner(my_rank, my_rank);
1031 else if (face.nbCell() == 1) {
1032 if (opposite_cell_uid == NULL_ITEM_UNIQUE_ID) {
1034 if (!cells_first_face_uid.
hasKey(cell_uid))
1035 fatal() <<
"NO KEY 1 for cell_uid=" << cell_uid;
1036 face_new_uid = cells_first_face_uid[cell_uid] + my_cells_nb_back_face[cell_local_id] + num_true_boundary_face;
1037 ++num_true_boundary_face;
1038 face.mutableItemBase().setOwner(my_rank, my_rank);
1041 if (!cells_first_face_uid.
hasKey(opposite_cell_uid))
1042 fatal() <<
"NO KEY 1 for cell_uid=" << cell_uid <<
" opoosite=" << opposite_cell_uid;
1043 face_new_uid = cells_first_face_uid[opposite_cell_uid] + faces_opposite_cell_index[face.localId()];
1044 face.mutableItemBase().setOwner(faces_opposite_cell_owner[face.localId()], my_rank);
1047 if (face_new_uid != NULL_ITEM_UNIQUE_ID) {
1048 faces_new_uid[face.localId()] = face_new_uid;
1049 face.mutableItemBase().setUniqueId(face_new_uid);
1079 Integer nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
1081 Integer nb_recv_sub_domain_boundary_face = 0;
1110 Integer nb_sub_domain_boundary_face = faces_local_id.
size();
1112 debug() <<
"NB BOUNDARY FACE=" << nb_sub_domain_boundary_face
1113 <<
" NB_FACE=" << nb_local_face
1114 <<
" GLOBAL_NB_BOUNDARY_FACE=" << global_nb_boundary_face;
1127 Int64 step_size = 1500000;
1128 Integer nb_phase = CheckedConvert::toInteger((global_nb_boundary_face / step_size) + 1);
1130 for (
Integer i_phase = 0; i_phase < nb_phase; ++i_phase) {
1131 Integer nb_face_to_send = nb_sub_domain_boundary_face / nb_phase;
1132 Integer first_face_to_send = nb_face_to_send * i_phase;
1133 Integer last_face_to_send = first_face_to_send + nb_face_to_send;
1134 if (i_phase + 1 == nb_phase)
1135 last_face_to_send = nb_sub_domain_boundary_face;
1136 Integer real_nb_face_to_send = last_face_to_send - first_face_to_send;
1138 faces_infos2.
clear();
1139 for (
Integer i_face = first_face_to_send; i_face < first_face_to_send + real_nb_face_to_send; ++i_face) {
1140 Face face(faces[faces_local_id[i_face]]);
1143 faces_infos2.
add(face.
type());
1145 faces_infos2.
add(node.uniqueId().asInt64());
1153 Integer face_index_in_cell = 0;
1154 if (has_back_cell) {
1155 for (
Face current_face_in_cell : cell.
faces()) {
1156 if (current_face_in_cell == face)
1158 if (current_face_in_cell.backCell() == cell)
1159 ++face_index_in_cell;
1163 face_index_in_cell = NULL_ITEM_ID;
1164 faces_infos2.
add(face_index_in_cell);
1166 faces_infos2.
add(IT_NullType);
1170 info() <<
"Number of face bytes received: " << recv_faces_infos.
size()
1171 <<
" phase=" << i_phase <<
"/" << nb_phase
1172 <<
" first_face=" << first_face_to_send
1173 <<
" last_face=" << last_face_to_send
1174 <<
" nb=" << real_nb_face_to_send;
1176 Integer recv_faces_infos_index = 0;
1178 for (
Integer i_sub_domain = 0; i_sub_domain < nb_rank; ++i_sub_domain) {
1179 bool is_end =
false;
1181 if (i_sub_domain == my_rank) {
1182 recv_faces_infos_index += faces_infos2.
size();
1187 Integer face_type = CheckedConvert::toInteger(recv_faces_infos[recv_faces_infos_index]);
1188 ++recv_faces_infos_index;
1189 if (face_type == IT_NullType) {
1197 recv_faces_infos_index += face_nb_node;
1198 Int64 cell_uid = recv_faces_infos[recv_faces_infos_index];
1199 ++recv_faces_infos_index;
1200 Integer cell_owner = CheckedConvert::toInteger(recv_faces_infos[recv_faces_infos_index]);
1201 ++recv_faces_infos_index;
1202 Integer cell_face_index = CheckedConvert::toInteger(recv_faces_infos[recv_faces_infos_index]);
1203 ++recv_faces_infos_index;
1205 Node node = nodes_map.
tryFind(faces_nodes_uid[0]);
1212 ++nb_recv_sub_domain_boundary_face;
1213 faces_opposite_cell_uid[face.
localId()] = cell_uid;
1214 faces_opposite_cell_index[face.
localId()] = cell_face_index;
1215 faces_opposite_cell_owner[face.
localId()] = cell_owner;
1216 cells_first_face_uid.
add(cell_uid, -1);
1220 info() <<
"Number of faces on the subdomain interface: "
1221 << nb_sub_domain_boundary_face <<
' ' << nb_recv_sub_domain_boundary_face;
1225 Int64 max_cell_uid = 0;
1228 if (cell_uid > max_cell_uid)
1229 max_cell_uid = cell_uid;
1232 debug() <<
"GLOBAL MAX CELL UID=" << global_max_cell_uid;
1234 _v1CellBlockSizes(faces_opposite_cell_uid, my_cells_nb_back_face, my_cells_faces_info);
1238 Integer first_cell_index_to_send = 0;
1239 Int64 current_face_uid = 0;
1241 for (
Integer i_phase = 0; i_phase < nb_phase; ++i_phase) {
1242 Integer nb_uid_to_send = CheckedConvert::toInteger(global_max_cell_uid / nb_phase);
1243 Integer first_uid_to_send = nb_uid_to_send * i_phase;
1244 Int64 last_uid_to_send = first_uid_to_send + nb_uid_to_send;
1245 if (i_phase + 1 == nb_phase)
1246 last_uid_to_send = global_max_cell_uid;
1250 for (
Integer zz = first_cell_index_to_send, zs = my_cells_faces_info.
size(); zz < zs; ++zz) {
1251 if (my_cells_faces_info[zz].m_unique_id <= last_uid_to_send)
1256 debug() <<
"FIRST TO SEND=" << first_cell_index_to_send
1257 <<
" NB=" << nb_cell_to_send
1258 <<
" first_uid=" << first_uid_to_send
1259 <<
" last_uid=" << last_uid_to_send;
1261 T_CellFaceInfo* begin_cell_array = my_cells_faces_info.
data() + first_cell_index_to_send;
1262 Int64* begin_array =
reinterpret_cast<Int64*
>(begin_cell_array);
1263 Integer begin_size = nb_cell_to_send * 3;
1269 first_cell_index_to_send += nb_cell_to_send;
1271 info() <<
"Infos faces (received) nb_int64=" << recv_cells_faces_infos.
size();
1272 Integer recv_nb_cell = recv_cells_faces_infos.
size() / 3;
1278 for (
Integer i = 0; i < recv_nb_cell; ++i) {
1279 Int64 cell_uid = recv_cells_faces_infos[i * 3];
1280 global_cells_faces_info[i].m_unique_id = cell_uid;
1281 global_cells_faces_info[i].m_nb_back_face = recv_cells_faces_infos[(i * 3) + 1];
1282 global_cells_faces_info[i].m_nb_true_boundary_face = recv_cells_faces_infos[(i * 3) + 2];
1284 info() <<
"Sorting the faces nb=" << global_cells_faces_info.
size();
1285 std::sort(std::begin(global_cells_faces_info), std::end(global_cells_faces_info));
1287 for (
Integer i = 0; i < recv_nb_cell; ++i) {
1288 Int64 cell_uid = global_cells_faces_info[i].m_unique_id;
1289 if (cells_map.
hasKey(cell_uid) || cells_first_face_uid.
hasKey(cell_uid))
1290 cells_first_face_uid.
add(cell_uid, current_face_uid);
1291 current_face_uid += global_cells_faces_info[i].m_nb_back_face + global_cells_faces_info[i].m_nb_true_boundary_face;
1306 for (BoundaryInfosMapEnumerator i_map(boundary_infos_to_send); ++i_map;) {
1307 Int32 sd = i_map.data()->key();
1313 info() <<
"NB_SEND=" << nb_sender <<
" NB_RECV=" << nb_receiver;
1314 Integer total = nb_sender + nb_receiver;
1316 info() <<
"GLOBAL_NB_MESSAGE=" << global_total;
1325 s->
setMode(ISerializer::ModeReserve);
1335 debug() <<
"END EXCHANGE";
1338template <
typename DataType>
1348 MyInfo(
const DataType& d,
Integer n)
1362 : m_last_index(5000, true)
1367 void add(
Int64 node_uid,
const DataType& data)
1369 Integer current_index = m_values.size();
1371 bool is_add =
false;
1372 HashTableMapT<Int64, Int32>::Data* d = m_last_index.lookupAdd(node_uid, -1, is_add);
1374 m_values.add(
MyInfo(data, d->value()));
1375 d->value() = current_index;
1380 UniqueArray<MyInfo> m_values;
1381 HashTableMapT<Int64, Int32> m_last_index;
1400 Integer nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
1405 faces_opposite_cell_uid.
fill(NULL_ITEM_ID);
1412 faces_new_uid.
fill(NULL_ITEM_ID);
1437 Int64 my_max_node_uid = NULL_ITEM_UNIQUE_ID;
1440 if (node_uid > my_max_node_uid)
1441 my_max_node_uid = node_uid;
1444 debug() <<
"NODE_UID_INFO: MY_MAX_UID=" << my_max_node_uid
1445 <<
" GLOBAL=" << global_max_node_uid;
1448 BoundaryInfosMap boundary_infos_to_send(nb_rank,
true);
1450 info() <<
"NB_CORE modulo=" << uid_to_subdomain_converter.modulo();
1458 if (face_nb_cell == 1) {
1460 is_boundary_nodes[node.
localId()] =
true;
1469 Int32 dest_rank = -1;
1470 if (!is_boundary_nodes[first_node.
localId()]) {
1471 v = nodes_info.
lookupAdd(first_node_uid)->value();
1474 dest_rank = uid_to_subdomain_converter.uidToRank(first_node_uid);
1475 v = boundary_infos_to_send.
lookupAdd(dest_rank)->value();
1477 v.
add(first_node_uid);
1483 if (back_cell.
null())
1484 v.
add(NULL_ITEM_UNIQUE_ID);
1487 if (front_cell.
null())
1488 v.
add(NULL_ITEM_UNIQUE_ID);
1500 Integer nb_receiver = exchanger->nbReceiver();
1501 debug() <<
"NB RECEIVER=" << nb_receiver;
1503 for (
Integer i = 0; i < nb_receiver; ++i) {
1510 received_infos.
resize(nb_info);
1515 while (z < nb_info) {
1516 Int64 node_uid = received_infos[z + 0];
1517 Int32 face_type = (
Int32)received_infos[z + 3];
1532 while (z < nb_info) {
1540 my_max_face_node =
math::max(node_nb_face, my_max_face_node);
1543 debug() <<
"GLOBAL MAX FACE NODE=" << global_max_face_node;
1546 boundary_infos_to_send = BoundaryInfosMap(nb_rank,
true);
1554 while (z < nb_info) {
1555 Int64 node_uid = a[z + 0];
1557 Int64 face_uid = a[z + 2];
1563 Integer face_index = node_nb_face;
1564 Int32 face_new_owner = sender_rank;
1565 for (
Integer y = 0; y < node_nb_face; ++y) {
1566 if (memcmp(&a[indexes[y] + 6], &a[z + 6],
sizeof(
Int64) * face_nb_node) == 0) {
1568 face_new_owner = (
Int32)a[indexes[y] + 1];
1571 Int64 face_new_uid = (node_uid * global_max_face_node) + face_index;
1575 v.
add(face_new_uid);
1576 v.
add(face_new_owner);
1582 my_max_face_node =
math::max(node_nb_face, my_max_face_node);
1589 Integer nb_receiver = exchanger->nbReceiver();
1590 debug() <<
"NB RECEIVER=" << nb_receiver;
1592 for (
Integer i = 0; i < nb_receiver; ++i) {
1597 received_infos.
resize(nb_info);
1599 if ((nb_info % 3) != 0)
1600 ARCANE_FATAL(
"info size can not be divided by 3 v={0}", nb_info);
1602 Int64 nb_item = nb_info / 3;
1603 for (
Int64 z = 0; z < nb_item; ++z) {
1604 Int64 old_uid = received_infos[(z * 3)];
1605 Int64 new_uid = received_infos[(z * 3) + 1];
1606 Int32 new_owner = (
Int32)received_infos[(z * 3) + 2];
1607 impl::MutableItemBase face(faces_map.
tryFind(old_uid));
1609 ARCANE_FATAL(
"Can not find own face uid={0}", old_uid);
1610 face.setUniqueId(new_uid);
1618 debug() <<
"END OF TEST NEW FACE COMPUTE";
1632 bool is_verbose = m_mesh_builder->isVerbose();
1641 if (cell_uid > max_uid)
1644 info() <<
"Max uid=" << max_uid;
1645 Integer nb_computed = max_uid + 1;
1653 Integer nb_true_boundary_face = 0;
1654 for (
Face face : cell.faces()) {
1655 if (face.backCell() == cell)
1657 else if (face.nbCell() == 1) {
1658 ++nb_true_boundary_face;
1661 cell_nb_num_back_face[cell_uid] = nb_num_back_face;
1662 cell_true_boundary_face[cell_uid] = nb_true_boundary_face;
1666 for (
Integer i = 0; i < nb_computed; ++i) {
1667 cell_first_face_uid[i] = current_face_uid;
1668 current_face_uid += cell_nb_num_back_face[i] + cell_true_boundary_face[i];
1674 info() <<
"Recv: Cell FaceInfo celluid=" << i
1675 <<
" firstfaceuid=" << cell_first_face_uid[i]
1676 <<
" nbback=" << cell_nb_num_back_face[i]
1677 <<
" nbbound=" << cell_true_boundary_face[i];
1684 Integer nb_true_boundary_face = 0;
1685 for (
Face face : cell.faces()) {
1686 Int64 face_new_uid = NULL_ITEM_UNIQUE_ID;
1687 if (face.backCell() == cell) {
1688 face_new_uid = cell_first_face_uid[cell_uid] + nb_num_back_face;
1691 else if (face.nbCell() == 1) {
1692 face_new_uid = cell_first_face_uid[cell_uid] + cell_nb_num_back_face[cell_uid] + nb_true_boundary_face;
1693 ++nb_true_boundary_face;
1695 if (face_new_uid != NULL_ITEM_UNIQUE_ID) {
1696 face.mutableItemBase().setUniqueId(face_new_uid);
1706 Int64 opposite_cell_uid = NULL_ITEM_UNIQUE_ID;
1707 bool true_boundary =
false;
1708 bool internal_other =
false;
1709 if (face.backCell() == cell) {
1711 else if (face.nbCell() == 1) {
1712 true_boundary =
true;
1715 internal_other =
true;
1716 opposite_cell_uid = face.backCell().uniqueId().asInt64();
1718 ostr() <<
"NEW LOCAL ID FOR CELLFACE cell_uid=" << cell.
uniqueId() <<
' '
1719 << face_index <<
" uid=" << face.uniqueId() <<
" (";
1720 for (
Node node : face.nodes())
1721 ostr() <<
' ' << node.uniqueId();
1724 ostr() <<
" internal-other";
1726 ostr() <<
" true-boundary";
1727 if (opposite_cell_uid != NULL_ITEM_ID)
1728 ostr() <<
" opposite " << opposite_cell_uid;
1733 info() << ostr.str();
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Integer size() const
Number of elements in the vector.
Modifiable view of an array of type T.
Base class for 1D data vectors.
void fill(ConstReferenceType value)
Fills the array with the value value.
void resize(Int64 s)
Changes the number of elements in the array to s.
ConstArrayView< T > subConstView(Int64 abegin, Int32 asize) const
Sub-view starting from element abegin and containing asize elements.
void copy(Span< const T > rhs)
Copies the values from rhs into the instance.
void clear()
Removes the elements from the array.
iterator begin()
Iterator over the first element of the array.
void add(ConstReferenceType val)
Adds element val to the end of the array.
const T * data() const
Access to the root of the array without any protection.
void reserve(Int64 new_capacity)
Reserves memory for new_capacity elements.
iterator end()
Iterator over the first element after the end of the array.
Class to convert a CellLocalId to a cell.
FaceConnectedListViewType faces() const
List of faces of the cell.
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.
Template class for converting a type.
Class to convert a FaceLocalId to a face.
Cell frontCell() const
Cell in front of the face (null cell if none).
Cell cell(Int32 i) const
i-th cell of the face
Int32 nbCell() const
Number of cells of the face (1 or 2).
bool isSubDomainBoundary() const
Indicates if the face is on the subdomain boundary (i.e nbCell()==1).
Cell backCell() const
Cell behind the face (null cell if none).
Hash table for associative arrays.
Data * lookupAdd(KeyTypeConstRef id, const ValueType &value, bool &is_add)
Searches for or adds the value corresponding to key id.
bool add(KeyTypeConstRef id, const ValueType &value)
Adds the value value corresponding to key id.
bool hasKey(KeyTypeConstRef id)
true if a value with key id is present
Interface of an entity family.
virtual Int32 maxLocalId() const =0
virtual Integer faceBuilderVersion() const =0
Face numbering version.
Information exchange between processors.
virtual void addSender(Int32 rank)=0
Adds a processor to send to.
virtual Integer nbSender() const =0
Number of processors to which we send.
virtual Integer nbReceiver() const =0
Number of processors from which we will receive messages.
virtual bool initializeCommunicationsMessages()=0
Calculates communications.
virtual ISerializeMessage * messageToSend(Integer i)=0
Message intended for the i-th processor.
virtual void processExchange()=0
Performs the exchange using the default options of ParallelExchangerOptions.
Interface of the parallelism manager for a subdomain.
virtual Int32 commRank() const =0
Rank of this instance in the communicator.
virtual void allGatherVariable(ConstArrayView< char > send_buf, Array< char > &recv_buf)=0
Performs an all-gather operation across all processors.
virtual Int32 commSize() const =0
Number of instances in the communicator.
virtual void waitAllRequests(ArrayView< Request > rvalues)=0
Blocks while waiting for the rvalues requests to complete.
virtual IParallelNonBlockingCollective * nonBlockingCollective() const =0
Interface for non-blocking collective operations.
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.
virtual void barrier()=0
Performs a barrier.
Interface for non-blocking collective parallel operations.
virtual Request allReduce(eReduceType rt, ConstArrayView< char > send_buf, ArrayView< char > recv_buf)=0
Performs the reduction of type rt on the array send_buf and stores the result in recv_buf.
void reserveInt64(Int64 n)
Reserve for n Int64.
@ ModePut
The serializer expects reserve().
@ ModeGet
The serializer expects get().
virtual Int64 getInt64()=0
Retrieve a size.
virtual void allocateBuffer()=0
Allocates the serializer memory.
virtual void putSpan(Span< const Real > values)
Add the array values.
virtual void getSpan(Span< Real > values)
Retrieve the array values.
virtual void reserveSpan(eBasicDataType dt, Int64 n)=0
Reserves memory for n values of dt.
virtual void setMode(eMode new_mode)=0
Sets the current mode.
virtual void putInt64(Int64 value)=0
Add the integer value.
virtual void flush()=0
Flushes all streams.
Int32 flags() const
Flags of the entity.
bool null() const
True if the entity is the null entity.
@ II_Shared
The entity is shared by another subdomain.
@ II_HasBackCell
The entity has a back cell.
@ II_SubDomainBoundary
The entity is at the boundary of two subdomains.
Info on a mesh entity type.
Integer nbLocalNode() const
Number of nodes of the entity.
Mesh entity type manager.
ItemTypeInfo * typeFromId(Integer id) const
Type corresponding to the number id.
Unique identifier of an entity.
Node node(Int32 i) const
i-th node of the entity
NodeConnectedListViewType nodes() const
List of nodes of the entity.
Int32 nbNode() const
Number of nodes of the entity.
Base class for a mesh element.
impl::MutableItemBase mutableItemBase() const
Mutable internal part of the entity.
constexpr Int32 localId() const
Local identifier of the entity in the processor subdomain.
Int32 owner() const
Owner subdomain number of the entity.
ItemUniqueId uniqueId() const
Unique identifier across all domains.
constexpr bool null() const
true if the entity is null (i.e. not connected to the mesh)
impl::ItemBase itemBase() const
Internal part of the entity.
Int16 type() const
Entity type.
Interface for a serialization message between IMessagePassingMng.
virtual MessageRank destination() const =0
Destination rank (if isSend() is true) or sender.
virtual ISerializer * serializer()=0
Serializer.
Int32 value() const
Rank value.
void setOwner(Integer suid, Int32 current_sub_domain)
Sets the sub-domain number of the entity owner.
void addFlags(Int32 added_flags)
Adds the flags added_flags to those of the entity.
Output stream linked to a String.
InstanceType * get() const
Associated instance or nullptr if none.
Reference to an instance.
1D vector of data with reference semantics.
constexpr __host__ __device__ pointer data() const noexcept
Pointer to the start of the view.
constexpr __host__ __device__ SizeType size() const noexcept
Returns the size of the array.
View of an array of elements of type T.
Unicode character string.
const char * localstr() const
Returns the conversion of the instance into UTF-8 encoding.
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flow for a debug message.
TraceMessage fatal() const
Flow for a fatal error message.
TraceMessage info() const
Flow for an information message.
TraceMessage error() const
Flow for an error message.
ITraceMng * traceMng() const
Trace manager.
TraceMessage pwarning() const
1D data vector with value semantics (STL style).
Implementation of a mesh.
IParallelMng * parallelMng() override
Parallelism manager.
String name() const override
Mesh name.
IMeshUniqueIdMng * meshUniqueIdMng() const override
Unique ID numbering manager.
void _computeFacesUniqueIdsParallelV2()
Calculates the unique IDs for each face in parallel V2.
void _v1CheckAndDump(Int64ConstArrayView faces_new_uid, Int64ConstArrayView faces_opposite_cell_uid)
Checks that every face has been numbered and, in verbose mode, writes one line per (cell,...
void _v1CellBlockSizes(Int64ConstArrayView faces_opposite_cell_uid, IntegerArray &my_cells_nb_back_face, Array< T_CellFaceInfo > &my_cells_faces_info)
Sizes every cell's block of face ids: its back faces plus its faces of the domain boundary.
void _computeFacesUniqueIdsSequential()
Calculates the unique IDs for each face sequentially.
void _v1AssignFaceUniqueIds(Int64ConstArrayView faces_opposite_cell_uid, IntegerConstArrayView faces_opposite_cell_index, IntegerConstArrayView faces_opposite_cell_owner, HashTableMapT< Int64, Int64 > &cells_first_face_uid, IntegerConstArrayView my_cells_nb_back_face)
Gives every face its uniqueId and its owner from the block starts.
void _v1Distributed()
Distributed computation of the face numbering of version 1.
FaceUniqueIdBuilder(DynamicMeshIncrementalBuilder *mesh_builder)
Constructs an instance for the mesh.
void _exchangeData(IParallelExchanger *exchanger, BoundaryInfosMap &boundary_infos_to_send)
void _v1ByAllGather(Int64ArrayView faces_opposite_cell_uid, IntegerArrayView faces_opposite_cell_index, IntegerArrayView faces_opposite_cell_owner, HashTableMapT< Int64, Int64 > &cells_first_face_uid, IntegerArray &my_cells_nb_back_face, Array< T_CellFaceInfo > &my_cells_faces_info)
The all-gather: every rank receives every boundary face, then every cell of the mesh,...
void _checkNoDuplicate()
Checks that there are no duplicate uniqueIds.
bool m_is_v1_distributed
Distribute the face numbering of version 1 (ARCANE_DISTRIBUTED_FACE_NUMBERING=1).
void _computeFacesUniqueIdsParallelV1()
Calculates the unique numbers for each face in parallel.
A variable all-to-all of Int64.
void start(IParallelMng *pm, ConstArrayView< Int64 > send, ConstArrayView< Int64 > send_count, ConstArrayView< Int64 > recv_count, Int64 nb_round)
Posts the exchange of send, send_count[r] Int64 for rank r.
Span< const Int64 > received() const
What was received, grouped by sending rank.
static Int64 exchangeCounts(IParallelMng *pm, ConstArrayView< Int64 > send_count, Array< Int64 > &recv_count)
Exchanges the counts, per rank, of what an exchange will bring.
void wait()
Completes the exchange.
Span< const Int64 > from(Int32 rank) const
What rank sent.
Associative array of ItemInternal.
void eachItem(const Lambda &lambda)
Template function to iterate over the instance's entities.
bool hasKey(Int64 key)
true if a value with the key id is present
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.
Helper class for parallel determination of face unique_ids.
T max(const T &a, const T &b, const T &c)
Returns the maximum of three elements.
@ ReduceSum
Sum of values.
@ ReduceMax
Maximum of values.
Ref< IParallelExchanger > createExchangerRef(IParallelMng *pm)
Returns an interface to transfer messages between ranks.
Array< Int64 > Int64Array
Dynamic one-dimensional array of 64-bit integers.
ArrayView< Int64 > Int64ArrayView
C equivalent of a 1D array of 64-bit integers.
bool arcaneIsCheck()
True if running in check mode.
UniqueArray< Int64 > Int64UniqueArray
Dynamic 1D array of 64-bit integers.
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
@ Int64
64-bit integer data type
ArrayView< Integer > IntegerArrayView
C equivalent of a 1D array of integers.
Array< Integer > IntegerArray
Dynamic one-dimensional array of integers.
ConstArrayView< Int64 > Int64ConstArrayView
C equivalent of a 1D array of 64-bit integers.
UniqueArray< Int32 > Int32UniqueArray
Dynamic 1D array of 32-bit integers.
double Real
Type representing a real number.
UniqueArray< Integer > IntegerUniqueArray
Dynamic 1D array of integers.
ConstArrayView< Integer > IntegerConstArrayView
C equivalent of a 1D array of integers.
std::int32_t Int32
Signed integer type of 32 bits.