Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
GhostLayerBuilder.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/* GhostLayerBuilder.cc (C) 2000-2025 */
9/* */
10/* Construction of ghost layers. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/ArgumentException.h"
15#include "arcane/utils/NotImplementedException.h"
16#include "arcane/utils/NotSupportedException.h"
17#include "arcane/utils/HashTableMap.h"
18#include "arcane/utils/PlatformUtils.h"
19#include "arcane/utils/ScopedPtr.h"
20#include "arcane/utils/ITraceMng.h"
21#include "arcane/utils/ValueConvert.h"
22#include "arcane/utils/OStringStream.h"
23#include "arcane/utils/CheckedConvert.h"
24
25#include "arcane/core/ItemTypeMng.h"
27#include "arcane/core/IParallelMng.h"
28#include "arcane/core/SerializeBuffer.h"
29#include "arcane/core/ItemPrinter.h"
30#include "arcane/core/IParallelExchanger.h"
31#include "arcane/core/ISerializeMessage.h"
32#include "arcane/core/IItemFamilyPolicyMng.h"
33#include "arcane/core/IItemFamilySerializer.h"
34#include "arcane/core/ParallelMngUtils.h"
35#include "arcane/core/IGhostLayerMng.h"
36
37#include "arcane/mesh/DynamicMesh.h"
38#include "arcane/mesh/GhostLayerBuilder.h"
39#include "arcane/mesh/OneMeshItemAdder.h"
40
41/*---------------------------------------------------------------------------*/
42/*---------------------------------------------------------------------------*/
43
44namespace Arcane::mesh
45{
46
47/*---------------------------------------------------------------------------*/
48/*---------------------------------------------------------------------------*/
49
50extern "C++" void
51_buildGhostLayerNewVersion(DynamicMesh* mesh, bool is_allocate, Int32 version);
52
53/*---------------------------------------------------------------------------*/
54/*---------------------------------------------------------------------------*/
55
56// #define ARCANE_DEBUG_DYNAMIC_MESH
57// #define ARCANE_DEBUG_DYNAMIC_MESH2
58
59/*---------------------------------------------------------------------------*/
60/*---------------------------------------------------------------------------*/
61
62/*---------------------------------------------------------------------------*/
63/*---------------------------------------------------------------------------*/
64
67: TraceAccessor(mesh_builder->mesh()->traceMng())
68, m_mesh(mesh_builder->mesh())
69, m_mesh_builder(mesh_builder)
70{
71}
72
73/*---------------------------------------------------------------------------*/
74/*---------------------------------------------------------------------------*/
75
76GhostLayerBuilder::
77~GhostLayerBuilder()
78{
79}
80
81/*---------------------------------------------------------------------------*/
82/*---------------------------------------------------------------------------*/
83
84/*---------------------------------------------------------------------------*/
85/*---------------------------------------------------------------------------*/
86
87void GhostLayerBuilder::
88addGhostLayers(bool is_allocate)
89{
90 Real begin_time = platform::getRealTime();
91 Integer version = m_mesh->ghostLayerMng()->builderVersion();
92 if (version == 1) {
93 throw NotSupportedException(A_FUNCINFO, "Version 1 is no longer supported");
94 }
95 else if (version == 2) {
96 info() << "Use ghost layer builder version 2";
97 _addOneGhostLayerV2();
98 }
99 else if (version == 3 || version == 4) {
100 info() << "Use GhostLayerBuilder with sort (version " << version << ")";
101 _buildGhostLayerNewVersion(m_mesh, is_allocate, version);
102 }
103 else
104 throw NotSupportedException(A_FUNCINFO, "Bad version number for addGhostLayer");
105
106 Real end_time = platform::getRealTime();
107 Real diff = (Real)(end_time - begin_time);
108 info() << "TIME to compute ghost layer=" << diff;
109}
110
111/*---------------------------------------------------------------------------*/
112/*---------------------------------------------------------------------------*/
113
114class NodeCellList
115{
116 public:
117 private:
118 public:
119
120 NodeCellList()
121 : m_cell_last_index(5000, true)
122 {}
123
124 public:
125
126 void add(Int64 node_uid, Int64 cell_uid, Int64 cell_owner)
127 {
128 Int32 current_index = m_cell_indexes.size();
129 m_cell_indexes.add(cell_uid);
130 m_cell_indexes.add(cell_owner);
131 bool is_add = false;
132 HashTableMapT<Int64, Int32>::Data* d = m_cell_last_index.lookupAdd(node_uid, -1, is_add);
133 m_cell_indexes.add(d->value());
134 d->value() = current_index;
135 }
136
137 public:
138
139 Int64UniqueArray m_cell_indexes;
140 HashTableMapT<Int64, Int32> m_cell_last_index;
141};
142
143/*---------------------------------------------------------------------------*/
144/*---------------------------------------------------------------------------*/
145
146void GhostLayerBuilder::
147_exchangeData(IParallelExchanger* exchanger, BoundaryInfosMap& boundary_infos_to_send)
148{
149 for (BoundaryInfosMapEnumerator i_map(boundary_infos_to_send); ++i_map;) {
150 Int32 sd = i_map.data()->key();
151 exchanger->addSender(sd);
152 }
154 {
155 for (Integer i = 0, ns = exchanger->nbSender(); i < ns; ++i) {
156 ISerializeMessage* sm = exchanger->messageToSend(i);
157 Int32 rank = sm->destination().value();
158 ISerializer* s = sm->serializer();
159 Int64ConstArrayView infos = boundary_infos_to_send[rank];
160
161 s->setMode(ISerializer::ModeReserve);
162 s->reserveArray(infos); // For the elements
163
164 s->allocateBuffer();
166
167 s->putArray(infos);
168 }
169 }
170 exchanger->processExchange();
171 debug() << "END EXCHANGE";
172}
173
174/*---------------------------------------------------------------------------*/
175/*---------------------------------------------------------------------------*/
176
177void GhostLayerBuilder::
178_addOneGhostLayerV2()
179{
180 info() << "** NEW GHOST LAYER BUILDER V2";
181 if (m_mesh->ghostLayerMng()->nbGhostLayer() != 1)
182 ARCANE_THROW(NotImplementedException, "Only one layer of ghost cells is supported");
183
184 IParallelMng* pm = m_mesh->parallelMng();
185 Int32 my_rank = pm->commRank();
186 Int32 nb_rank = pm->commSize();
187 debug() << " RANK=" << pm->commRank() << " size=" << pm->commSize();
188 if (!pm->isParallel()) {
189 debug() << "NOT PARALLEL";
190 return;
191 }
192#ifdef ARCANE_DEBUG_DYNAMIC_MESH
193 const bool is_verbose = true;
194#else
195 const bool is_verbose = false;
196#endif
197
198 OStringStream ostr;
199 if (is_verbose)
200 ostr() << "** FACES LIST\n";
201
202 Integer nb_sub_domain_boundary_face = 0;
203 // Marks nodes on the boundary
204 ItemInternalMap& cells_map = m_mesh->cellsMap(); // Supports mesh transfers
205 ItemInternalMap& faces_map = m_mesh->facesMap(); // Determines boundaries before transfer
206 // ItemInternalMap& edges_map = m_mesh->edgesMap(); // Not directly used by the algorithm
207 ItemInternalMap& nodes_map = m_mesh->nodesMap(); // Locates modifications
208
209 const int shared_and_boundary_flags = ItemFlags::II_Shared | ItemFlags::II_SubDomainBoundary;
210 // Iterates over faces and marks boundary nodes, edges, and faces
211 faces_map.eachItem([&](Face face) {
212 impl::ItemBase face_base = face.itemBase();
213 if (is_verbose) {
214 ostr() << ItemPrinter(face);
215 ostr() << '\n';
216 }
217 bool is_sub_domain_boundary_face = false;
218 if (face_base.hasFlags(ItemFlags::II_Boundary)) {
219 is_sub_domain_boundary_face = true;
220 }
221 else {
222 if (face.nbCell() == 2 && (face.cell(0).owner() != my_rank || face.cell(1).owner() != my_rank))
223 is_sub_domain_boundary_face = true;
224 }
225 if (is_sub_domain_boundary_face) {
226 face_base.toMutable().addFlags(shared_and_boundary_flags);
227 ++nb_sub_domain_boundary_face;
228 for (Item inode : face.nodes())
229 inode.mutableItemBase().addFlags(shared_and_boundary_flags);
230 for (Item iedge : face.edges())
231 iedge.mutableItemBase().addFlags(shared_and_boundary_flags);
232 }
233 });
234
235 Integer boundary_nodes_uid_count = 0;
236
237 // Iterates over nodes and adds boundary nodes
238 Int64 my_max_node_uid = NULL_ITEM_UNIQUE_ID;
239 nodes_map.eachItem([&](Node node) {
240 Int32 f = node.itemBase().flags();
241 if (f & ItemFlags::II_Shared) {
242 Int64 node_uid = node.uniqueId();
243 if (node_uid > my_max_node_uid)
244 my_max_node_uid = node_uid;
245 ++boundary_nodes_uid_count;
246 }
247 });
248
249 Int64 global_max_node_uid = pm->reduce(Parallel::ReduceMax, my_max_node_uid);
250 debug() << "NB BOUNDARY NODE=" << boundary_nodes_uid_count
251 << " MY_MAX_UID=" << my_max_node_uid
252 << " GLOBAL=" << global_max_node_uid;
253
254 if (is_verbose) {
255 ostr.reset();
256 ostr() << "List of shared cells:\n";
257 }
258
259 //TODO: choose a good value to initialize the table
260 BoundaryInfosMap boundary_infos_to_send(200, true);
261 NodeUidToSubDomain uid_to_subdomain_converter(global_max_node_uid, nb_rank);
262
263 cells_map.eachItem([&](Cell cell) {
264 if (is_verbose) {
265 ostr() << "Send cell " << ItemPrinter(cell) << '\n';
266 }
267 //info() << " CHECK cell uid=" << cell->uniqueId() << " owner=" << cell->owner();
268 //bool add_cell = false;
269 for (Node node : cell.nodes()) {
270 //info() << "** CHECK NODE node=" << i_node->uniqueId() << " cell=" << cell->uniqueId();
271 if (node.hasFlags(ItemFlags::II_Shared)) {
272 Int64 node_uid = node.uniqueId();
273 //info() << "** ADD BOUNDARY CELL node=" << node_uid << " cell=" << cell->uniqueId();
274 Int32 dest_rank = uid_to_subdomain_converter.uidToRank(node_uid);
275 SharedArray<Int64> v = boundary_infos_to_send.lookupAdd(dest_rank)->value();
276 v.add(node_uid);
277 v.add(cell.owner());
278 v.add(cell.uniqueId());
279 //TODO: delete duplicates?
280 //add_cell = true;
281 //break;
282 }
283 }
284 });
285
286 if (is_verbose)
287 info() << ostr.str();
288
289 info() << "Number of shared faces: " << nb_sub_domain_boundary_face;
290
291 auto exchanger{ ParallelMngUtils::createExchangerRef(pm) };
292
293 if (!platform::getEnvironmentVariable("ARCANE_COLLECTIVE_GHOST_LAYER").null())
295
296 _exchangeData(exchanger.get(), boundary_infos_to_send);
297
298 traceMng()->flush();
299 pm->barrier();
300 NodeCellList node_cell_list;
301 {
302 Integer nb_receiver = exchanger->nbReceiver();
303 debug() << "NB RECEIVER=" << nb_receiver;
304 Int64UniqueArray received_infos;
305 for (Integer i = 0; i < nb_receiver; ++i) {
306 ISerializeMessage* sm = exchanger->messageToReceive(i);
307 //Int32 orig_rank = sm->destSubDomain();
308 ISerializer* s = sm->serializer();
310 s->getArray(received_infos);
311 Int64 nb_info = received_infos.largeSize();
312 //info() << "RECEIVE NB_INFO=" << nb_info << " from=" << orig_rank;
313 if ((nb_info % 3) != 0)
314 ARCANE_FATAL("Inconsistent received data v={0}", nb_info);
315 Int64 nb_info_true = nb_info / 3;
316 for (Int64 z = 0; z < nb_info_true; ++z) {
317 Int64 node_uid = received_infos[(z * 3) + 0];
318 Int64 cell_owner = received_infos[(z * 3) + 1];
319 Int64 cell_uid = received_infos[(z * 3) + 2];
320 node_cell_list.add(node_uid, cell_uid, cell_owner);
321 }
322 }
323 }
324
325 boundary_infos_to_send = BoundaryInfosMap(1000, true);
326
327 {
328 Int64ConstArrayView cell_indexes = node_cell_list.m_cell_indexes;
329 debug() << "NB_CELL_INDEXES = " << cell_indexes.size();
330 //for( Integer i=0, s=cell_indexes.size(); i<s; ++i )
331 //info() << "INDEX I=" << i << " V=" << cell_indexes[i];
332 Int32UniqueArray ranks;
333 Int64UniqueArray cells;
334 for (HashTableMapEnumeratorT<Int64, Int32> i_map(node_cell_list.m_cell_last_index); ++i_map;) {
335 HashTableMapT<Int64, Int32>::Data* d = i_map.data();
336 Int32 index = d->value();
337 Int64 node_uid = d->key();
338 //info() << "NODE UID=" << node_uid;
339 ranks.clear();
340 cells.clear();
341 // Since we know the list of cells connected to this node, as well as their
342 // owner, we take the opportunity to calculate the node's owner by considering
343 // that it is the same owner as the cell with the smallest uniqueId()
344 // connected to this node.
345 Int32 node_new_owner = NULL_SUB_DOMAIN_ID;
346 Int64 smallest_cell_uid = NULL_ITEM_UNIQUE_ID;
347 //TODO add safety by calculating the max number of values
348 while (index != (-1)) {
349 Int64 cell_uid = cell_indexes[index];
350 Int32 cell_owner = CheckedConvert::toInt32(cell_indexes[index + 1]);
351 index = CheckedConvert::toInteger(cell_indexes[index + 2]);
352 //info() << " CELLS: uid=" << cell_uid << " owner=" << cell_owner;
353 ranks.add((Int32)cell_owner);
354 cells.add(cell_uid);
355 if (cell_uid < smallest_cell_uid || node_new_owner == NULL_SUB_DOMAIN_ID) {
356 smallest_cell_uid = cell_uid;
357 node_new_owner = cell_owner;
358 }
359 }
360 // Sort the ranks then remove duplicates
361 std::sort(std::begin(ranks), std::end(ranks));
362 Integer new_size = CheckedConvert::toInteger(std::unique(std::begin(ranks), std::end(ranks)) - std::begin(ranks));
363 ranks.resize(new_size);
364 //info() << "NEW_SIZE=" << new_size;
365 //for( Integer z=0; z<new_size; ++z )
366 //info() << "NEW_RANK=" << ranks[z];
367
368 // If the number of ranks equals 1, it means that the node belongs to only one subdomain
369 // and therefore it is a true boundary node. There is no need to transfer its cells.
370 if (new_size == 1)
371 continue;
372 Integer nb_cell = cells.size();
373 for (Integer z = 0; z < new_size; ++z) {
374 Int32 dest_rank = ranks[z];
375 //info() << "NEW_RANK=" << dest_rank;
376 Int64Array& v = boundary_infos_to_send.lookupAdd(dest_rank)->value();
377 v.add(node_uid);
378 v.add(node_new_owner);
379 v.add(new_size);
380 v.add(nb_cell);
381 for (Integer z2 = 0; z2 < new_size; ++z2)
382 v.add(ranks[z2]);
383 for (Integer z2 = 0; z2 < nb_cell; ++z2)
384 v.add(cells[z2]);
385 }
386 }
387 }
388
390 _exchangeData(exchanger.get(), boundary_infos_to_send);
391 debug() << "END OF EXCHANGE";
392
393 typedef HashTableMapT<Int32, SharedArray<Int32>> SubDomainItemMap;
394 SubDomainItemMap cells_to_send(50, true);
395 {
396 Integer nb_receiver = exchanger->nbReceiver();
397 debug() << "NB RECEIVER 2 =" << nb_receiver;
398 Int64UniqueArray received_infos;
399 //HashTableMapT<Int64,Int32> nodes_nb_cell(1000,true);
400 for (Integer i = 0; i < nb_receiver; ++i) {
401 ISerializeMessage* sm = exchanger->messageToReceive(i);
402 //Int32 orig_rank = sm->destSubDomain();
403 ISerializer* s = sm->serializer();
405 //info() << "RECEIVE NB_INFO=" << nb_info << " from=" << orig_rank;
406 s->getArray(received_infos);
407 Int64 nb_info = received_infos.largeSize();
408 Int64 z = 0;
409 Int32UniqueArray ranks;
410 Int32UniqueArray cells;
411 while (z < nb_info) {
412 Int64 node_uid = received_infos[z];
413 Int32 node_new_owner = CheckedConvert::toInt32(received_infos[z + 1]);
414 Int32 nb_rank = CheckedConvert::toInt32(received_infos[z + 2]);
415 Int32 nb_cell = CheckedConvert::toInt32(received_infos[z + 3]);
416 //info() << "RECEIVE NODE uid="<< node_uid << " nb_rank=" << nb_rank << " nb_cell=" << nb_cell;
417 nodes_map.findItem(node_uid).toMutable().setOwner(node_new_owner, my_rank);
418 ranks.clear();
419 cells.clear();
420 z += 4;
421 for (Integer z2 = 0; z2 < nb_rank; ++z2) {
422 Int32 nrank = (Int32)received_infos[z + z2];
423 if (nrank != my_rank)
424 ranks.add(nrank);
425 }
426 z += nb_rank;
427 for (Integer z2 = 0; z2 < nb_cell; ++z2) {
428 Int64 cell_uid = received_infos[z + z2];
429 impl::ItemBase dcell = cells_map.tryFind(cell_uid);
430 if (!dcell.null())
431 cells.add(dcell.localId());
432 }
433 for (Integer z2 = 0, zs = ranks.size(); z2 < zs; ++z2) {
434 SubDomainItemMap::Data* d = cells_to_send.lookupAdd(ranks[z2]);
435 SharedArray<Int32> dv = d->value();
436 for (Integer z3 = 0, zs3 = cells.size(); z3 < zs3; ++z3)
437 dv.add(cells[z3]);
438 }
439 z += nb_cell;
440 }
441 }
442 }
443
444 // Sends and receives ghost cells
445 _exchangeCells(cells_to_send, false);
446 m_mesh_builder->printStats();
447}
448
449/*---------------------------------------------------------------------------*/
450/*---------------------------------------------------------------------------*/
451
452void GhostLayerBuilder::
453_exchangeCells(HashTableMapT<Int32, SharedArray<Int32>>& cells_to_send, bool with_flags)
454{
455 //TODO: merge with GhostLayerBuilder2::_exchangeCells().
456 typedef HashTableMapT<Int32, SharedArray<Int32>> SubDomainItemMap;
457 IParallelMng* pm = m_mesh->parallelMng();
458 auto exchanger{ ParallelMngUtils::createExchangerRef(pm) };
459 for (SubDomainItemMap::Enumerator i_map(cells_to_send); ++i_map;) {
460 Int32 sd = i_map.data()->key();
461 // TODO: items may contain duplicates and therefore they should be removed
462 // to avoid unnecessarily sending the same cell multiple times.
463 Int32ConstArrayView items = i_map.data()->value();
464 info(4) << "CELLS TO SEND SD=" << sd << " NB=" << items.size();
465 exchanger->addSender(sd);
466 }
468 for (Integer i = 0, ns = exchanger->nbSender(); i < ns; ++i) {
469 ISerializeMessage* sm = exchanger->messageToSend(i);
470 Int32 rank = sm->destination().value();
471 ISerializer* s = sm->serializer();
472 Int32ConstArrayView items_to_send = cells_to_send[rank];
473 //m_mesh->serializeCells(s,items_to_send,with_flags);
474 ScopedPtrT<IItemFamilySerializer> cell_serializer(m_mesh->cellFamily()->policyMng()->createSerializer(with_flags));
475 s->setMode(ISerializer::ModeReserve);
476 cell_serializer->serializeItems(s, items_to_send);
477 s->allocateBuffer();
478 s->setMode(ISerializer::ModePut);
479 cell_serializer->serializeItems(s, items_to_send);
480 }
481 exchanger->processExchange();
482 info(4) << "END EXCHANGE CELLS";
483 for (Integer i = 0, ns = exchanger->nbReceiver(); i < ns; ++i) {
484 ISerializeMessage* sm = exchanger->messageToReceive(i);
485 ISerializer* s = sm->serializer();
486 //m_mesh->addCells(s,with_flags);
488 ScopedPtrT<IItemFamilySerializer> cell_serializer(m_mesh->cellFamily()->policyMng()->createSerializer(with_flags));
489 cell_serializer->deserializeItems(s, nullptr);
490 }
491}
492
493/*---------------------------------------------------------------------------*/
494/*---------------------------------------------------------------------------*/
495
498{
499 info() << "** AMR GHOST CHILD FROM PARENT BUILDER V1";
500
501 IParallelMng* pm = m_mesh->parallelMng();
502 debug() << " RANK=" << pm->commRank() << " size=" << pm->commSize();
503 if (!pm->isParallel()) {
504 debug() << "NOT PARALLEL";
505 return;
506 }
507 Integer sid = pm->commRank();
508
509 // Mark the nodes on the boundary
510 ItemInternalMap& cells_map = m_mesh->cellsMap();
511
512 FaceFamily& true_face_family = m_mesh->trueFaceFamily();
513
514 //TODO: choose correct value to initialize the table
515 BoundaryInfosMap boundary_infos_to_send(200, true);
516
517 cells_map.eachItem([&](Item cell) {
518 ARCANE_ASSERT((cell.owner() != -1), (""));
519 if (cell.itemBase().level() == 0 && cell.owner() != sid) {
520 ARCANE_ASSERT((cell.owner() != -1), (""));
521 Int64Array& v = boundary_infos_to_send.lookupAdd(cell.owner())->value();
522 v.add(sid);
523 v.add(cell.uniqueId());
524 }
525 });
526
527 // Position the send list
528 auto exchanger{ ParallelMngUtils::createExchangerRef(pm) };
529 _exchangeData(exchanger.get(), boundary_infos_to_send);
530
531 traceMng()->flush();
532 pm->barrier();
533
534 typedef HashTableMapT<Int32, SharedArray<Int32>> SubDomainItemMap;
535 SubDomainItemMap cells_to_send(50, true);
536 {
537 Integer nb_receiver = exchanger->nbReceiver();
538 debug() << "NB RECEIVER=" << nb_receiver;
539 Int64UniqueArray received_infos;
540 for (Integer i = 0; i < nb_receiver; ++i) {
541 ISerializeMessage* sm = exchanger->messageToReceive(i);
542 ISerializer* s = sm->serializer();
544 s->getArray(received_infos);
545 Int64 nb_info = received_infos.size();
546 //Int32 orig_rank = sm->destSubDomain();
547 //info() << "RECEIVE NB_INFO=" << nb_info << " from=" << orig_rank;
548 if ((nb_info % 2) != 0)
549 ARCANE_FATAL("info size can not be divided by 2 v={0}", nb_info);
550 Int64 nb_info_true = nb_info / 2;
551 Integer nb_recv_child = 0;
552 for (Int64 z = 0; z < nb_info_true; ++z) {
553 Int32 cell_owner = CheckedConvert::toInt32(received_infos[(z * 2) + 0]);
554 Int64 cell_uid = received_infos[(z * 2) + 1];
555
556 impl::ItemBase cell = cells_map.findItem(cell_uid);
557 ARCANE_ASSERT((cell.uniqueId() == cell_uid), (""));
558 if (!cell.hasHChildren())
559 continue;
560 UniqueArray<ItemInternal*> cell_family;
561 ARCANE_ASSERT((cell.level() == 0), (""));
562 ARCANE_ASSERT((cell.owner() != -1), ("CELL"));
563 ARCANE_ASSERT((cell_owner != -1), ("CELL"));
564 true_face_family.familyTree(cell_family, cell);
565 SubDomainItemMap::Data* d = cells_to_send.lookupAdd(cell_owner);
566 Int32Array& dv = d->value();
567 const Integer cs = cell_family.size();
568 nb_recv_child += cs;
569 for (Integer c = 1; c < cs; c++) {
570 ItemInternal* child = cell_family[c];
571 ARCANE_ASSERT((child->owner() != -1), ("CHILD"));
572 //debug() << child->topHParent()->uniqueId() << " " << cell->uniqueId() << " " << child->topHParent()->owner() << " " << cell->owner();
573 //ARCANE_ASSERT((child->topHParent() == cell),("CHILD"));
574 dv.add(child->localId());
575 }
576 cell_family.clear();
577 }
578 debug() << "nb_recv_child= " << nb_recv_child;
579 }
580 }
581 // Sends and receives ghost cells
582 _exchangeCells(cells_to_send, true);
583 m_mesh_builder->printStats();
584}
585
586/*---------------------------------------------------------------------------*/
587/*---------------------------------------------------------------------------*/
588/*---------------------------------------------------------------------------*/
589/*---------------------------------------------------------------------------*/
590
591void GhostLayerBuilder::
592addGhostChildFromParent2(Array<Int64>& ghost_cell_to_refine)
593{
594 info() << "** AMR GHOST CHILD FROM PARENT BUILDER V2";
595
596 IParallelMng* pm = m_mesh->parallelMng();
597 debug() << " RANK=" << pm->commRank() << " size=" << pm->commSize();
598 if (!pm->isParallel()) {
599 debug() << "NOT PARALLEL";
600 return;
601 }
602 Integer sid = pm->commRank();
603
604 // Mark the nodes on the boundary
605 ItemInternalMap& cells_map = m_mesh->cellsMap();
606
607 //TODO: choose correct value to initialize the table
608 BoundaryInfosMap boundary_infos_to_send(200, true);
609 // level 0 cells are not concerned
610 // only active cells with level greater than 0 are concerned
611 // that cells that have just been refined or def-refined are concerned
612 cells_map.eachItem([&](Item cell) {
613 ARCANE_ASSERT((cell.owner() != -1), (""));
614 if (cell.owner() == sid)
615 return;
616 // this assumes that the flags are already synchronized
618 // cell to add
619 ghost_cell_to_refine.add(cell.uniqueId());
620 Int64Array& v = boundary_infos_to_send.lookupAdd(cell.owner())->value();
621 v.add(sid);
622 v.add(cell.uniqueId());
623 }
624 });
625
626 // Position the send list
627 auto exchanger{ ParallelMngUtils::createExchangerRef(pm) };
628 _exchangeData(exchanger.get(), boundary_infos_to_send);
629
630 traceMng()->flush();
631 pm->barrier();
632
633 typedef HashTableMapT<Int32, SharedArray<Int32>> SubDomainItemMap;
634 SubDomainItemMap cells_to_send(50, true);
635 {
636 Integer nb_receiver = exchanger->nbReceiver();
637 debug() << "NB RECEIVER=" << nb_receiver;
638 Int64UniqueArray received_infos;
639 for (Integer i = 0; i < nb_receiver; ++i) {
640 ISerializeMessage* sm = exchanger->messageToReceive(i);
641 //Int32 orig_rank = sm->destSubDomain();
642 ISerializer* s = sm->serializer();
644 //info() << "RECEIVE NB_INFO=" << nb_info << " from=" << orig_rank;
645 s->getArray(received_infos);
646 Int64 nb_info = received_infos.size();
647 if ((nb_info % 2) != 0)
648 ARCANE_FATAL("info size can not be divided by 2 v={0}", nb_info);
649 Int64 nb_info_true = nb_info / 2;
650 Integer nb_recv_child = 0;
651 for (Int64 z = 0; z < nb_info_true; ++z) {
652 Int32 cell_owner = CheckedConvert::toInt32(received_infos[(z * 2) + 0]);
653 Int64 cell_uid = received_infos[(z * 2) + 1];
654
655 Cell cell = cells_map.findItem(cell_uid);
656 ARCANE_ASSERT((cell.uniqueId() == cell_uid), (""));
657 ARCANE_ASSERT((cell.owner() != -1), ("CELL"));
658 ARCANE_ASSERT((cell_owner != -1), ("CELL"));
659
660 SubDomainItemMap::Data* d = cells_to_send.lookupAdd(cell_owner);
661 Int32Array& dv = d->value();
662
663 nb_recv_child += cell.nbHChildren();
664 for (Integer c = 0, cs = cell.nbHChildren(); c < cs; c++) {
665 Cell child = cell.hChild(c);
666 ARCANE_ASSERT((child.owner() != -1), ("CHILD"));
667 //debug() << child->topHParent()->uniqueId() << " " << cell->uniqueId() << " " << child->topHParent()->owner() << " " << cell->owner();
668 //ARCANE_ASSERT((child->topHParent() == cell),("CHILD"));
669 dv.add(child.localId());
670 }
671 }
672 debug() << "nb_recv_child= " << nb_recv_child;
673 }
674 }
675
676 // Sends and receives ghost cells
677 _exchangeCells(cells_to_send, true);
678 m_mesh_builder->printStats();
679}
680
681/*---------------------------------------------------------------------------*/
682/*---------------------------------------------------------------------------*/
683/*---------------------------------------------------------------------------*/
684
685NodeUidToSubDomain::
686NodeUidToSubDomain(Int64 max_uid, Int32 nb_rank)
687: m_nb_rank(nb_rank)
688, m_modulo(1)
689, m_nb_by_rank(max_uid)
690{
691 m_nb_by_rank = max_uid / nb_rank;
692 if (m_nb_by_rank == 0)
693 m_nb_by_rank = max_uid;
694 m_modulo = nb_rank;
695 Integer div_value = 1;
696 if (m_nb_rank > 4)
697 div_value = 2;
698 String s = platform::getEnvironmentVariable("ARCANE_INIT_RANK_GROUP_SIZE");
699 if (!s.null()) {
700 bool is_ok = builtInGetValue(div_value, s);
701 if (is_ok) {
702 if (div_value < 0)
703 div_value = 1;
704 if (div_value > m_nb_rank)
705 div_value = m_nb_rank;
706 }
707 }
708 m_modulo = m_nb_rank / div_value;
709}
710
711/*---------------------------------------------------------------------------*/
712/*---------------------------------------------------------------------------*/
713
714} // End namespace Arcane::mesh
715
716/*---------------------------------------------------------------------------*/
717/*---------------------------------------------------------------------------*/
#define ARCANE_THROW(exception_class,...)
Macro for throwing an exception with formatting.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Utility functions for the mesh.
Integer size() const
Number of elements in the vector.
Base class for 1D data vectors.
void clear()
Removes the elements from the array.
void add(ConstReferenceType val)
Adds element val to the end of the array.
constexpr const_pointer data() const noexcept
Pointer to the allocated memory.
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.
virtual Integer builderVersion() const =0
Ghost cell builder version.
Information exchange between processors.
virtual void addSender(Int32 rank)=0
Adds a processor to send to.
@ EM_Collective
Uses collective operations (allToAll).
virtual Integer nbSender() const =0
Number of processors to which we send.
virtual void setExchangeMode(eExchangeMode mode)=0
Sets the exchange mode.
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.
virtual ISerializeMessage * messageToReceive(Integer i)=0
Message received from the i-th processor.
Interface of the parallelism manager for a subdomain.
virtual Int32 commRank() const =0
Rank of this instance in the communicator.
virtual Int32 commSize() const =0
Number of instances in the communicator.
virtual bool isParallel() const =0
Returns true if the execution is parallel.
virtual void barrier()=0
Performs a barrier.
virtual void putArray(Span< const Real > values)=0
Save the number of elements and the values elements.
virtual void reserveArray(Span< const Real > values)=0
Reserve to save the number of elements and the values elements.
virtual void getArray(Array< Real > &values)=0
Resize and fill values.
virtual void allocateBuffer()=0
Allocates the serializer memory.
virtual void setMode(eMode new_mode)=0
Sets the current mode.
virtual void flush()=0
Flushes all streams.
Int32 owner() const
Number of the owning subdomain of the entity.
Int32 level() const
Int32 localId() const
Local number (in the subdomain) of the entity.
@ II_Shared
The entity is shared by another subdomain.
Definition ItemFlags.h:59
@ II_SubDomainBoundary
The entity is at the boundary of two subdomains.
Definition ItemFlags.h:60
@ II_JustRefined
The entity has just been refined.
Definition ItemFlags.h:78
@ II_Boundary
The entity is on the boundary.
Definition ItemFlags.h:51
Internal structure of a mesh entity.
Base class for a mesh element.
Definition Item.h:84
Int32 owner() const
Owner subdomain number of the entity.
Definition Item.h:252
constexpr bool hasFlags(Int32 flags) const
Returns if the flags are set for the entity.
Definition Item.h:352
ItemUniqueId uniqueId() const
Unique identifier across all domains.
Definition Item.h:239
impl::ItemBase itemBase() const
Internal part of the entity.
Definition Item.h:383
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
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flow for a debug message.
TraceMessage info() const
Flow for an information message.
ITraceMng * traceMng() const
Trace manager.
1D data vector with value semantics (STL style).
Implementation of a mesh.
Definition DynamicMesh.h:98
IParallelMng * parallelMng() override
Parallelism manager.
IGhostLayerMng * ghostLayerMng() const override
Associated ghost layer manager.
GhostLayerBuilder(DynamicMeshIncrementalBuilder *mesh_builder)
Constructs an instance for the mesh.
impl::ItemBase findItem(Int64 uid) const
Returns the unique ID entity uid.
void eachItem(const Lambda &lambda)
Template function to iterate over the instance's entities.
@ ReduceMax
Maximum of values.
Ref< IParallelExchanger > createExchangerRef(IParallelMng *pm)
Returns an interface to transfer messages between ranks.
Real getRealTime()
Real time used in seconds.
String getEnvironmentVariable(const String &name)
Environment variable named name.
Array< Int64 > Int64Array
Dynamic one-dimensional array of 64-bit integers.
Definition UtilsTypes.h:125
UniqueArray< Int64 > Int64UniqueArray
Dynamic 1D array of 64-bit integers.
Definition UtilsTypes.h:339
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
ConstArrayView< Int32 > Int32ConstArrayView
C equivalent of a 1D array of 32-bit integers.
Definition UtilsTypes.h:482
ConstArrayView< Int64 > Int64ConstArrayView
C equivalent of a 1D array of 64-bit integers.
Definition UtilsTypes.h:480
UniqueArray< Int32 > Int32UniqueArray
Dynamic 1D array of 32-bit integers.
Definition UtilsTypes.h:341
double Real
Type representing a real number.
Array< Int32 > Int32Array
Dynamic one-dimensional array of 32-bit integers.
Definition UtilsTypes.h:127
@ Cell
The mesh is AMR by cell.
Definition MeshKind.h:53
std::int32_t Int32
Signed integer type of 32 bits.