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 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();
487 ScopedPtrT<IItemFamilySerializer> cell_serializer(m_mesh->cellFamily()->policyMng()->createSerializer(with_flags));
488 cell_serializer->deserializeItems(s, nullptr);
489 }
490}
491
492/*---------------------------------------------------------------------------*/
493/*---------------------------------------------------------------------------*/
494
497{
498 info() << "** AMR GHOST CHILD FROM PARENT BUILDER V1";
499
500 IParallelMng* pm = m_mesh->parallelMng();
501 debug() << " RANK=" << pm->commRank() << " size=" << pm->commSize();
502 if (!pm->isParallel()) {
503 debug() << "NOT PARALLEL";
504 return;
505 }
506 Integer sid = pm->commRank();
507
508 // Mark the nodes on the boundary
509 ItemInternalMap& cells_map = m_mesh_internal->cellsMap();
510
511 FaceFamily& true_face_family = m_mesh_internal->trueFaceFamily();
512
513 //TODO: choose correct value to initialize the table
514 BoundaryInfosMap boundary_infos_to_send(200, true);
515
516 cells_map.eachItem([&](Item cell) {
517 ARCANE_ASSERT((cell.owner() != -1), (""));
518 if (cell.itemBase().level() == 0 && cell.owner() != sid) {
519 ARCANE_ASSERT((cell.owner() != -1), (""));
520 Int64Array& v = boundary_infos_to_send.lookupAdd(cell.owner())->value();
521 v.add(sid);
522 v.add(cell.uniqueId());
523 }
524 });
525
526 // Position the send list
527 auto exchanger{ ParallelMngUtils::createExchangerRef(pm) };
528 _exchangeData(exchanger.get(), boundary_infos_to_send);
529
530 traceMng()->flush();
531 pm->barrier();
532
533 typedef HashTableMapT<Int32, SharedArray<Int32>> SubDomainItemMap;
534 SubDomainItemMap cells_to_send(50, true);
535 {
536 Integer nb_receiver = exchanger->nbReceiver();
537 debug() << "NB RECEIVER=" << nb_receiver;
538 Int64UniqueArray received_infos;
539 for (Integer i = 0; i < nb_receiver; ++i) {
540 ISerializeMessage* sm = exchanger->messageToReceive(i);
541 ISerializer* s = sm->serializer();
543 s->getArray(received_infos);
544 Int64 nb_info = received_infos.size();
545 //Int32 orig_rank = sm->destSubDomain();
546 //info() << "RECEIVE NB_INFO=" << nb_info << " from=" << orig_rank;
547 if ((nb_info % 2) != 0)
548 ARCANE_FATAL("info size can not be divided by 2 v={0}", nb_info);
549 Int64 nb_info_true = nb_info / 2;
550 Integer nb_recv_child = 0;
551 for (Int64 z = 0; z < nb_info_true; ++z) {
552 Int32 cell_owner = CheckedConvert::toInt32(received_infos[(z * 2) + 0]);
553 Int64 cell_uid = received_infos[(z * 2) + 1];
554
555 impl::ItemBase cell = cells_map.findItem(cell_uid);
556 ARCANE_ASSERT((cell.uniqueId() == cell_uid), (""));
557 if (!cell.hasHChildren())
558 continue;
559 UniqueArray<ItemInternal*> cell_family;
560 ARCANE_ASSERT((cell.level() == 0), (""));
561 ARCANE_ASSERT((cell.owner() != -1), ("CELL"));
562 ARCANE_ASSERT((cell_owner != -1), ("CELL"));
563 true_face_family.familyTree(cell_family, cell);
564 SubDomainItemMap::Data* d = cells_to_send.lookupAdd(cell_owner);
565 Int32Array& dv = d->value();
566 const Integer cs = cell_family.size();
567 nb_recv_child += cs;
568 for (Integer c = 1; c < cs; c++) {
569 ItemInternal* child = cell_family[c];
570 ARCANE_ASSERT((child->owner() != -1), ("CHILD"));
571 //debug() << child->topHParent()->uniqueId() << " " << cell->uniqueId() << " " << child->topHParent()->owner() << " " << cell->owner();
572 //ARCANE_ASSERT((child->topHParent() == cell),("CHILD"));
573 dv.add(child->localId());
574 }
575 cell_family.clear();
576 }
577 debug() << "nb_recv_child= " << nb_recv_child;
578 }
579 }
580 // Sends and receives ghost cells
581 _exchangeCells(cells_to_send, true);
582 m_mesh_internal->printStats(TraceMessage::DEFAULT_LEVEL);
583}
584
585/*---------------------------------------------------------------------------*/
586/*---------------------------------------------------------------------------*/
587/*---------------------------------------------------------------------------*/
588/*---------------------------------------------------------------------------*/
589
590void GhostLayerBuilder::
591addGhostChildFromParent2(Array<Int64>& ghost_cell_to_refine)
592{
593 info() << "** AMR GHOST CHILD FROM PARENT BUILDER V2";
594
595 IParallelMng* pm = m_mesh->parallelMng();
596 debug() << " RANK=" << pm->commRank() << " size=" << pm->commSize();
597 if (!pm->isParallel()) {
598 debug() << "NOT PARALLEL";
599 return;
600 }
601 Integer sid = pm->commRank();
602
603 // Mark the nodes on the boundary
604 ItemInternalMap& cells_map = m_mesh_internal->cellsMap();
605
606 //TODO: choose correct value to initialize the table
607 BoundaryInfosMap boundary_infos_to_send(200, true);
608 // level 0 cells are not concerned
609 // only active cells with level greater than 0 are concerned
610 // that cells that have just been refined or def-refined are concerned
611 cells_map.eachItem([&](Item cell) {
612 ARCANE_ASSERT((cell.owner() != -1), (""));
613 if (cell.owner() == sid)
614 return;
615 // this assumes that the flags are already synchronized
617 // cell to add
618 ghost_cell_to_refine.add(cell.uniqueId());
619 Int64Array& v = boundary_infos_to_send.lookupAdd(cell.owner())->value();
620 v.add(sid);
621 v.add(cell.uniqueId());
622 }
623 });
624
625 // Position the send list
626 auto exchanger{ ParallelMngUtils::createExchangerRef(pm) };
627 _exchangeData(exchanger.get(), boundary_infos_to_send);
628
629 traceMng()->flush();
630 pm->barrier();
631
632 typedef HashTableMapT<Int32, SharedArray<Int32>> SubDomainItemMap;
633 SubDomainItemMap cells_to_send(50, true);
634 {
635 Integer nb_receiver = exchanger->nbReceiver();
636 debug() << "NB RECEIVER=" << nb_receiver;
637 Int64UniqueArray received_infos;
638 for (Integer i = 0; i < nb_receiver; ++i) {
639 ISerializeMessage* sm = exchanger->messageToReceive(i);
640 //Int32 orig_rank = sm->destSubDomain();
641 ISerializer* s = sm->serializer();
643 //info() << "RECEIVE NB_INFO=" << nb_info << " from=" << orig_rank;
644 s->getArray(received_infos);
645 Int64 nb_info = received_infos.size();
646 if ((nb_info % 2) != 0)
647 ARCANE_FATAL("info size can not be divided by 2 v={0}", nb_info);
648 Int64 nb_info_true = nb_info / 2;
649 Integer nb_recv_child = 0;
650 for (Int64 z = 0; z < nb_info_true; ++z) {
651 Int32 cell_owner = CheckedConvert::toInt32(received_infos[(z * 2) + 0]);
652 Int64 cell_uid = received_infos[(z * 2) + 1];
653
654 Cell cell = cells_map.findItem(cell_uid);
655 ARCANE_ASSERT((cell.uniqueId() == cell_uid), (""));
656 ARCANE_ASSERT((cell.owner() != -1), ("CELL"));
657 ARCANE_ASSERT((cell_owner != -1), ("CELL"));
658
659 SubDomainItemMap::Data* d = cells_to_send.lookupAdd(cell_owner);
660 Int32Array& dv = d->value();
661
662 nb_recv_child += cell.nbHChildren();
663 for (Integer c = 0, cs = cell.nbHChildren(); c < cs; c++) {
664 Cell child = cell.hChild(c);
665 ARCANE_ASSERT((child.owner() != -1), ("CHILD"));
666 //debug() << child->topHParent()->uniqueId() << " " << cell->uniqueId() << " " << child->topHParent()->owner() << " " << cell->owner();
667 //ARCANE_ASSERT((child->topHParent() == cell),("CHILD"));
668 dv.add(child.localId());
669 }
670 }
671 debug() << "nb_recv_child= " << nb_recv_child;
672 }
673 }
674
675 // Sends and receives ghost cells
676 _exchangeCells(cells_to_send, true);
677 m_mesh_internal->printStats(TraceMessage::DEFAULT_LEVEL);
678}
679
680/*---------------------------------------------------------------------------*/
681/*---------------------------------------------------------------------------*/
682/*---------------------------------------------------------------------------*/
683
684NodeUidToSubDomain::
685NodeUidToSubDomain(Int64 max_uid, Int32 nb_rank)
686: m_nb_rank(nb_rank)
687, m_modulo(1)
688, m_nb_by_rank(max_uid)
689{
690 m_nb_by_rank = max_uid / nb_rank;
691 if (m_nb_by_rank == 0)
692 m_nb_by_rank = max_uid;
693 m_modulo = nb_rank;
694 Integer div_value = 1;
695 if (m_nb_rank > 4)
696 div_value = 2;
697 String s = platform::getEnvironmentVariable("ARCANE_INIT_RANK_GROUP_SIZE");
698 if (!s.null()) {
699 bool is_ok = builtInGetValue(div_value, s);
700 if (is_ok) {
701 if (div_value < 0)
702 div_value = 1;
703 if (div_value > m_nb_rank)
704 div_value = m_nb_rank;
705 }
706 }
707 m_modulo = m_nb_rank / div_value;
708}
709
710/*---------------------------------------------------------------------------*/
711/*---------------------------------------------------------------------------*/
712
713} // End namespace Arcane::mesh
714
715/*---------------------------------------------------------------------------*/
716/*---------------------------------------------------------------------------*/
#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.