Arcane  4.2.3.0
Developer documentation
Loading...
Searching...
No Matches
FaceUniqueIdBuilder.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/* FaceUniqueIdBuilder.cc (C) 2000-2026 */
9/* */
10/* Construction of unique face identifiers. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
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"
19
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"
27
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"
35
36#include <unordered_set>
37#include <algorithm>
38#include <cstdint>
39#include <fstream>
40#include <utility>
41
42/*---------------------------------------------------------------------------*/
43/*---------------------------------------------------------------------------*/
44
45namespace Arcane::mesh
46{
47
48/*---------------------------------------------------------------------------*/
49/*---------------------------------------------------------------------------*/
50
51extern "C++" void
52_computeFaceUniqueIdVersion3(DynamicMesh* mesh);
53extern "C++" void
54_computeFaceUniqueIdVersion5(DynamicMesh* mesh);
55extern "C++" void
56arcaneComputeCartesianFaceUniqueId(DynamicMesh* mesh);
57
58/*---------------------------------------------------------------------------*/
59/*---------------------------------------------------------------------------*/
60
63: TraceAccessor(mesh_builder->mesh()->traceMng())
64, m_mesh(mesh_builder->mesh())
65, m_mesh_builder(mesh_builder)
66{
67 // ARCANE_DISTRIBUTED_FACE_NUMBERING=1 distributes the computation of the face
68 // numbering of version 1 over the ranks instead of performing it on each.
69 auto distributed = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_DISTRIBUTED_FACE_NUMBERING", true);
70 m_is_v1_distributed = distributed && distributed.value() != 0;
71}
72
73/*---------------------------------------------------------------------------*/
74/*---------------------------------------------------------------------------*/
75
76void FaceUniqueIdBuilder::
77computeFacesUniqueIds()
78{
79 IParallelMng* pm = m_mesh->parallelMng();
80 Real begin_time = platform::getRealTime();
81 Integer face_version = m_mesh->meshUniqueIdMng()->faceBuilderVersion();
82 bool is_parallel = pm->isParallel();
83 info() << "Using version=" << face_version << " to compute faces unique ids"
84 << " mesh=" << m_mesh->name() << " is_parallel=" << is_parallel;
85
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);
88
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";
97 }
98 else {
99 // Version 1 or 2
100 if (is_parallel) {
101 if (face_version == 2) {
102 //NOT YET BY DEFAULT
103 info() << "Use new mesh init in FaceUniqueIdBuilder";
105 }
106 else {
107 // Default version.
109 }
110 }
111 else {
113 }
114 }
115
116 Real end_time = platform::getRealTime();
117 Real diff = (Real)(end_time - begin_time);
118 info() << "TIME to compute face unique ids=" << diff;
119
120 if (arcaneIsCheck())
122
123 ItemInternalMap& faces_map = m_mesh->facesMap();
124
125 // We must re-index #m_faces_map because the uniqueId() of the
126 // faces have been modified
127 if (face_version != 0)
128 m_mesh->faceFamily()->notifyItemsUniqueIdChanged();
129
130 bool is_verbose = m_mesh_builder->isVerbose();
131 if (is_verbose) {
132 info() << "NEW FACES_MAP after re-indexing";
133 faces_map.eachItem([&](Item face) {
134 info() << "Face uid=" << face.uniqueId() << " lid=" << face.localId();
135 });
136 }
137 // With version 0 or 5, the owners are not positioned
138 // We must do it now
139 if (face_version == 0 || face_version == 5) {
140 ItemsOwnerBuilder owner_builder(m_mesh);
141 owner_builder.computeFacesOwner();
142 }
143}
144
145/*---------------------------------------------------------------------------*/
146/*---------------------------------------------------------------------------*/
152{
153 info() << "Check no duplicate face uniqueId";
154 ItemInternalMap& faces_map = m_mesh->facesMap();
155 std::unordered_set<Int64> checked_faces_map;
156 faces_map.eachItem([&](Item face) {
157 ItemUniqueId uid = face.uniqueId();
158 auto p = checked_faces_map.find(uid);
159 if (p != checked_faces_map.end()) {
160 pwarning() << "Duplicate Face UniqueId=" << uid;
161 ARCANE_FATAL("Duplicate Face uniqueId={0}", uid);
162 }
163 checked_faces_map.insert(uid);
164 });
165}
166
167/*---------------------------------------------------------------------------*/
168/*---------------------------------------------------------------------------*/
176class T_CellFaceInfo
177{
178 public:
179
180 T_CellFaceInfo(Int64 uid, Integer nb_back_face, Integer nb_true_boundary_face)
181 : m_unique_id(uid)
182 , m_nb_back_face(nb_back_face)
183 , m_nb_true_boundary_face(nb_true_boundary_face)
184 {
185 }
186
187 T_CellFaceInfo()
188 : m_unique_id(NULL_ITEM_ID)
189 , m_nb_back_face(0)
190 , m_nb_true_boundary_face(0)
191 {
192 }
193
194 public:
195
196 bool operator<(const T_CellFaceInfo& ci) const
197 {
198 return m_unique_id < ci.m_unique_id;
199 }
200
201 public:
202
203 Int64 m_unique_id;
204 Int64 m_nb_back_face;
205 Int64 m_nb_true_boundary_face;
206};
207
208/*---------------------------------------------------------------------------*/
209/*---------------------------------------------------------------------------*/
210
211namespace
212{
213
215inline Int32
216_bucketOfHash(Int64 key, Int32 nb_rank)
217{
218 // splitmix64 finaliser: equal keys meet, consecutive ones do not pile up.
219 uint64_t h = static_cast<uint64_t>(key);
220 h = (h ^ (h >> 30)) * 0xbf58476d1ce4e5b9ULL;
221 h = (h ^ (h >> 27)) * 0x94d049bb133111ebULL;
222 h ^= h >> 31;
223 return static_cast<Int32>(h % static_cast<uint64_t>(nb_rank));
224}
225
239_sliceBounds(IParallelMng* pm, ConstArrayView<Int64> keys, Int64 g_lo, Int64 g_hi)
240{
241 const Int32 nb_rank = pm->commSize();
242 // The more buckets, the better the balance and the larger the sum over the
243 // ranks (nb_bucket_per_slice * nb_rank Int64).
244 const Int64 nb_bucket_per_slice = 4;
245
246 struct Bucket
247 {
248 Int64 lo;
249 Int64 width;
250 Int64 count;
251 };
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 });
256 };
257 // Counts the keys of the buckets not counted yet, summed over the ranks.
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)
262 todo.add(i);
263 }
264 UniqueArray<Int64> c(todo.size());
265 const Int64* k = keys.data();
266 const Int64* k_end = k + keys.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);
270 }
272 for (Int32 i = 0; i < todo.size(); ++i)
273 buckets[todo[i]].count = c[i];
274 };
275
276 UniqueArray<Bucket> buckets;
277 split(buckets, g_lo, g_hi - g_lo + 1, nb_bucket_per_slice * nb_rank);
278 count(buckets);
279 Int64 total = 0;
280 for (const Bucket& b : buckets)
281 total += b.count;
282
283 // A bucket holding more than a slice's share is cut again, into as many
284 // buckets per share as at first. Every rank holds the same histogram, so
285 // every rank cuts the same buckets.
286 for (;;) {
287 UniqueArray<Bucket> next;
288 bool is_cut = false;
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);
292 is_cut = true;
293 }
294 else
295 next.add(b);
296 }
297 if (!is_cut)
298 break;
299 buckets = next;
300 count(buckets);
301 }
302
303 UniqueArray<Int64> bounds(nb_rank + 1, g_hi + 1);
304 bounds[0] = g_lo;
305 Int32 last = 0;
306 Int64 before = 0;
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)
310 bounds[t] = b.lo;
311 last = std::max(last, s);
312 before += b.count;
313 }
314 return bounds;
315}
316
318inline Int32
319_sliceOf(ConstArrayView<Int64> bounds, Int64 uid)
320{
321 // Empty slices repeat a bound; the last of equal bounds is the one that holds uid.
322 return static_cast<Int32>(std::upper_bound(bounds.begin(), bounds.end(), uid) - bounds.begin()) - 1;
323}
324
325} // namespace
326
327/*---------------------------------------------------------------------------*/
328/*---------------------------------------------------------------------------*/
351{
354 return;
355 }
356
357 Integer nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
358
359 UniqueArray<Int64> faces_opposite_cell_uid(nb_local_face);
360 faces_opposite_cell_uid.fill(NULL_ITEM_ID);
361 UniqueArray<Integer> faces_opposite_cell_index(nb_local_face);
362 UniqueArray<Integer> faces_opposite_cell_owner(nb_local_face);
363 HashTableMapT<Int64, Int64> cells_first_face_uid(m_mesh_builder->oneMeshItemAdder()->nbCell() * 2, true);
364 IntegerUniqueArray my_cells_nb_back_face;
365 UniqueArray<T_CellFaceInfo> my_cells_faces_info;
366
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);
369 _v1AssignFaceUniqueIds(faces_opposite_cell_uid, faces_opposite_cell_index, faces_opposite_cell_owner,
370 cells_first_face_uid, my_cells_nb_back_face);
371}
372
373/*---------------------------------------------------------------------------*/
374/*---------------------------------------------------------------------------*/
420{
421 info() << "Computing FaceUniqueIds using distributed version 1";
422 IParallelMng* pm = m_mesh->parallelMng();
423 const Int32 nb_rank = pm->commSize();
424 const Int32 my_rank = pm->commRank();
425 ItemInternalMap& faces_map = m_mesh->facesMap();
426 ItemInternalMap& cells_map = m_mesh->cellsMap();
427 FaceLocalIdToFaceConverter faces(m_mesh->faceFamily());
428 CellLocalIdToCellConverter cells_of(m_mesh->cellFamily());
429 const Int32 nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
430
431 // The faces with one cell here, and the cells by increasing uniqueId.
432 UniqueArray<Int32> bfaces;
433 Int32 max_nb_node = 0;
434 faces_map.eachItem([&](Face face) {
435 if (face.isSubDomainBoundary()) {
436 bfaces.add(face.localId());
437 max_nb_node = std::max(max_nb_node, face.nbNode());
438 }
439 });
440 const Int32 nb_bface = bfaces.size();
441
443 cells.reserve(cells_map.count());
444 Int32 has_foreign_cell = 0;
445 cells_map.eachItem([&](Cell cell) {
446 cells.add(std::make_pair(cell.uniqueId().asInt64(), cell.localId()));
447 if (cell.owner() != my_rank)
448 has_foreign_cell = 1;
449 });
450 std::sort(cells.begin(), cells.end());
451 const Int32 nb_cell = cells.size();
452
453 Int64 g_lo = 0;
454 Int64 g_hi = 0;
455 {
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)
462 return; // no cell anywhere
463 g_lo = -v[1];
464 g_hi = v[2];
465 }
466
467 // --- Step 1, out: one record per face with one cell here, sorted node
468 // uniqueIds padded with -1, then the uniqueId of the cell if it is in front
469 // of the face, -1 if it is behind it.
470 const Int32 s1 = max_nb_node + 1;
471 UniqueArray<Int32> dest(nb_bface);
472 UniqueArray<Int64> e1_count(nb_rank, 0);
473 UniqueArray<Int64> keys(static_cast<Int64>(nb_bface) * max_nb_node);
474 UniqueArray<Int64> nodes_uid;
475 for (Int32 i = 0; i < nb_bface; ++i) {
476 Face face(faces[bfaces[i]]);
478 nodes_uid.clear();
479 for (Node node : face.nodes())
480 nodes_uid.add(node.uniqueId().asInt64());
481 std::sort(nodes_uid.begin(), nodes_uid.end());
482 Int64* k = keys.data() + static_cast<Int64>(i) * max_nb_node;
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;
487 }
488 auto key_of = [&](Int32 i) { return keys.data() + static_cast<Int64>(i) * max_nb_node; };
489 // The order of two node keys, uniqueId by uniqueId
490 auto key_less = [max_nb_node](const Int64* ka, const Int64* kb) {
491 for (Int32 z = 0; z < max_nb_node; ++z) {
492 if (ka[z] != kb[z])
493 return ka[z] < kb[z];
494 }
495 return false;
496 };
497 auto is_back = [&](Int32 i) { return (faces[bfaces[i]].itemBase().flags() & ItemFlags::II_HasBackCell) != 0; };
498
499 UniqueArray<Int64> e1_index(nb_rank + 1, 0);
500 for (Int32 r = 0; r < nb_rank; ++r)
501 e1_index[r + 1] = e1_index[r] + e1_count[r] / s1;
502 // sent[p] = the face sent at position p of the buffer
503 UniqueArray<Int32> sent(nb_bface);
504 UniqueArray<Int64> e1_send(static_cast<Int64>(nb_bface) * s1);
505 {
506 UniqueArray<Int64> at(e1_index.subConstView(0, nb_rank));
507 for (Int32 i = 0; i < nb_bface; ++i) {
508 const Int64 p = at[dest[i]]++;
509 sent[CheckedConvert::toInt32(p)] = i;
510 Int64* r = e1_send.data() + p * s1;
511 const Int64* k = key_of(i);
512 for (Int32 z = 0; z < max_nb_node; ++z)
513 r[z] = k[z];
514 r[max_nb_node] = is_back(i) ? -1 : faces[bfaces[i]].cell(0).uniqueId().asInt64();
515 }
516 }
517 UniqueArray<Int64> e1_recv_count;
518 const Int64 e1_round = Int64AllToAll::exchangeCounts(pm, e1_count, e1_recv_count);
519 Int64AllToAll e1;
520 e1.start(pm, e1_send, e1_count, e1_recv_count, e1_round);
521
522 // --- While it travels: the runs, their slices, and step 2 out.
523 UniqueArray<Int32> cell_nb_back(nb_cell, 0);
524 UniqueArray<Int64> run_starts; // unsplit runs, for the slice bounds
525 for (Int32 c = 0; c < nb_cell; ++c) {
526 Cell cell(cells_of[cells[c].second]);
527 Int32 n = 0;
528 for (Face face : cell.faces()) {
529 if (face.backCell() == cell)
530 ++n;
531 }
532 cell_nb_back[c] = n;
533 if (c == 0 || cells[c].first != cells[c - 1].first + 1)
534 run_starts.add(cells[c].first);
535 }
536 const UniqueArray<Int64> bounds = _sliceBounds(pm, run_starts, g_lo, g_hi);
537
538 // Runs cut at the slice bounds: [run_first[r], run_first[r] + run_count[r]) are
539 // cells[run_cell[r] ...], all in slice run_slice[r].
540 UniqueArray<Int32> run_cell;
541 UniqueArray<Int32> run_slice;
542 UniqueArray<Int64> slice_total(nb_rank, 0); // this rank's part of every slice's total
543 {
544 Int32 s = 0;
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])
549 ++s;
550 if (c == 0 || uid != cells[c - 1].first + 1 || s != old_s) {
551 run_cell.add(c);
552 run_slice.add(s);
553 }
554 slice_total[s] += cell_nb_back[c];
555 }
556 }
557 const Int32 nb_run = run_cell.size();
558 run_cell.add(nb_cell);
559 UniqueArray<Int64> e2_count(nb_rank, 0);
560 for (Int32 r = 0; r < nb_run; ++r)
561 e2_count[run_slice[r]] += 3;
562 UniqueArray<Int64> e2_index(nb_rank + 1, 0);
563 for (Int32 r = 0; r < nb_rank; ++r)
564 e2_index[r + 1] = e2_index[r] + e2_count[r] / 3;
565 UniqueArray<Int32> run_sent(nb_run); // run_sent[p] = the run sent at position p
566 UniqueArray<Int64> e2_send(static_cast<Int64>(nb_run) * 3);
567 {
568 UniqueArray<Int64> at(e2_index.subConstView(0, nb_rank));
569 for (Int32 r = 0; r < nb_run; ++r) {
570 const Int64 p = at[run_slice[r]]++;
571 run_sent[CheckedConvert::toInt32(p)] = r;
572 Int64 nb_back = 0;
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;
578 }
579 }
580 UniqueArray<Int64> e2_recv_count;
581 const Int64 e2_round = Int64AllToAll::exchangeCounts(pm, e2_count, e2_recv_count);
582 Int64AllToAll e2;
583 e2.start(pm, e2_send, e2_count, e2_recv_count, e2_round);
584
585 // --- Step 1 at the meeting rank: pair the halves.
586 e1.wait();
587 const Int32 n1 = CheckedConvert::toInt32(e1.received().size() / s1);
588 UniqueArray<Int32> rec_src(n1);
589 UniqueArray<Int32> rec_pos(n1);
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) {
593 rec_src[i] = r;
594 rec_pos[i] = p;
595 }
596 }
597 auto rec_of = [&](Int32 i) { return e1.received().data() + static_cast<Int64>(i) * s1; };
598 UniqueArray<Int32> order(n1);
599 for (Int32 i = 0; i < n1; ++i)
600 order[i] = i;
601 std::sort(order.begin(), order.end(), [&](Int32 a, Int32 b) { return key_less(rec_of(a), rec_of(b)); });
602 auto same_key = [&](Int32 a, Int32 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) {
606 if (ka[z] != kb[z])
607 return false;
608 }
609 return true;
610 };
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];
615 return o.str();
616 };
617
618 // Answers to the halves of a pair, (position << 32) | rank of the other half;
619 // the cells in front of a lone face, to the rank of their slice.
620 UniqueArray<Int64> pair_answer; // (destination, answer) flattened
621 UniqueArray<Int64> lone_cell; // (slice, cell uid) flattened
622 for (Int32 i = 0; i < n1;) {
623 Int32 j = i + 1;
624 while (j < n1 && same_key(order[i], order[j]))
625 ++j;
626 const Int32 a = order[i];
627 if (j - i == 1) {
628 const Int64 cell_uid = rec_of(a)[max_nb_node];
629 if (cell_uid >= 0) {
630 const Int32 s = _sliceOf(bounds, cell_uid);
631 lone_cell.add(s);
632 lone_cell.add(cell_uid);
633 slice_total[s] += 1;
634 }
635 }
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]);
649 }
650 else
651 ARCANE_FATAL("Face numbering: the face of nodes ({0}) is held by {1} sub-domains",
652 key_string(a), j - i);
653 i = j;
654 }
655
656 // The totals of the slices, summed while step 1 comes back.
657 UniqueArray<Int64> g_slice_total(nb_rank, 0);
658 Parallel::Request total_request;
660 if (nbc)
661 total_request = nbc->allReduce(Parallel::ReduceSum, slice_total, g_slice_total);
662 else {
663 g_slice_total.copy(slice_total);
664 pm->reduce(Parallel::ReduceSum, g_slice_total);
665 }
666
667 // --- Step 1, back: to each rank [nb answers][answers][lone cells].
668 UniqueArray<Int64> b_count(nb_rank, 1);
669 UniqueArray<Int64> b_nb_answer(nb_rank, 0);
670 for (Int64 k = 0; k < pair_answer.size(); k += 2) {
671 ++b_count[pair_answer[k]];
672 ++b_nb_answer[pair_answer[k]];
673 }
674 for (Int64 k = 0; k < lone_cell.size(); k += 2)
675 ++b_count[lone_cell[k]];
676 UniqueArray<Int64> b_index(nb_rank + 1, 0);
677 for (Int32 r = 0; r < nb_rank; ++r)
678 b_index[r + 1] = b_index[r] + b_count[r];
679 UniqueArray<Int64> b_send(b_index[nb_rank]);
680 {
681 UniqueArray<Int64> at(nb_rank);
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;
685 }
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];
690 }
691 UniqueArray<Int64> b_recv_count;
692 const Int64 b_round = Int64AllToAll::exchangeCounts(pm, b_count, b_recv_count);
693 Int64AllToAll e1b;
694 e1b.start(pm, b_send, b_count, b_recv_count, b_round);
695 e1b.wait();
696
697 // partner[i] = the rank holding the other half of face i, -1 if it is alone.
698 UniqueArray<Int32> partner(nb_bface, -1);
699 UniqueArray<Int64> my_lone; // cells of my slice in front of a lone face
700 for (Int32 r = 0; r < nb_rank; ++r) {
701 Span<const Int64> m = e1b.from(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;
707 }
708 for (Int64 k = nb_answer + 1; k < m.size(); ++k)
709 my_lone.add(m[k]);
710 }
711 std::sort(my_lone.begin(), my_lone.end());
712
713 // --- Step 2 at the rank of the slice: the runs in order, the lone faces
714 // in their cells, and the start of every run.
715 e2.wait();
716 if (nbc)
717 pm->waitAllRequests(ArrayView<Parallel::Request>(1, &total_request));
718 Int64 slice_start = 0;
719 for (Int32 r = 0; r < my_rank; ++r)
720 slice_start += g_slice_total[r];
721 const Int32 n2 = CheckedConvert::toInt32(e2.received().size() / 3);
722 const Int64* runs = e2.received().data();
723 UniqueArray<Int32> run_order(n2);
724 for (Int32 i = 0; i < n2; ++i)
725 run_order[i] = i;
726 std::sort(run_order.begin(), run_order.end(),
727 [&](Int32 a, Int32 b) { return runs[a * 3] < runs[b * 3]; });
728 UniqueArray<Int64> a_send(n2);
729 {
730 Int64 running = slice_start;
731 Int64 end_prev = INT64_MIN;
732 Int32 l = 0;
733 const Int32 nb_lone = my_lone.size();
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;
743 running += run[2];
744 for (; l < nb_lone && my_lone[l] < end; ++l)
745 ++running;
746 end_prev = end;
747 }
748 if (l < nb_lone)
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);
753 }
754
755 // --- Step 2, back: one start per run, in the order the runs came.
756 UniqueArray<Int64> a_count(nb_rank);
757 UniqueArray<Int64> a_recv_count(nb_rank);
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;
761 }
762 Int64AllToAll e2b;
763 e2b.start(pm, a_send, a_count, a_recv_count, e2_round);
764 e2b.wait();
765
766 // --- Every face of a cell of this rank that it numbers.
767 UniqueArray<Int64> faces_new_uid(nb_local_face);
768 faces_new_uid.fill(NULL_ITEM_ID);
769 UniqueArray<Int8> is_lone(nb_local_face, 0);
770 for (Int32 i = 0; i < nb_bface; ++i) {
771 if (partner[i] < 0)
772 is_lone[bfaces[i]] = 1;
773 }
774 for (Int32 p = 0; p < nb_run; ++p) {
775 const Int32 r = run_sent[p];
776 Int64 start = e2b.received()[p];
777 for (Int32 c = run_cell[r]; c < run_cell[r + 1]; ++c) {
778 Cell cell(cells_of[cells[c].second]);
779 Integer num_back = 0;
780 Integer num_lone = 0;
781 for (Face face : cell.faces()) {
782 Int64 face_new_uid = NULL_ITEM_UNIQUE_ID;
783 if (face.backCell() == cell) {
784 face_new_uid = start + num_back;
785 ++num_back;
786 }
787 else if (face.nbCell() == 1 && is_lone[face.localId()]) {
788 face_new_uid = start + cell_nb_back[c] + num_lone;
789 ++num_lone;
790 }
791 if (face_new_uid != NULL_ITEM_UNIQUE_ID) {
792 faces_new_uid[face.localId()] = face_new_uid;
793 face.mutableItemBase().setUniqueId(face_new_uid);
794 face.mutableItemBase().setOwner(my_rank, my_rank);
795 }
796 }
797 start += cell_nb_back[c] + num_lone;
798 }
799 }
800
801 // --- Step 3: the rank behind a shared face tells the rank in front.
802 {
803 const Int32 s3 = has_foreign_cell ? 2 : 1;
804 // The shared faces grouped by partner, back ones and front ones apart,
805 // each group in node order: both sides list the faces they share alike.
806 UniqueArray<Int32> shared;
807 for (Int32 i = 0; i < nb_bface; ++i) {
808 if (partner[i] >= 0)
809 shared.add(i);
810 }
811 std::sort(shared.begin(), shared.end(), [&](Int32 a, Int32 b) {
812 if (partner[a] != partner[b])
813 return partner[a] < partner[b];
814 return key_less(key_of(a), key_of(b));
815 });
816 // The messages of step 3 are no larger than those of step 1, so they
817 // need no more rounds; their sizes are known on both sides.
818 UniqueArray<Int64> e3_count(nb_rank, 0);
819 UniqueArray<Int64> e3_recv_count(nb_rank, 0);
820 UniqueArray<UniqueArray<Int32>> in_face(nb_rank);
821 for (Int32 i : shared) {
822 if (is_back(i))
823 e3_count[partner[i]] += s3;
824 else {
825 in_face[partner[i]].add(i);
826 e3_recv_count[partner[i]] += s3;
827 }
828 }
829 UniqueArray<Int64> e3_send;
830 for (Int32 i : shared) {
831 if (is_back(i)) {
832 e3_send.add(faces_new_uid[bfaces[i]]);
833 if (s3 == 2)
834 e3_send.add(faces[bfaces[i]].cell(0).owner());
835 }
836 }
837 Int64AllToAll e3;
838 e3.start(pm, e3_send, e3_count, e3_recv_count, e1_round);
839 e3.wait();
840 for (Int32 p = 0; p < nb_rank; ++p) {
841 Span<const Int64> in = e3.from(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;
847 face.mutableItemBase().setUniqueId(uid);
848 face.mutableItemBase().setOwner(owner, my_rank);
849 }
850 }
851 }
852
853 // Only the verbose listing reads it; the cell on the other side of a shared
854 // face is not known here.
855 UniqueArray<Int64> faces_opposite_cell_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) {
859 if (partner[i] >= 0)
860 faces_opposite_cell_uid[bfaces[i]] = -2;
861 }
862 }
863 _v1CheckAndDump(faces_new_uid, faces_opposite_cell_uid);
864
865 info() << "Distributed face numbering: " << nb_bface << " faces with one cell, "
866 << nb_run << " runs of cells, " << n2 << " runs in slice " << my_rank;
867}
868
869/*---------------------------------------------------------------------------*/
870/*---------------------------------------------------------------------------*/
876_v1CellBlockSizes(Int64ConstArrayView faces_opposite_cell_uid,
877 IntegerArray& my_cells_nb_back_face,
878 Array<T_CellFaceInfo>& my_cells_faces_info)
879{
880 ItemInternalMap& cells_map = m_mesh->cellsMap();
881 Int32 max_cell_local_id = 0;
882 cells_map.eachItem([&](Item cell) {
883 max_cell_local_id = std::max(max_cell_local_id, cell.localId());
884 });
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());
889
890 cells_map.eachItem([&](Cell cell) {
891 Int64 cell_uid = cell.uniqueId().asInt64();
892 Int32 cell_local_id = cell.localId();
893 Integer nb_back_face = 0;
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)
898 ++nb_back_face;
899 else if (face.nbCell() == 1 && opposite_cell_uid == NULL_ITEM_ID) {
900 ++nb_true_boundary_face;
901 }
902 }
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));
905 });
906 std::sort(std::begin(my_cells_faces_info), std::end(my_cells_faces_info));
907}
908
909/*---------------------------------------------------------------------------*/
910/*---------------------------------------------------------------------------*/
920_v1CheckAndDump(Int64ConstArrayView faces_new_uid, Int64ConstArrayView faces_opposite_cell_uid)
921{
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();
925 ItemInternalMap& cells_map = m_mesh->cellsMap();
926
927 // Verifies that all faces have been re-indexed
928 {
929 Integer nb_error = 0;
930 for (Integer i = 0, is = nb_local_face; i < is; ++i) {
931 if (faces_new_uid[i] == NULL_ITEM_UNIQUE_ID) {
932 ++nb_error;
933 if (nb_error < 10)
934 error() << "The face lid=" << i << " has not been re-indexed.";
935 }
936 }
937 if (nb_error != 0)
938 ARCANE_FATAL("Some ({0}) faces have not been reindexed", nb_error);
939 }
940
941 if (is_verbose) {
942 OStringStream ostr;
943 cells_map.eachItem([&](Cell cell) {
944 Int64 cell_uid = cell.uniqueId().asInt64();
945 Integer face_index = 0;
946 for (Face face : cell.faces()) {
947 Int64 opposite_cell_uid = faces_opposite_cell_uid[face.localId()];
948 bool shared = false;
949 bool true_boundary = false;
950 bool internal_other = false;
951 if (face.backCell() == cell) {
952 }
953 else if (face.nbCell() == 1) {
954 if (opposite_cell_uid == NULL_ITEM_ID)
955 true_boundary = true;
956 else
957 shared = true;
958 }
959 else {
960 internal_other = true;
961 opposite_cell_uid = face.backCell().uniqueId().asInt64();
962 }
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();
971 ostr() << ")";
972 if (internal_other)
973 ostr() << " internal-other";
974 if (true_boundary)
975 ostr() << " true-boundary";
976 if (opposite_cell_uid >= 0) {
977 ostr() << " opposite " << opposite_cell_uid;
978 }
979 if (shared)
980 ostr() << " (shared)";
981 ostr() << "\n";
982 ++face_index;
983 }
984 });
985 info() << ostr.str();
986 String file_name("faces_uid.");
987 file_name = file_name + my_rank;
988 std::ofstream ofile(file_name.localstr());
989 ofile << ostr.str();
990 }
991}
992
993/*---------------------------------------------------------------------------*/
994/*---------------------------------------------------------------------------*/
999_v1AssignFaceUniqueIds(Int64ConstArrayView faces_opposite_cell_uid,
1000 IntegerConstArrayView faces_opposite_cell_index,
1001 IntegerConstArrayView faces_opposite_cell_owner,
1002 HashTableMapT<Int64, Int64>& cells_first_face_uid,
1003 IntegerConstArrayView my_cells_nb_back_face)
1004{
1005 IParallelMng* pm = m_mesh->parallelMng();
1006 Integer my_rank = pm->commRank();
1007 Integer nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
1008 ItemInternalMap& cells_map = m_mesh->cellsMap();
1009
1010 // For verification, ensures that all elements of this array
1011 // are valid, which means that all faces have been
1012 // renumbered
1013 UniqueArray<Int64> faces_new_uid(nb_local_face);
1014 faces_new_uid.fill(NULL_ITEM_ID);
1015
1016 cells_map.eachItem([&](Cell cell) {
1017 Int64 cell_uid = cell.uniqueId();
1018 Int32 cell_local_id = cell.localId();
1019 Integer num_local_face = 0;
1020 Integer num_true_boundary_face = 0;
1021 for (Face face : cell.faces()) {
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);
1029 ++num_local_face;
1030 }
1031 else if (face.nbCell() == 1) {
1032 if (opposite_cell_uid == NULL_ITEM_UNIQUE_ID) {
1033 // This is a boundary face of the initial domain
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);
1039 }
1040 else {
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);
1045 }
1046 }
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);
1050 }
1051 }
1052 });
1053
1054 _v1CheckAndDump(faces_new_uid, faces_opposite_cell_uid);
1055}
1056
1057/*---------------------------------------------------------------------------*/
1058/*---------------------------------------------------------------------------*/
1068_v1ByAllGather(Int64ArrayView faces_opposite_cell_uid,
1069 IntegerArrayView faces_opposite_cell_index,
1070 IntegerArrayView faces_opposite_cell_owner,
1071 HashTableMapT<Int64, Int64>& cells_first_face_uid,
1072 IntegerArray& my_cells_nb_back_face,
1073 Array<T_CellFaceInfo>& my_cells_faces_info)
1074{
1075 IParallelMng* pm = m_mesh->parallelMng();
1076 Integer my_rank = pm->commRank();
1077 Integer nb_rank = pm->commSize();
1078
1079 Integer nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
1080
1081 Integer nb_recv_sub_domain_boundary_face = 0;
1082
1083 Int64UniqueArray faces_infos;
1084 faces_infos.reserve(10000);
1085 ItemInternalMap& cells_map = m_mesh->cellsMap();
1086 ItemInternalMap& faces_map = m_mesh->facesMap();
1087 ItemInternalMap& nodes_map = m_mesh->nodesMap();
1088
1089 // Gather data from other processors into recv_cells;
1090 // To prevent the arrays from being too large, we proceed in several
1091 // steps.
1092 // Each sub-domain builds its list of boundary faces, with for each face:
1093 // - its type
1094 // - the list of its nodes,
1095 // - the unique number of its cell
1096 // - the owner of its cell
1097 // - its index in its cell
1098 // This list will then be sent to all sub-domains.
1099 {
1100 ItemTypeMng* itm = m_mesh->itemTypeMng();
1101
1102 UniqueArray<Int32> faces_local_id;
1103
1104 faces_map.eachItem([&](Face face) {
1105 bool boundary_val = face.isSubDomainBoundary();
1106 if (boundary_val)
1107 faces_local_id.add(face.localId());
1108 });
1109
1110 Integer nb_sub_domain_boundary_face = faces_local_id.size();
1111 Int64 global_nb_boundary_face = pm->reduce(Parallel::ReduceSum, (Int64)nb_sub_domain_boundary_face);
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;
1115
1116 Int64UniqueArray faces_infos2;
1117 Int64UniqueArray recv_faces_infos;
1118
1119 // Calculate the size of a send block
1120 // The memory required for a face is equal to nb_node + 4.
1121 // If we assume we have quadrangles in general, this
1122 // makes 8 Int64 per face, or 64 bytes per face.
1123 // The memory required to send everything is therefore 64 * global_nb_boundary_face.
1124 // step_size * nb_proc * 64 bytes.
1125 // The default step_size is calculated so that the required memory
1126 // is on the order of 100 Mo for each message.
1127 Int64 step_size = 1500000;
1128 Integer nb_phase = CheckedConvert::toInteger((global_nb_boundary_face / step_size) + 1);
1129 FaceLocalIdToFaceConverter faces(m_mesh->faceFamily());
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;
1137
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]]);
1142 bool has_back_cell = face.itemBase().flags() & ItemFlags::II_HasBackCell;
1143 faces_infos2.add(face.type());
1144 for (Node node : face.nodes())
1145 faces_infos2.add(node.uniqueId().asInt64());
1146
1147 //info() << " ADD FACE lid=" << face->localId();
1148
1149 Cell cell = face.cell(0);
1150 faces_infos2.add(cell.uniqueId().asInt64());
1151 faces_infos2.add(cell.owner());
1152
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)
1157 break;
1158 if (current_face_in_cell.backCell() == cell)
1159 ++face_index_in_cell;
1160 }
1161 }
1162 else
1163 face_index_in_cell = NULL_ITEM_ID;
1164 faces_infos2.add(face_index_in_cell);
1165 }
1166 faces_infos2.add(IT_NullType); // To indicate that the list ends
1167
1168 pm->allGatherVariable(faces_infos2, recv_faces_infos);
1169
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;
1175
1176 Integer recv_faces_infos_index = 0;
1177
1178 for (Integer i_sub_domain = 0; i_sub_domain < nb_rank; ++i_sub_domain) {
1179 bool is_end = false;
1180 // We must not read the info that comes from me
1181 if (i_sub_domain == my_rank) {
1182 recv_faces_infos_index += faces_infos2.size();
1183 continue;
1184 }
1185 // Deserializes the info for each subdomain
1186 while (!is_end) {
1187 Integer face_type = CheckedConvert::toInteger(recv_faces_infos[recv_faces_infos_index]);
1188 ++recv_faces_infos_index;
1189 if (face_type == IT_NullType) {
1190 is_end = true;
1191 break;
1192 }
1193 ItemTypeInfo* itt = itm->typeFromId(face_type);
1194 Integer face_nb_node = itt->nbLocalNode();
1195 ConstArrayView<Int64> faces_nodes_uid(face_nb_node, &recv_faces_infos[recv_faces_infos_index]);
1196
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;
1204
1205 Node node = nodes_map.tryFind(faces_nodes_uid[0]);
1206 // If the face does not exist in my subdomain, it is not of interest to me
1207 if (node.null())
1208 continue;
1209 Face face = ItemTools::findFaceInNode2(node, face_type, faces_nodes_uid);
1210 if (face.null())
1211 continue;
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);
1217 }
1218 }
1219 }
1220 info() << "Number of faces on the subdomain interface: "
1221 << nb_sub_domain_boundary_face << ' ' << nb_recv_sub_domain_boundary_face;
1222 }
1223
1224 // Finds the max uniqueId of the cells across all subdomains.
1225 Int64 max_cell_uid = 0;
1226 cells_map.eachItem([&](Item cell) {
1227 Int64 cell_uid = cell.uniqueId().asInt64();
1228 if (cell_uid > max_cell_uid)
1229 max_cell_uid = cell_uid;
1230 });
1231 Int64 global_max_cell_uid = pm->reduce(Parallel::ReduceMax, max_cell_uid);
1232 debug() << "GLOBAL MAX CELL UID=" << global_max_cell_uid;
1233
1234 _v1CellBlockSizes(faces_opposite_cell_uid, my_cells_nb_back_face, my_cells_faces_info);
1235
1236 {
1237 Integer nb_phase = 16;
1238 Integer first_cell_index_to_send = 0;
1239 Int64 current_face_uid = 0;
1240
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;
1247
1248 //Integer last_cell_index_to_send = first_cell_index_to_send;
1249 Integer nb_cell_to_send = 0;
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)
1252 ++nb_cell_to_send;
1253 else
1254 break;
1255 }
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;
1260
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;
1264
1265 Int64ConstArrayView cells_faces_infos(begin_size, begin_array);
1266
1267 Int64UniqueArray recv_cells_faces_infos;
1268 pm->allGatherVariable(cells_faces_infos, recv_cells_faces_infos);
1269 first_cell_index_to_send += nb_cell_to_send;
1270
1271 info() << "Infos faces (received) nb_int64=" << recv_cells_faces_infos.size();
1272 Integer recv_nb_cell = recv_cells_faces_infos.size() / 3;
1273
1274 // NOTE: since we know the possible min and max uid, we can optimize by
1275 // creating an array dimensioned with this min and max as bounds and
1276 // filling the elements of this array directly. This way, we
1277 UniqueArray<T_CellFaceInfo> global_cells_faces_info(recv_nb_cell);
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];
1283 }
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));
1286
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;
1292 }
1293 }
1294 }
1295}
1296
1297/*---------------------------------------------------------------------------*/
1298/*---------------------------------------------------------------------------*/
1304_exchangeData(IParallelExchanger* exchanger, BoundaryInfosMap& boundary_infos_to_send)
1305{
1306 for (BoundaryInfosMapEnumerator i_map(boundary_infos_to_send); ++i_map;) {
1307 Int32 sd = i_map.data()->key();
1308 exchanger->addSender(sd);
1309 }
1311 Integer nb_sender = exchanger->nbSender();
1312 Integer nb_receiver = exchanger->nbReceiver();
1313 info() << "NB_SEND=" << nb_sender << " NB_RECV=" << nb_receiver;
1314 Integer total = nb_sender + nb_receiver;
1315 Integer global_total = exchanger->parallelMng()->reduce(Parallel::ReduceSum, total);
1316 info() << "GLOBAL_NB_MESSAGE=" << global_total;
1317
1318 {
1319 for (Integer i = 0, ns = exchanger->nbSender(); i < ns; ++i) {
1320 ISerializeMessage* sm = exchanger->messageToSend(i);
1321 Int32 rank = sm->destination().value();
1322 ISerializer* s = sm->serializer();
1323 Int64ConstArrayView infos = boundary_infos_to_send[rank];
1324 Integer nb_info = infos.size();
1325 s->setMode(ISerializer::ModeReserve);
1326 s->reserveInt64(1); // For the number of elements
1327 s->reserveSpan(eBasicDataType::Int64, nb_info); // For the elements
1328 s->allocateBuffer();
1330 s->putInt64(nb_info);
1331 s->putSpan(infos);
1332 }
1333 }
1334 exchanger->processExchange();
1335 debug() << "END EXCHANGE";
1336}
1337
1338template <typename DataType>
1340{
1341 public:
1342 private:
1343
1344 class MyInfo
1345 {
1346 public:
1347
1348 MyInfo(const DataType& d, Integer n)
1349 : data(d)
1350 , next_index(n)
1351 {}
1352
1353 public:
1354
1355 DataType data;
1356 Integer next_index;
1357 };
1358
1359 public:
1360
1361 ItemInfoMultiList()
1362 : m_last_index(5000, true)
1363 {}
1364
1365 public:
1366
1367 void add(Int64 node_uid, const DataType& data)
1368 {
1369 Integer current_index = m_values.size();
1370
1371 bool is_add = false;
1372 HashTableMapT<Int64, Int32>::Data* d = m_last_index.lookupAdd(node_uid, -1, is_add);
1373
1374 m_values.add(MyInfo(data, d->value()));
1375 d->value() = current_index;
1376 }
1377
1378 public:
1379
1380 UniqueArray<MyInfo> m_values;
1381 HashTableMapT<Int64, Int32> m_last_index;
1382};
1383
1384/*---------------------------------------------------------------------------*/
1385/*---------------------------------------------------------------------------*/
1395{
1396 IParallelMng* pm = m_mesh->parallelMng();
1397 Integer my_rank = pm->commRank();
1398 Integer nb_rank = pm->commSize();
1399
1400 Integer nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
1401 //Integer nb_local_cell = m_mesh_builder->nbCell();
1402 //bool is_verbose = m_mesh_builder->isVerbose();
1403
1404 Int64UniqueArray faces_opposite_cell_uid(nb_local_face);
1405 faces_opposite_cell_uid.fill(NULL_ITEM_ID);
1406 IntegerUniqueArray faces_opposite_cell_index(nb_local_face);
1407 IntegerUniqueArray faces_opposite_cell_owner(nb_local_face);
1408
1409 // For verification, ensures that all elements of this array
1410 // are valid, which means that all faces have been renumbered.
1411 Int64UniqueArray faces_new_uid(nb_local_face);
1412 faces_new_uid.fill(NULL_ITEM_ID);
1413
1414 Int64UniqueArray faces_infos;
1415 faces_infos.reserve(10000);
1416 ItemInternalMap& faces_map = m_mesh->facesMap();
1417 ItemInternalMap& nodes_map = m_mesh->nodesMap();
1418
1419 // NOTE: this array is not useful on all cells. It
1420 // is enough that it contains the cells we need, that is,
1421 // ours + those connected to one of our faces.
1422 HashTableMapT<Int32, Int32> cell_first_face_uid(m_mesh_builder->oneMeshItemAdder()->nbCell() * 2, true);
1423
1424 // Collects data from other processors into recv_cells;
1425 // To prevent the arrays from being too large, we proceed in several
1426 // steps.
1427 // Each subdomain builds its list of boundary faces, for each face:
1428 // - its type
1429 // - the list of its nodes,
1430 // - the unique ID of its cell
1431 // - the owner of its cell
1432 // - its index in its cell
1433 // This list will then be sent to all subdomains.
1434 ItemTypeMng* itm = m_mesh->itemTypeMng();
1435
1436 // Determines the max unique id of the nodes
1437 Int64 my_max_node_uid = NULL_ITEM_UNIQUE_ID;
1438 nodes_map.eachItem([&](Item node) {
1439 Int64 node_uid = node.uniqueId();
1440 if (node_uid > my_max_node_uid)
1441 my_max_node_uid = node_uid;
1442 });
1443 Int64 global_max_node_uid = pm->reduce(Parallel::ReduceMax, my_max_node_uid);
1444 debug() << "NODE_UID_INFO: MY_MAX_UID=" << my_max_node_uid
1445 << " GLOBAL=" << global_max_node_uid;
1446
1447 //TODO: choose a good value to initialize the table
1448 BoundaryInfosMap boundary_infos_to_send(nb_rank, true);
1449 NodeUidToSubDomain uid_to_subdomain_converter(global_max_node_uid, nb_rank);
1450 info() << "NB_CORE modulo=" << uid_to_subdomain_converter.modulo();
1451 HashTableMapT<Int64, SharedArray<Int64>> nodes_info(100000, true);
1452 IItemFamily* node_family = m_mesh->nodeFamily();
1453 UniqueArray<bool> is_boundary_nodes(node_family->maxLocalId(), false);
1454
1455 // Marks all boundary nodes because these are the ones that need to be sent
1456 faces_map.eachItem([&](Face face) {
1457 Integer face_nb_cell = face.nbCell();
1458 if (face_nb_cell == 1) {
1459 for (Node node : face.nodes())
1460 is_boundary_nodes[node.localId()] = true;
1461 }
1462 });
1463
1464 // Determines the list of boundary faces
1465 faces_map.eachItem([&](Face face) {
1466 Node first_node = face.node(0);
1467 Int64 first_node_uid = first_node.uniqueId();
1469 Int32 dest_rank = -1;
1470 if (!is_boundary_nodes[first_node.localId()]) {
1471 v = nodes_info.lookupAdd(first_node_uid)->value();
1472 }
1473 else {
1474 dest_rank = uid_to_subdomain_converter.uidToRank(first_node_uid);
1475 v = boundary_infos_to_send.lookupAdd(dest_rank)->value();
1476 }
1477 v.add(first_node_uid); // 0
1478 v.add(my_rank); // 1
1479 v.add(face.uniqueId()); // 2
1480 v.add(face.type()); // 3
1481 Cell back_cell = face.backCell();
1482 Cell front_cell = face.frontCell();
1483 if (back_cell.null()) // 4 : only used for debug
1484 v.add(NULL_ITEM_UNIQUE_ID);
1485 else
1486 v.add(back_cell.uniqueId());
1487 if (front_cell.null()) // 5 : only used for debug
1488 v.add(NULL_ITEM_UNIQUE_ID);
1489 else
1490 v.add(front_cell.uniqueId());
1491 for (Integer z = 0, zs = face.nbNode(); z < zs; ++z)
1492 v.add(face.node(z).uniqueId());
1493 });
1494
1495 // Positions the list of sends
1497 _exchangeData(exchanger.get(), boundary_infos_to_send);
1498
1499 {
1500 Integer nb_receiver = exchanger->nbReceiver();
1501 debug() << "NB RECEIVER=" << nb_receiver;
1502 Int64UniqueArray received_infos;
1503 for (Integer i = 0; i < nb_receiver; ++i) {
1504 ISerializeMessage* sm = exchanger->messageToReceive(i);
1505 //Int32 orig_rank = sm->destSubDomain();
1506 ISerializer* s = sm->serializer();
1508 Int64 nb_info = s->getInt64();
1509 //info() << "RECEIVE NB_INFO=" << nb_info << " from=" << orig_rank;
1510 received_infos.resize(nb_info);
1511 s->getSpan(received_infos);
1512 //if ((nb_info % 3)!=0)
1513 //fatal() << "info size can not be divided by 3";
1514 Integer z = 0;
1515 while (z < nb_info) {
1516 Int64 node_uid = received_infos[z + 0];
1517 Int32 face_type = (Int32)received_infos[z + 3];
1518 ItemTypeInfo* itt = itm->typeFromId(face_type);
1519 Integer face_nb_node = itt->nbLocalNode();
1520 Int64Array& a = nodes_info.lookupAdd(node_uid)->value();
1521 a.addRange(Int64ConstArrayView(6 + face_nb_node, &received_infos[z]));
1522 z += 6;
1523 z += face_nb_node;
1524 }
1525 }
1526 Integer my_max_face_node = 0;
1527 for (HashTableMapT<Int64, SharedArray<Int64>>::Enumerator inode(nodes_info); ++inode;) {
1528 Int64ConstArrayView a = *inode;
1529 Integer nb_info = a.size();
1530 Integer z = 0;
1531 Integer node_nb_face = 0;
1532 while (z < nb_info) {
1533 ++node_nb_face;
1534 Int32 face_type = (Int32)a[z + 3];
1535 ItemTypeInfo* itt = itm->typeFromId(face_type);
1536 Integer face_nb_node = itt->nbLocalNode();
1537 z += 6;
1538 z += face_nb_node;
1539 }
1540 my_max_face_node = math::max(node_nb_face, my_max_face_node);
1541 }
1542 Integer global_max_face_node = pm->reduce(Parallel::ReduceMax, my_max_face_node);
1543 debug() << "GLOBAL MAX FACE NODE=" << global_max_face_node;
1544 // OK, maintenant donne comme uid de la face (node_uid * global_max_face_node + index)
1545 IntegerUniqueArray indexes;
1546 boundary_infos_to_send = BoundaryInfosMap(nb_rank, true);
1547
1548 for (HashTableMapT<Int64, SharedArray<Int64>>::Enumerator inode(nodes_info); ++inode;) {
1549 Int64ConstArrayView a = *inode;
1550 Integer nb_info = a.size();
1551 Integer z = 0;
1552 Integer node_nb_face = 0;
1553 indexes.clear();
1554 while (z < nb_info) {
1555 Int64 node_uid = a[z + 0];
1556 Int32 sender_rank = (Int32)a[z + 1];
1557 Int64 face_uid = a[z + 2];
1558 Int32 face_type = (Int32)a[z + 3];
1559 ItemTypeInfo* itt = itm->typeFromId(face_type);
1560 Integer face_nb_node = itt->nbLocalNode();
1561
1562 // Checks if the face is already in the list:
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) {
1567 face_index = y;
1568 face_new_owner = (Int32)a[indexes[y] + 1];
1569 }
1570 }
1571 Int64 face_new_uid = (node_uid * global_max_face_node) + face_index;
1572 Int64Array& v = boundary_infos_to_send.lookupAdd(sender_rank)->value();
1573 // Indicates to the owner of this face its new uid
1574 v.add(face_uid);
1575 v.add(face_new_uid);
1576 v.add(face_new_owner);
1577 indexes.add(z);
1578 z += 6;
1579 z += face_nb_node;
1580 ++node_nb_face;
1581 }
1582 my_max_face_node = math::max(node_nb_face, my_max_face_node);
1583 }
1584 }
1586
1587 _exchangeData(exchanger.get(), boundary_infos_to_send);
1588 {
1589 Integer nb_receiver = exchanger->nbReceiver();
1590 debug() << "NB RECEIVER=" << nb_receiver;
1591 Int64UniqueArray received_infos;
1592 for (Integer i = 0; i < nb_receiver; ++i) {
1593 ISerializeMessage* sm = exchanger->messageToReceive(i);
1594 ISerializer* s = sm->serializer();
1596 Int64 nb_info = s->getInt64();
1597 received_infos.resize(nb_info);
1598 s->getSpan(received_infos);
1599 if ((nb_info % 3) != 0)
1600 ARCANE_FATAL("info size can not be divided by 3 v={0}", nb_info);
1601 ;
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));
1608 if (face.null())
1609 ARCANE_FATAL("Can not find own face uid={0}", old_uid);
1610 face.setUniqueId(new_uid);
1611 face.setOwner(new_owner, my_rank);
1612 }
1613 }
1614 }
1615
1616 traceMng()->flush();
1617 pm->barrier();
1618 debug() << "END OF TEST NEW FACE COMPUTE";
1619 return;
1620}
1621
1622/*---------------------------------------------------------------------------*/
1623/*---------------------------------------------------------------------------*/
1631{
1632 bool is_verbose = m_mesh_builder->isVerbose();
1633
1634 ItemInternalMap& cells_map = m_mesh->cellsMap();
1635
1636 // In sequential mode, the uniqueIds() of the cells cannot exceed the
1637 // size of Integers even in 32 bits.
1638 Int32 max_uid = 0;
1639 cells_map.eachItem([&](Item cell) {
1640 Int32 cell_uid = cell.uniqueId().asInt32();
1641 if (cell_uid > max_uid)
1642 max_uid = cell_uid;
1643 });
1644 info() << "Max uid=" << max_uid;
1645 Integer nb_computed = max_uid + 1;
1646 Int32UniqueArray cell_first_face_uid(nb_computed, 0);
1647 Int32UniqueArray cell_nb_num_back_face(nb_computed, 0);
1648 Int32UniqueArray cell_true_boundary_face(nb_computed, 0);
1649
1650 cells_map.eachItem([&](Cell cell) {
1651 Int32 cell_uid = cell.uniqueId().asInt32();
1652 Integer nb_num_back_face = 0;
1653 Integer nb_true_boundary_face = 0;
1654 for (Face face : cell.faces()) {
1655 if (face.backCell() == cell)
1656 ++nb_num_back_face;
1657 else if (face.nbCell() == 1) {
1658 ++nb_true_boundary_face;
1659 }
1660 }
1661 cell_nb_num_back_face[cell_uid] = nb_num_back_face;
1662 cell_true_boundary_face[cell_uid] = nb_true_boundary_face;
1663 });
1664
1665 Integer current_face_uid = 0;
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];
1669 }
1670
1671 if (is_verbose) {
1672 cells_map.eachItem([&](Item cell) {
1673 Int32 i = cell.uniqueId().asInt32();
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];
1678 });
1679 }
1680
1681 cells_map.eachItem([&](Cell cell) {
1682 Int32 cell_uid = cell.uniqueId().asInt32();
1683 Integer nb_num_back_face = 0;
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;
1689 ++nb_num_back_face;
1690 }
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;
1694 }
1695 if (face_new_uid != NULL_ITEM_UNIQUE_ID) {
1696 face.mutableItemBase().setUniqueId(face_new_uid);
1697 }
1698 }
1699 });
1700
1701 if (is_verbose) {
1702 OStringStream ostr;
1703 cells_map.eachItem([&](Cell cell) {
1704 Integer face_index = 0;
1705 for (Face face : cell.faces()) {
1706 Int64 opposite_cell_uid = NULL_ITEM_UNIQUE_ID;
1707 bool true_boundary = false;
1708 bool internal_other = false;
1709 if (face.backCell() == cell) {
1710 }
1711 else if (face.nbCell() == 1) {
1712 true_boundary = true;
1713 }
1714 else {
1715 internal_other = true;
1716 opposite_cell_uid = face.backCell().uniqueId().asInt64();
1717 }
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();
1722 ostr() << ")";
1723 if (internal_other)
1724 ostr() << " internal-other";
1725 if (true_boundary)
1726 ostr() << " true-boundary";
1727 if (opposite_cell_uid != NULL_ITEM_ID)
1728 ostr() << " opposite " << opposite_cell_uid;
1729 ostr() << '\n';
1730 ++face_index;
1731 }
1732 });
1733 info() << ostr.str();
1734 }
1735}
1736
1737/*---------------------------------------------------------------------------*/
1738/*---------------------------------------------------------------------------*/
1739
1740} // End namespace Arcane::mesh
1741
1742/*---------------------------------------------------------------------------*/
1743/*---------------------------------------------------------------------------*/
#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.
Cell of a mesh.
Definition Item.h:1300
FaceConnectedListViewType faces() const
List of faces of the cell.
Definition Item.h:1403
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.
Face of a cell.
Definition Item.h:1032
Cell frontCell() const
Cell in front of the face (null cell if none).
Definition Item.h:1780
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
bool isSubDomainBoundary() const
Indicates if the face is on the subdomain boundary (i.e nbCell()==1).
Definition Item.h:1148
Cell backCell() const
Cell behind the face (null cell if none).
Definition Item.h:1774
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.
Definition IItemFamily.h:85
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.
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.
Definition ItemFlags.h:59
@ II_HasBackCell
The entity has a back cell.
Definition ItemFlags.h:53
@ II_SubDomainBoundary
The entity is at the boundary of two subdomains.
Definition ItemFlags.h:60
Info on a mesh entity type.
Integer nbLocalNode() const
Number of nodes of the entity.
Mesh entity type manager.
Definition ItemTypeMng.h:64
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
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
constexpr Int32 localId() const
Local identifier of the entity in the processor subdomain.
Definition Item.h:233
Int32 owner() const
Owner subdomain number of the entity.
Definition Item.h:252
ItemUniqueId uniqueId() const
Unique identifier across all domains.
Definition Item.h:239
constexpr bool null() const
true if the entity is null (i.e. not connected to the mesh)
Definition Item.h:230
impl::ItemBase itemBase() const
Internal part of the entity.
Definition Item.h:383
Int16 type() const
Entity type.
Definition Item.h:255
virtual MessageRank destination() const =0
Destination rank (if isSend() is true) or sender.
virtual ISerializer * serializer()=0
Serializer.
Int32 value() const
Rank value.
Definition MessageRank.h:76
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.
Node of a mesh.
Definition Item.h:598
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.
Definition Span.h:537
constexpr __host__ __device__ SizeType size() const noexcept
Returns the size of the array.
Definition Span.h:325
View of an array of elements of type T.
Definition Span.h:633
const char * localstr() const
Returns the conversion of the instance into UTF-8 encoding.
Definition String.cc:229
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.
Definition DynamicMesh.h:98
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.
static Face findFaceInNode2(Node node, Integer face_type_id, Int64ConstArrayView face_nodes_uid)
Definition ItemTools.cc:44
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.
Definition MathUtils.h:407
@ ReduceMax
Maximum of values.
Ref< IParallelExchanger > createExchangerRef(IParallelMng *pm)
Returns an interface to transfer messages between ranks.
Real getRealTime()
Real time used in seconds.
Array< Int64 > Int64Array
Dynamic one-dimensional array of 64-bit integers.
Definition UtilsTypes.h:119
ArrayView< Int64 > Int64ArrayView
C equivalent of a 1D array of 64-bit integers.
Definition UtilsTypes.h:445
bool arcaneIsCheck()
True if running in check mode.
Definition Misc.cc:66
UniqueArray< Int64 > Int64UniqueArray
Dynamic 1D array of 64-bit integers.
Definition UtilsTypes.h:333
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:451
Array< Integer > IntegerArray
Dynamic one-dimensional array of integers.
Definition UtilsTypes.h:127
ConstArrayView< Int64 > Int64ConstArrayView
C equivalent of a 1D array of 64-bit integers.
Definition UtilsTypes.h:474
UniqueArray< Int32 > Int32UniqueArray
Dynamic 1D array of 32-bit integers.
Definition UtilsTypes.h:335
double Real
Type representing a real number.
UniqueArray< Integer > IntegerUniqueArray
Dynamic 1D array of integers.
Definition UtilsTypes.h:341
ConstArrayView< Integer > IntegerConstArrayView
C equivalent of a 1D array of integers.
Definition UtilsTypes.h:480
std::int32_t Int32
Signed integer type of 32 bits.