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