Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
CartesianMeshAMRPatchMng.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/* CartesianMeshAMRPatchMng.cc (C) 2000-2026 */
9/* */
10/* AMR Patch Manager for a Cartesian Mesh. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/cartesianmesh/internal/CartesianMeshAMRPatchMng.h"
15
16#include "arcane/utils/Array2View.h"
17#include "arcane/utils/Array3View.h"
18#include "arcane/utils/FixedArray.h"
19#include "arcane/utils/Vector2.h"
20#include "arcane/utils/Vector3.h"
21
22#include "arcane/core/IGhostLayerMng.h"
23#include "arcane/core/IMesh.h"
24#include "arcane/core/ItemPrinter.h"
25#include "arcane/core/IParallelMng.h"
26#include "arcane/core/VariableTypes.h"
27#include "arcane/core/IMeshModifier.h"
28#include "arcane/core/materials/IMeshMaterialMng.h"
29
30#include "arcane/cartesianmesh/CellDirectionMng.h"
31#include "arcane/cartesianmesh/ICartesianMesh.h"
32
33#include "arcane/cartesianmesh/internal/CartesianPatchGroup.h"
34#include "arcane/cartesianmesh/internal/ICartesianMeshInternal.h"
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38
39namespace Arcane
40{
41
42/*---------------------------------------------------------------------------*/
43/*---------------------------------------------------------------------------*/
44
45CartesianMeshAMRPatchMng::
46CartesianMeshAMRPatchMng(ICartesianMesh* cmesh, ICartesianMeshNumberingMngInternal* numbering_mng)
47: TraceAccessor(cmesh->mesh()->traceMng())
48, m_mesh(cmesh->mesh())
49, m_cmesh(cmesh)
50, m_num_mng(numbering_mng)
51{
52}
53
54/*---------------------------------------------------------------------------*/
55/*---------------------------------------------------------------------------*/
56
57/*
58 * For the comments of this method, we consider the following coordinate system:
59 * (top)
60 * y (front)
61 * ^ z
62 * | /
63 * | /
64 * (left) ------->x (right)
65 * (rear)(bottom)
66 */
67void CartesianMeshAMRPatchMng::
68refine()
69{
70 IParallelMng* pm = m_mesh->parallelMng();
71 Int32 my_rank = pm->commRank();
72 Int32 max_level = 0;
73
74 UniqueArray<Cell> cell_to_refine_internals;
75 ENUMERATE_ (Cell, icell, m_mesh->allActiveCells()) {
76 Cell cell = *icell;
77 if (cell.itemBase().flags() & ItemFlags::II_Refine) {
78 cell_to_refine_internals.add(cell);
79 if (cell.level() > max_level)
80 max_level = cell.level();
81 }
82 }
83 m_num_mng->prepareLevel(max_level + 1);
84
85 UniqueArray<Int64> cells_infos;
86 UniqueArray<Int64> faces_infos;
87 UniqueArray<Int64> nodes_infos;
88
89 Integer total_nb_cells = 0;
90 Integer total_nb_nodes = 0;
91 Integer total_nb_faces = 0;
92
93 std::unordered_map<Int64, Int32> node_uid_to_owner;
94 std::unordered_map<Int64, Int32> face_uid_to_owner;
95
96 UniqueArray<Int64> node_uid_change_owner_only;
97 UniqueArray<Int64> face_uid_change_owner_only;
98
99 // Two arrays allowing the retrieval of unique IDs of nodes and faces
100 // from each child cell upon calling getNodeUids()/getFaceUids().
101 UniqueArray<Int64> child_nodes_uids(m_num_mng->nbNodeByCell());
102 UniqueArray<Int64> child_faces_uids(m_num_mng->nbFaceByCell());
103
104 // We must record the parent cells of each child cell to update connectivities
105 // when creating the cells.
106 UniqueArray<Int32> parent_cells;
107
108 // Maps replacing ghost cells.
109 std::unordered_map<Int64, Int32> around_parent_cells_uid_to_owner;
110 std::unordered_map<Int64, Int32> around_parent_cells_uid_to_flags;
111
112 {
113 // We only need these two flags for surrounding cells.
114 // (II_Refine to know if surrounding cells are in the same patch)
115 // (II_Inactive to know if surrounding cells are already refined)
117 _shareInfosOfCellsAroundPatch(cell_to_refine_internals, around_parent_cells_uid_to_owner, around_parent_cells_uid_to_flags, useful_flags);
118 }
119
120 if (m_mesh->dimension() == 2) {
121
122 // Masks for "child neighbors" and "parent neighbors in the same patch" cases.
123 // These masks determine whether a node should be created based on
124 // the surrounding cells.
125 // For example, if we are studying a child cell and there is
126 // a child cell to the left, we should not create nodes 0 and 3 (mask_node_if_cell_left[]) (because
127 // they have already been created by the cell on the left).
128 // The same applies to neighboring parent cells: if we are on a child cell located
129 // on the left side of the parent cell (child cells 0 and 2 in the case of a
130 // refinement pattern = 2), and there is a parent cell to the left and that parent cell
131 // is currently ((being refined and in our subdomain) or (is inactive)), we apply
132 // the mask_node_if_cell_left[] rule because the nodes were created by it and we want to avoid
133 // duplicate nodes.
134 // These masks also allow us to determine the owner of the nodes in
135 // the case of multiple subdomains.
136 // For example, if we are on a child cell located
137 // on the left side of the parent cell (child cells 0 and 2 in the case of a
138 // refinement pattern = 2), and there is a parent cell to the left and that cell
139 // (belongs to another subdomain) and (is currently being refined),
140 // we create this node but assign the process that owns
141 // the parent cell on the left as the owner.
142 constexpr bool mask_node_if_cell_left[] = { false, true, true, false };
143 constexpr bool mask_node_if_cell_bottom[] = { false, false, true, true };
144
145 constexpr bool mask_node_if_cell_right[] = { true, false, false, true };
146 constexpr bool mask_node_if_cell_top[] = { true, true, false, false };
147
148 constexpr bool mask_face_if_cell_left[] = { true, true, true, false };
149 constexpr bool mask_face_if_cell_bottom[] = { false, true, true, true };
150
151 constexpr bool mask_face_if_cell_right[] = { true, false, true, true };
152 constexpr bool mask_face_if_cell_top[] = { true, true, false, true };
153
154 // For sizing:
155 // - we have "cell_to_refine_internals.size() * 4" child cells,
156 // - for each cell, we have 2 pieces of info (cell type and cell uniqueId)
157 // - for each cell, we have "m_num_mng->getNbNode()" uniqueIds (the uniqueIds of each node in the cell).
158 cells_infos.reserve((cell_to_refine_internals.size() * 4) * (2 + m_num_mng->nbNodeByCell()));
159
160 // For sizing, maximum:
161 // - we have "cell_to_refine_internals.size() * 12" faces
162 // - for each face, we have 2 pieces of info (face type and face uniqueId)
163 // - for each face, we have 2 node uniqueIds.
164 faces_infos.reserve((cell_to_refine_internals.size() * 12) * (2 + 2));
165
166 // For sizing, maximum:
167 // - we have (cell_to_refine_internals.size() * 9) node uniqueIds.
168 nodes_infos.reserve(cell_to_refine_internals.size() * 9);
169
170 FixedArray<Int64, 9> uid_cells_around_parent_cell_1d;
171 FixedArray<Int32, 9> owner_cells_around_parent_cell_1d;
172 FixedArray<Int32, 9> flags_cells_around_parent_cell_1d;
173
174 for (Cell parent_cell : cell_to_refine_internals) {
175 const Int64 parent_cell_uid = parent_cell.uniqueId();
176 const Int32 parent_cell_level = parent_cell.level();
177 const bool parent_cell_is_own = (parent_cell.owner() == my_rank);
178
179 const CartCoord parent_coord_x = m_num_mng->cellUniqueIdToCoordX(parent_cell_uid, parent_cell_level);
180 const CartCoord parent_coord_y = m_num_mng->cellUniqueIdToCoordY(parent_cell_uid, parent_cell_level);
181
182 const CartCoord child_coord_x = m_num_mng->offsetLevelToLevel(parent_coord_x, parent_cell_level, parent_cell_level + 1);
183 const CartCoord child_coord_y = m_num_mng->offsetLevelToLevel(parent_coord_y, parent_cell_level, parent_cell_level + 1);
184
185 const Int32 pattern = m_num_mng->pattern();
186
187 m_num_mng->cellUniqueIdsAroundCell(parent_cell, uid_cells_around_parent_cell_1d.view());
188
189 for (Int32 i = 0; i < 9; ++i) {
190 const Int64 uid_cell = uid_cells_around_parent_cell_1d[i];
191 // If uid_cell != -1, there might be a cell (but we don't know if it is actually present).
192 // If around_parent_cells_uid_to_owner[uid_cell] != -1, there is indeed a cell.
193 if (uid_cell != -1 && around_parent_cells_uid_to_owner[uid_cell] != -1) {
194 owner_cells_around_parent_cell_1d[i] = around_parent_cells_uid_to_owner[uid_cell];
195 flags_cells_around_parent_cell_1d[i] = around_parent_cells_uid_to_flags[uid_cell];
196 }
197 else {
198 uid_cells_around_parent_cell_1d[i] = -1;
199 owner_cells_around_parent_cell_1d[i] = -1;
200 flags_cells_around_parent_cell_1d[i] = 0;
201 }
202 }
203
204 // To simplify, we use 2D views. (array[Y][X]).
205 ConstArray2View uid_cells_around_parent_cell(uid_cells_around_parent_cell_1d.data(), 3, 3);
206 ConstArray2View owner_cells_around_parent_cell(owner_cells_around_parent_cell_1d.data(), 3, 3);
207 ConstArray2View flags_cells_around_parent_cell(flags_cells_around_parent_cell_1d.data(), 3, 3);
208
209 // #priority_owner_2d
210 // Here are the priorities for node and face ownership:
211 // ┌─────────┐
212 // │6 7 8│
213 // └───────┐ │
214 // ┌─┐ ┌─┐ │ │
215 // │3│ │4│ │5│
216 // │ │ └─┘ └─┘
217 // │ └───────┐
218 // │0 1 2│
219 // └─────────┘
220 //
221 // ^y
222 // |
223 // ->x
224
225 // #arcane_order_to_around_2d
226 // Note for 2D Cartesian meshes:
227 // The face iterators iterate in the order (for cell 4 here):
228 // 0. Face between [4, 1],
229 // 1. Face between [4, 5],
230 // 2. Face between [4, 7],
231 // 3. Face between [4, 3],
232 //
233 // The node iterators iterate in the order (for cell 4 here):
234 // 0. Node between [4, 0]
235 // 1. Node between [4, 2]
236 // 2. Node between [4, 8]
237 // 3. Node between [4, 6]
238
239 // Each number designates a parent cell and a priority (0 being the highest priority).
240 // 4 = parent_cell ("us")
241
242 // Example 1:
243 // We are looking to refine level 0 cells (i.e., create level 1 cells).
244 // At the bottom, there are no cells.
245 // On the left (priority 3), there is a cell that is already refined (flag "II_Inactive").
246 // We are priority 4, so we are prioritized. Therefore, the nodes and faces we share
247 // belong to it.
248
249 // Example 2:
250 // We are looking to refine level 0 cells (i.e., create level 1 cells).
251 // At the top, there are already refined cells (flag "II_Inactive").
252 // We are prioritized over them, so we recover the ownership of the nodes and faces we share. This change of ownership must be signaled to them.
253
254 // We simplify using a boolean array.
255 // If true, we must apply the ownership priority.
256 // If false, we consider that there is no cell at the defined position.
257 FixedArray<FixedArray<bool, 3>, 3> is_cell_around_parent_cell_present_and_useful;
258
259 // For cells that prioritize us, we must look at both flags.
260 // If a cell has the "II_Refine" flag, we do not exist for it, so it takes ownership
261 // of the faces and nodes we share.
262 // If a cell has the "II_Inactive" flag, it already has the correct owners.
263 // In any case, if true, the faces and nodes we share belong to them.
264 is_cell_around_parent_cell_present_and_useful[0][0] = ((uid_cells_around_parent_cell(0, 0) != -1) && (flags_cells_around_parent_cell(0, 0) & (ItemFlags::II_Refine | ItemFlags::II_Inactive)));
265 is_cell_around_parent_cell_present_and_useful[0][1] = ((uid_cells_around_parent_cell(0, 1) != -1) && (flags_cells_around_parent_cell(0, 1) & (ItemFlags::II_Refine | ItemFlags::II_Inactive)));
266 is_cell_around_parent_cell_present_and_useful[0][2] = ((uid_cells_around_parent_cell(0, 2) != -1) && (flags_cells_around_parent_cell(0, 2) & (ItemFlags::II_Refine | ItemFlags::II_Inactive)));
267
268 is_cell_around_parent_cell_present_and_useful[1][0] = ((uid_cells_around_parent_cell(1, 0) != -1) && (flags_cells_around_parent_cell(1, 0) & (ItemFlags::II_Refine | ItemFlags::II_Inactive)));
269 // is_cell_around_parent_cell_present_and_useful[1][1] = parent_cell;
270
271 // For non-prioritized cells, we must look at only one flag.
272 // If a cell has the "II_Inactive" flag, it must be notified that we are taking ownership
273 // of the nodes and faces we share.
274 // We do not look at the "II_Refine" flag because, if these cells are also being refined,
275 // they know that we exist and that we obtain the ownership of the nodes and faces we share.
276 // In summary, if true, the faces and nodes we share belong to us.
277 is_cell_around_parent_cell_present_and_useful[1][2] = ((uid_cells_around_parent_cell(1, 2) != -1) && (flags_cells_around_parent_cell(1, 2) & ItemFlags::II_Inactive));
278
279 is_cell_around_parent_cell_present_and_useful[2][0] = ((uid_cells_around_parent_cell(2, 0) != -1) && (flags_cells_around_parent_cell(2, 0) & ItemFlags::II_Inactive));
280 is_cell_around_parent_cell_present_and_useful[2][1] = ((uid_cells_around_parent_cell(2, 1) != -1) && (flags_cells_around_parent_cell(2, 1) & ItemFlags::II_Inactive));
281 is_cell_around_parent_cell_present_and_useful[2][2] = ((uid_cells_around_parent_cell(2, 2) != -1) && (flags_cells_around_parent_cell(2, 2) & ItemFlags::II_Inactive));
282
283 // In addition to checking if each parent cell around our parent cell exists and possesses (II_Inactive) or will possess (II_Refine) children...
284 // ... we check if each parent cell is present in our subdomain, whether it is a ghost cell or not.
285 auto is_cell_around_parent_cell_in_subdomain = [&](const Integer y, const Integer x) {
286 return is_cell_around_parent_cell_present_and_useful[y][x] && (flags_cells_around_parent_cell(y, x) & ItemFlags::II_UserMark1);
287 };
288
289 // ... we check if each parent cell is owned by the same owner as our parent cell.
290 auto is_cell_around_parent_cell_same_owner = [&](const Integer y, const Integer x) {
291 return is_cell_around_parent_cell_present_and_useful[y][x] && (owner_cells_around_parent_cell(y, x) == owner_cells_around_parent_cell(1, 1));
292 };
293
294 // ... we check if each parent cell has a different owner compared to our parent cell.
295 auto is_cell_around_parent_cell_different_owner = [&](const Integer y, const Integer x) {
296 return is_cell_around_parent_cell_present_and_useful[y][x] && (owner_cells_around_parent_cell(y, x) != owner_cells_around_parent_cell(1, 1));
297 };
298
299 // We iterate over all child cells.
300 for (CartCoord j = child_coord_y; j < child_coord_y + pattern; ++j) {
301 for (CartCoord i = child_coord_x; i < child_coord_x + pattern; ++i) {
302 parent_cells.add(parent_cell.localId());
303 total_nb_cells++;
304
305 const Int64 child_cell_uid = m_num_mng->cellUniqueId(CartCoord2(i, j), parent_cell_level + 1);
306 // debug() << "Child -- x : " << i << " -- y : " << j << " -- level : " << parent_cell_level + 1 << " -- uid : " << child_cell_uid;
307
308 m_num_mng->cellNodeUniqueIds(CartCoord2(i, j), parent_cell_level + 1, child_nodes_uids);
309 m_num_mng->cellFaceUniqueIds(CartCoord2(i, j), parent_cell_level + 1, child_faces_uids);
310
311 constexpr Integer type_cell = IT_Quad4;
312 constexpr Integer type_face = IT_Line2;
313
314 // Cell Part.
315 cells_infos.add(type_cell);
316 cells_infos.add(child_cell_uid);
317 for (Integer nc = 0; nc < m_num_mng->nbNodeByCell(); nc++) {
318 cells_infos.add(child_nodes_uids[nc]);
319 }
320
321 // Face Part.
322 for (Integer l = 0; l < m_num_mng->nbFaceByCell(); ++l) {
323 Integer child_face_owner = -1;
324 bool is_new_face = false;
325
326 // Two parts:
327 // First, we check if we should create face l. To do this, we must check if it is present on the
328 // adjacent cell.
329 // For left/bottom, the principle is the same. If the child cell is entirely to the left/bottom of the parent cell, we check
330 // if there is a parent cell to the left/bottom. Otherwise, we create the face. If yes, we check the mask to know if we
331 // should create the face.
332 // For right/top, the principle is different from left/bottom. We only follow the mask if we are entirely to the right/top
333 // of the parent cell. Otherwise, we always create the right/top faces.
334 // Finally, we use the "is_cell_around_parent_cell_in_subdomain" array. If the adjacent parent cell is in
335 // our subdomain, the faces shared with our parent cell may already exist; in this case,
336 // there is no duplicate.
337 if (
338 ((i == child_coord_x && !is_cell_around_parent_cell_in_subdomain(1, 0)) || (mask_face_if_cell_left[l])) &&
339 ((i != (child_coord_x + pattern - 1) || !is_cell_around_parent_cell_in_subdomain(1, 2)) || mask_face_if_cell_right[l]) &&
340 ((j == child_coord_y && !is_cell_around_parent_cell_in_subdomain(0, 1)) || (mask_face_if_cell_bottom[l])) &&
341 ((j != (child_coord_y + pattern - 1) || !is_cell_around_parent_cell_in_subdomain(2, 1)) || mask_face_if_cell_top[l])) {
342 is_new_face = true;
343 faces_infos.add(type_face);
344 faces_infos.add(child_faces_uids[l]);
345
346 // The face nodes are always nodes l and l+1
347 // because we use the same exploration for both cases.
348 for (Integer nc = l; nc < l + 2; nc++) {
349 faces_infos.add(child_nodes_uids[nc % m_num_mng->nbNodeByCell()]);
350 }
351 total_nb_faces++;
352
353 // By default, parent_cell is the owner of the new face.
354 child_face_owner = owner_cells_around_parent_cell(1, 1);
355 }
356
357 // Second part.
358 // We must now find the correct owner for the face. Aside from the "is_cell_around_parent_cell_same_owner" array,
359 // the condition is identical to the one above.
360 // The change of array is important because from here on, we are sure that the face we are interested in exists.
361 // The new array allows us to know if the adjacent cell is also ours or not. If not, then
362 // an ownership change is possible, according to the priorities defined above. We do not need to know
363 // if the cell is present in the subdomain.
364 if (
365 ((i == child_coord_x && !is_cell_around_parent_cell_same_owner(1, 0)) || (mask_face_if_cell_left[l])) &&
366 ((i != (child_coord_x + pattern - 1) || !is_cell_around_parent_cell_same_owner(1, 2)) || mask_face_if_cell_right[l]) &&
367 ((j == child_coord_y && !is_cell_around_parent_cell_same_owner(0, 1)) || (mask_face_if_cell_bottom[l])) &&
368 ((j != (child_coord_y + pattern - 1) || !is_cell_around_parent_cell_same_owner(2, 1)) || mask_face_if_cell_top[l])) {
369 // Here, the condition construction is the same every time.
370 // The first boolean (i == child_coord_x) checks if the child is on the correct side of the parent cell.
371 // The second boolean (!mask_face_if_cell_left[l]) tells us if face l is indeed
372 // the shared face with the adjacent parent cell.
373 // The third boolean (is_cell_around_parent_cell_different_owner(1, 0)) checks if there is an
374 // adjacent cell that takes ownership of the face or to whom we take ownership.
375
376 // Furthermore, there are two different cases depending on the priorities defined above:
377 // - either we are not prioritized, so we assign the priority owner to our face,
378 // - or we are prioritized, so we position ourselves as the owner of the face and must notify
379 // all other processes (the former owner process as well as processes that may
380 // have the face as a ghost).
381
382 // Finally, in the case of ownership change, only the process taking over ownership must
383 // communicate about it. Processes that only possess the ghost face should not
384 // communicate (but they can locally define the correct owner, TODO Possible Optimization?).
385
386 // On the left, priority 3 < 4, so it takes ownership of the face.
387 if (i == child_coord_x && (!mask_face_if_cell_left[l]) && is_cell_around_parent_cell_different_owner(1, 0)) {
388 child_face_owner = owner_cells_around_parent_cell(1, 0);
389 }
390
391 // At the bottom, priority 1 < 4, so it takes ownership of the face.
392 else if (j == child_coord_y && (!mask_face_if_cell_bottom[l]) && is_cell_around_parent_cell_different_owner(0, 1)) {
393 child_face_owner = owner_cells_around_parent_cell(0, 1);
394 }
395
396 // Otherwise, parent_cell is the owner of the face.
397 else {
398
399 // Otherwise, it is an internal face belonging to parent_cell.
400 child_face_owner = owner_cells_around_parent_cell(1, 1);
401 }
402 }
403
404 // If there is a face creation and/or an ownership change.
405 if (child_face_owner != -1) {
406 face_uid_to_owner[child_faces_uids[l]] = child_face_owner;
407
408 // When there is an ownership change without face creation,
409 // we must set aside the uniqueIds of these faces to be able to iterate over them later.
410 if (!is_new_face) {
411 face_uid_change_owner_only.add(child_faces_uids[l]);
412 // debug() << "Child face (change owner) -- x : " << i
413 // << " -- y : " << j
414 // << " -- level : " << parent_cell_level + 1
415 // << " -- face : " << l
416 // << " -- uid_face : " << child_faces_uids[l]
417 // << " -- owner : " << child_face_owner;
418 }
419 else {
420 // debug() << "Child face (create face) -- x : " << i
421 // << " -- y : " << j
422 // << " -- level : " << parent_cell_level + 1
423 // << " -- face : " << l
424 // << " -- uid_face : " << child_faces_uids[l]
425 // << " -- owner : " << child_face_owner;
426 }
427 }
428 }
429
430 // Node Part.
431 // This part is quite similar to the face part, except that there can be
432 // more possible owners.
433 for (Int32 l = 0; l < m_num_mng->nbNodeByCell(); ++l) {
434 Int32 child_node_owner = -1;
435 bool is_new_node = false;
436
437 // Two parts:
438 // First, we check if we should create node l. To do this, we must check if it is present on the
439 // adjacent cell.
440 // For left/bottom, the principle is the same. If the child cell is entirely to the left/bottom of the parent cell, we check
441 // if there is a parent cell to the left/bottom. Otherwise, we create the node. If yes, we check the mask to know if we
442 // should create the node.
443 // For right/top, the principle is different from left/bottom. We only follow the mask if the child cell is entirely to the right/top
444 // of the parent cell. Otherwise, we always create the right/top nodes.
445 // Finally, we use the "is_cell_around_parent_cell_in_subdomain" array. If the adjacent parent cell is in
446 // our subdomain, the nodes shared with our parent cell may already exist; in this case,
447 // there is no duplicate.
448 if (
449 ((i == child_coord_x && !is_cell_around_parent_cell_in_subdomain(1, 0)) || (mask_node_if_cell_left[l])) &&
450 ((i != (child_coord_x + pattern - 1) || !is_cell_around_parent_cell_in_subdomain(1, 2)) || mask_node_if_cell_right[l]) &&
451 ((j == child_coord_y && !is_cell_around_parent_cell_in_subdomain(0, 1)) || (mask_node_if_cell_bottom[l])) &&
452 ((j != (child_coord_y + pattern - 1) || !is_cell_around_parent_cell_in_subdomain(2, 1)) || mask_node_if_cell_top[l])) {
453 is_new_node = true;
454 nodes_infos.add(child_nodes_uids[l]);
455 total_nb_nodes++;
456
457 // By default, parent_cell is the owner of the new node.
458 child_node_owner = owner_cells_around_parent_cell(1, 1);
459 }
460
461 // Second part.
462 // We must now find the correct owner for the node. Aside from the array "is_cell_around_parent_cell_same_owner",
463 // the condition is identical to the one above.
464 // The change of array is important because from here, we are sure that the node we are interested in exists.
465 // The new array allows us to know if the neighboring cell is also ours or not. If not, then
466 // an owner change is possible, according to the priorities defined above. We do not need to know
467 // if the cell is present in the subdomain.
468 if (
469 ((i == child_coord_x && !is_cell_around_parent_cell_same_owner(1, 0)) || (mask_node_if_cell_left[l])) &&
470 ((i != (child_coord_x + pattern - 1) || !is_cell_around_parent_cell_same_owner(1, 2)) || mask_node_if_cell_right[l]) &&
471 ((j == child_coord_y && !is_cell_around_parent_cell_same_owner(0, 1)) || (mask_node_if_cell_bottom[l])) &&
472 ((j != (child_coord_y + pattern - 1) || !is_cell_around_parent_cell_same_owner(2, 1)) || mask_node_if_cell_top[l])) {
473 // Compared to faces that only have two possible owners, a node can
474 // have up to four.
475 // (And yes, in 3D, it's even more fun!)
476
477 // If the node is on the left side of the parent cell ("on the left face").
478 if (i == child_coord_x && (!mask_node_if_cell_left[l])) {
479
480 // If the node is on the bottom of the parent cell ("on the bottom face").
481 // So, node in bottom left (same position as the parent cell node).
482 if (j == child_coord_y && (!mask_node_if_cell_bottom[l])) {
483
484 // Priority 0 < 4.
485 if (is_cell_around_parent_cell_different_owner(0, 0)) {
486 child_node_owner = owner_cells_around_parent_cell(0, 0);
487 }
488
489 // Priority 1 < 4.
490 else if (is_cell_around_parent_cell_different_owner(0, 1)) {
491 child_node_owner = owner_cells_around_parent_cell(0, 1);
492 }
493
494 // Priority 3 < 4.
495 else if (is_cell_around_parent_cell_different_owner(1, 0)) {
496 child_node_owner = owner_cells_around_parent_cell(1, 0);
497 }
498
499 else {
500 child_node_owner = owner_cells_around_parent_cell(1, 1);
501 }
502 }
503
504 // If the node is on the top of the parent cell ("on the top face").
505 // So, node in top left (same position as the parent cell node).
506 else if (j == (child_coord_y + pattern - 1) && (!mask_node_if_cell_top[l])) {
507
508 // Priority 3 < 4.
509 if (is_cell_around_parent_cell_different_owner(1, 0)) {
510 child_node_owner = owner_cells_around_parent_cell(1, 0);
511 }
512
513 // Otherwise, parent_cell is the owner of the node.
514 else {
515 child_node_owner = owner_cells_around_parent_cell(1, 1);
516 }
517 }
518
519 // If the node is somewhere on the parent left face...
520 else {
521 // If there is a cell to the left, it is the owner of the node.
522 if (is_cell_around_parent_cell_different_owner(1, 0)) {
523 child_node_owner = owner_cells_around_parent_cell(1, 0);
524 }
525
526 // Otherwise, parent_cell is the owner of the node.
527 else {
528 child_node_owner = owner_cells_around_parent_cell(1, 1);
529 }
530 }
531 }
532
533 // If the node is on the right side of the parent cell ("on the right face").
534 else if (i == (child_coord_x + pattern - 1) && (!mask_node_if_cell_right[l])) {
535
536 // If the node is on the bottom of the parent cell ("on the bottom face").
537 // So, node in bottom right (same position as the parent cell node).
538 if (j == child_coord_y && (!mask_node_if_cell_bottom[l])) {
539
540 // Priority 1 < 4.
541 if (is_cell_around_parent_cell_different_owner(0, 1)) {
542 child_node_owner = owner_cells_around_parent_cell(0, 1);
543 }
544
545 // Priority 2 < 4.
546 else if (is_cell_around_parent_cell_different_owner(0, 2)) {
547 child_node_owner = owner_cells_around_parent_cell(0, 2);
548 }
549
550 // Otherwise, parent_cell is the owner of the node.
551 else {
552 child_node_owner = owner_cells_around_parent_cell(1, 1);
553 }
554 }
555
556 // If the node is on the top of the parent cell ("on the top face").
557 // So, node in top right (same position as the parent cell node).
558 else if (j == (child_coord_y + pattern - 1) && (!mask_node_if_cell_top[l])) {
559 child_node_owner = owner_cells_around_parent_cell(1, 1);
560 }
561
562 // If the node is somewhere on the parent right face...
563 else {
564 child_node_owner = owner_cells_around_parent_cell(1, 1);
565 }
566 }
567
568 // If the node is neither on the parent left face nor on the parent right face...
569 else {
570
571 // If the node is on the bottom of the parent cell ("on the bottom face") and
572 // there is a bottom cell with priority 1 < 4, it is the owner of the node.
573 if (j == child_coord_y && (!mask_node_if_cell_bottom[l]) && is_cell_around_parent_cell_different_owner(0, 1)) {
574 child_node_owner = owner_cells_around_parent_cell(0, 1);
575 }
576
577 // If the node is on the top of the parent cell ("on the top face") and
578 // there is a top cell with priority 7 > 4, parent_cell is the owner of the node.
579 else if (parent_cell_is_own && j == (child_coord_y + pattern - 1) && (!mask_node_if_cell_top[l]) && is_cell_around_parent_cell_different_owner(2, 1)) {
580 child_node_owner = owner_cells_around_parent_cell(1, 1);
581 }
582
583 // Nodes that are not on any face of the parent cell.
584 else {
585 child_node_owner = owner_cells_around_parent_cell(1, 1);
586 }
587 }
588 }
589
590 // If there is a node creation and/or an owner change.
591 if (child_node_owner != -1) {
592 node_uid_to_owner[child_nodes_uids[l]] = child_node_owner;
593
594 // When there is an owner change without node creation,
595 // we must set aside the uniqueIds of these nodes to be able to
596 // iterate over them later.
597 if (!is_new_node) {
598 node_uid_change_owner_only.add(child_nodes_uids[l]);
599 // debug() << "Child node (change owner) -- x : " << i
600 // << " -- y : " << j
601 // << " -- level : " << parent_cell_level + 1
602 // << " -- node : " << l
603 // << " -- uid_node : " << child_nodes_uids[l]
604 // << " -- owner : " << child_node_owner;
605 }
606 else {
607 // debug() << "Child node (create node) -- x : " << i
608 // << " -- y : " << j
609 // << " -- level : " << parent_cell_level + 1
610 // << " -- node : " << l
611 // << " -- uid_node : " << child_nodes_uids[l]
612 // << " -- owner : " << child_node_owner;
613 }
614 }
615 }
616 }
617 }
618 }
619 }
620
621 // For 3D, it is very similar, just a bit longer. I am copying the comments, but with some adaptations.
622 else if (m_mesh->dimension() == 3) {
623
624 // Masks for "child neighbors" and "parent neighbors of the same patch" cases.
625 // These masks allow us to know whether we should create a node or not depending on
626 // the surrounding cells.
627 // For example, if we are studying a child cell and there is
628 // a child cell to the left, we should not create nodes 0, 3, 4, 7 (mask_node_if_cell_left[]) (because
629 // they have already been created by the cell to the left).
630 // Same for neighboring parent cells: if we are on a child cell located
631 // on the left side of the parent cell (child cells 0, 2, 4, 6 in the case of a
632 // refinement pattern = 2), there is a parent cell to the left and that parent cell
633 // is currently ((being refined and in our subdomain) or (is inactive)), we apply
634 // the mask_node_if_cell_left[] rule because the nodes were created by it and we want to avoid
635 // duplicate nodes.
636 // These masks also allow us to determine the owner of the nodes in
637 // the case of multiple subdomains.
638 // For example, if we are on a child cell located
639 // on the left side of the parent cell (child cells 0, 2, 4, 6 in the case of a
640 // refinement pattern = 2), there is a parent cell to the left and that cell
641 // (belongs to another subdomain) and (is being refined),
642 // we create this node but we give it as owner the process to which belongs
643 // the parent cell to the left.
644 constexpr bool mask_node_if_cell_left[] = { false, true, true, false, false, true, true, false };
645 constexpr bool mask_node_if_cell_bottom[] = { false, false, true, true, false, false, true, true };
646 constexpr bool mask_node_if_cell_rear[] = { false, false, false, false, true, true, true, true };
647
648 constexpr bool mask_node_if_cell_right[] = { true, false, false, true, true, false, false, true };
649 constexpr bool mask_node_if_cell_top[] = { true, true, false, false, true, true, false, false };
650 constexpr bool mask_node_if_cell_front[] = { true, true, true, true, false, false, false, false };
651
652 constexpr bool mask_face_if_cell_left[] = { true, false, true, true, true, true };
653 constexpr bool mask_face_if_cell_bottom[] = { true, true, false, true, true, true };
654 constexpr bool mask_face_if_cell_rear[] = { false, true, true, true, true, true };
655
656 constexpr bool mask_face_if_cell_right[] = { true, true, true, true, false, true };
657 constexpr bool mask_face_if_cell_top[] = { true, true, true, true, true, false };
658 constexpr bool mask_face_if_cell_front[] = { true, true, true, false, true, true };
659
660 // Small difference compared to 2D. For 2D, the position of the face nodes
661 // in the "child_nodes_uids" array is always the same (l and l+1, see 2D).
662 // For 3D, this is not the case, so we have arrays to have a correspondence
663 // between the nodes of each face and the position of the nodes in the "child_nodes_uids" array.
664 // (Example: for face 1 (same enumeration order as Arcane), we must take the
665 // "nodes_in_face_1" array and therefore the nodes "child_nodes_uids[0]", "child_nodes_uids[3]",
666 // "child_nodes_uids[7]" and "child_nodes_uids[4]").
667 constexpr Int32 nodes_in_face_0[] = { 0, 1, 2, 3 };
668 constexpr Int32 nodes_in_face_1[] = { 0, 3, 7, 4 };
669 constexpr Int32 nodes_in_face_2[] = { 0, 1, 5, 4 };
670 constexpr Int32 nodes_in_face_3[] = { 4, 5, 6, 7 };
671 constexpr Int32 nodes_in_face_4[] = { 1, 2, 6, 5 };
672 constexpr Int32 nodes_in_face_5[] = { 3, 2, 6, 7 };
673
674 constexpr Int32 nb_nodes_in_face = 4;
675
676 // For the size:
677 // - we have "cell_to_refine_internals.size() * 8" child cells,
678 // - for each cell, we have 2 pieces of information (cell type and cell uniqueId)
679 // - for each cell, we have "m_num_mng->getNbNode()" uniqueIds (the uniqueIds of each node of the cell).
680 cells_infos.reserve((cell_to_refine_internals.size() * 8) * (2 + m_num_mng->nbNodeByCell()));
681
682 // For the size, maximum:
683 // - we have "cell_to_refine_internals.size() * 36" child faces,
684 // - for each face, we have 2 pieces of information (face type and face uniqueId)
685 // - for each face, we have 4 node uniqueIds.
686 faces_infos.reserve((cell_to_refine_internals.size() * 36) * (2 + 4));
687
688 // For the size, maximum:
689 // - we have (cell_to_refine_internals.size() * 27) node uniqueIds.
690 nodes_infos.reserve(cell_to_refine_internals.size() * 27);
691
692 FixedArray<Int64, 27> uid_cells_around_parent_cell_1d;
693 FixedArray<Int32, 27> owner_cells_around_parent_cell_1d;
694 FixedArray<Int32, 27> flags_cells_around_parent_cell_1d;
695
696 for (Cell parent_cell : cell_to_refine_internals) {
697 const Int64 parent_cell_uid = parent_cell.uniqueId();
698 const Int32 parent_cell_level = parent_cell.level();
699
700 const CartCoord3 parent_coord = m_num_mng->cellUniqueIdToCoord(parent_cell_uid, parent_cell_level);
701 const CartCoord3 child_coord = m_num_mng->offsetLevelToLevel(parent_coord, parent_cell_level, parent_cell_level + 1);
702
703 const Int32 pattern = m_num_mng->pattern();
704
705 m_num_mng->cellUniqueIdsAroundCell(parent_cell, uid_cells_around_parent_cell_1d.view());
706
707 for (Integer i = 0; i < 27; ++i) {
708 Int64 uid_cell = uid_cells_around_parent_cell_1d[i];
709 // If uid_cell != -1, there might be a cell (but we don't know if it is actually present).
710 // If around_parent_cells_uid_to_owner[uid_cell] != -1, there is indeed a cell.
711 if (uid_cell != -1 && around_parent_cells_uid_to_owner[uid_cell] != -1) {
712 owner_cells_around_parent_cell_1d[i] = around_parent_cells_uid_to_owner[uid_cell];
713 flags_cells_around_parent_cell_1d[i] = around_parent_cells_uid_to_flags[uid_cell];
714 }
715 else {
716 uid_cells_around_parent_cell_1d[i] = -1;
717 owner_cells_around_parent_cell_1d[i] = -1;
718 flags_cells_around_parent_cell_1d[i] = 0;
719 }
720 }
721
722 // To simplify, we use 3D views. (array[Z][Y][X]).
723 ConstArray3View uid_cells_around_parent_cell(uid_cells_around_parent_cell_1d.data(), 3, 3, 3);
724 ConstArray3View owner_cells_around_parent_cell(owner_cells_around_parent_cell_1d.data(), 3, 3, 3);
725 ConstArray3View flags_cells_around_parent_cell(flags_cells_around_parent_cell_1d.data(), 3, 3, 3);
726
727 // #priority_owner_3d
728 // Here are the priorities for node and face ownership:
729 // ┌──────────┐ │ ┌──────────┐ │ ┌──────────┐
730 // │ 6 7 8│ │ │15 16 17│ │ │24 25 26│
731 // │ │ │ └───────┐ │ │ │ │
732 // │ │ │ ┌──┐┌──┐│ │ │ │ │
733 // │ 3 4 5│ │ │12││13││14│ │ │21 22 23│
734 // │ │ │ │ │└──┘└──┘ │ │ │
735 // │ │ │ │ └───────┐ │ │ │
736 // │ 0 1 2│ │ │ 9 10 11│ │ │18 19 20│
737 // └──────────┘ │ └──────────┘ │ └──────────┘
738 // Z=0 │ Z=1 │ Z=2
739 // ("rear") │ │ ("front")
740 //
741 // ^y
742 // |
743 // ->x
744
745 // #arcane_order_to_around_3d
746 // Note for 3D Cartesian meshes:
747 // The face iterators iterate in the order (for cell 13 here):
748 // 0. Face between [13, 4],
749 // 1. Face between [13, 12],
750 // 2. Face between [13, 10],
751 // 3. Face between [13, 22],
752 // 4. Face between [13, 14],
753 // 5. Face between [13, 16],
754 //
755 // The node iterators iterate in the order (for cell 13 here):
756 // 0. Node between [13, 0]
757 // 1. Node between [13, 2]
758 // 2. Node between [13, 8]
759 // 3. Node between [13, 6]
760 // 4. Node between [13, 18]
761 // 5. Node between [13, 20]
762 // 6. Node between [13, 26]
763 // 7. Node between [13, 24]
764
765 // Each number designates a parent cell and a priority (0 being the highest priority).
766 // 13 = parent_cell ("us")
767
768 // Example 1:
769 // We are looking to refine level 0 cells (thus creating level 1 cells).
770 // At the bottom, there are no cells.
771 // To the left (thus priority 12), there is a cell that is already refined (flag "II_Inactive").
772 // We are priority 13, so we are prioritized. Therefore, the nodes and faces we share
773 // belong to it.
774
775 // Example 2:
776 // We are looking to refine level 0 cells (thus creating level 1 cells).
777 // At the top, there are already refined cells (flag "II_Inactive").
778 // We are prioritized over them, so we retrieve the ownership of the nodes and faces we share
779 // in common. This ownership change must be signaled to them.
780
781 // We simplify with a boolean array.
782 // If true, then we must apply the ownership priority.
783 // If false, then we consider that there is no cell at the defined position.
784 FixedArray<FixedArray<FixedArray<bool, 3>, 3>, 3> is_cell_around_parent_cell_present_and_useful;
785
786 // For cells that are prioritized over us, we must look at both flags.
787 // If a cell has the "II_Refine" flag, we do not exist for it, so it takes ownership
788 // of the faces and nodes we share.
789 // If a cell has the "II_Inactive" flag, it already has the correct owners.
790 // In any case, if true, then the faces and nodes we share belong to them.
791 is_cell_around_parent_cell_present_and_useful[0][0][0] = ((uid_cells_around_parent_cell(0, 0, 0) != -1) && (flags_cells_around_parent_cell(0, 0, 0) & (ItemFlags::II_Refine | ItemFlags::II_Inactive)));
792 is_cell_around_parent_cell_present_and_useful[0][0][1] = ((uid_cells_around_parent_cell(0, 0, 1) != -1) && (flags_cells_around_parent_cell(0, 0, 1) & (ItemFlags::II_Refine | ItemFlags::II_Inactive)));
793 is_cell_around_parent_cell_present_and_useful[0][0][2] = ((uid_cells_around_parent_cell(0, 0, 2) != -1) && (flags_cells_around_parent_cell(0, 0, 2) & (ItemFlags::II_Refine | ItemFlags::II_Inactive)));
794 is_cell_around_parent_cell_present_and_useful[0][1][0] = ((uid_cells_around_parent_cell(0, 1, 0) != -1) && (flags_cells_around_parent_cell(0, 1, 0) & (ItemFlags::II_Refine | ItemFlags::II_Inactive)));
795 is_cell_around_parent_cell_present_and_useful[0][1][1] = ((uid_cells_around_parent_cell(0, 1, 1) != -1) && (flags_cells_around_parent_cell(0, 1, 1) & (ItemFlags::II_Refine | ItemFlags::II_Inactive)));
796 is_cell_around_parent_cell_present_and_useful[0][1][2] = ((uid_cells_around_parent_cell(0, 1, 2) != -1) && (flags_cells_around_parent_cell(0, 1, 2) & (ItemFlags::II_Refine | ItemFlags::II_Inactive)));
797 is_cell_around_parent_cell_present_and_useful[0][2][0] = ((uid_cells_around_parent_cell(0, 2, 0) != -1) && (flags_cells_around_parent_cell(0, 2, 0) & (ItemFlags::II_Refine | ItemFlags::II_Inactive)));
798 is_cell_around_parent_cell_present_and_useful[0][2][1] = ((uid_cells_around_parent_cell(0, 2, 1) != -1) && (flags_cells_around_parent_cell(0, 2, 1) & (ItemFlags::II_Refine | ItemFlags::II_Inactive)));
799 is_cell_around_parent_cell_present_and_useful[0][2][2] = ((uid_cells_around_parent_cell(0, 2, 2) != -1) && (flags_cells_around_parent_cell(0, 2, 2) & (ItemFlags::II_Refine | ItemFlags::II_Inactive)));
800
801 is_cell_around_parent_cell_present_and_useful[1][0][0] = ((uid_cells_around_parent_cell(1, 0, 0) != -1) && (flags_cells_around_parent_cell(1, 0, 0) & (ItemFlags::II_Refine | ItemFlags::II_Inactive)));
802 is_cell_around_parent_cell_present_and_useful[1][0][1] = ((uid_cells_around_parent_cell(1, 0, 1) != -1) && (flags_cells_around_parent_cell(1, 0, 1) & (ItemFlags::II_Refine | ItemFlags::II_Inactive)));
803 is_cell_around_parent_cell_present_and_useful[1][0][2] = ((uid_cells_around_parent_cell(1, 0, 2) != -1) && (flags_cells_around_parent_cell(1, 0, 2) & (ItemFlags::II_Refine | ItemFlags::II_Inactive)));
804
805 is_cell_around_parent_cell_present_and_useful[1][1][0] = ((uid_cells_around_parent_cell(1, 1, 0) != -1) && (flags_cells_around_parent_cell(1, 1, 0) & (ItemFlags::II_Refine | ItemFlags::II_Inactive)));
806 // is_cell_around_parent_cell_present_and_useful[1][1][1] = parent_cell;
807
808 // For non-prioritized cells, we only need to look at one flag.
809 // If a cell has the "II_Inactive" flag, it must be notified that we are taking ownership
810 // of the nodes and faces we share.
811 // We do not look at the "II_Refine" flag because, if these cells are also being refined,
812 // they know that we exist and that we obtain ownership of the nodes and faces we share.
813 // In summary, if true, then the faces and nodes we share belong to us.
814 is_cell_around_parent_cell_present_and_useful[1][1][2] = ((uid_cells_around_parent_cell(1, 1, 2) != -1) && (flags_cells_around_parent_cell(1, 1, 2) & ItemFlags::II_Inactive));
815
816 is_cell_around_parent_cell_present_and_useful[1][2][0] = ((uid_cells_around_parent_cell(1, 2, 0) != -1) && (flags_cells_around_parent_cell(1, 2, 0) & ItemFlags::II_Inactive));
817 is_cell_around_parent_cell_present_and_useful[1][2][1] = ((uid_cells_around_parent_cell(1, 2, 1) != -1) && (flags_cells_around_parent_cell(1, 2, 1) & ItemFlags::II_Inactive));
818 is_cell_around_parent_cell_present_and_useful[1][2][2] = ((uid_cells_around_parent_cell(1, 2, 2) != -1) && (flags_cells_around_parent_cell(1, 2, 2) & ItemFlags::II_Inactive));
819
820 is_cell_around_parent_cell_present_and_useful[2][0][0] = ((uid_cells_around_parent_cell(2, 0, 0) != -1) && (flags_cells_around_parent_cell(2, 0, 0) & ItemFlags::II_Inactive));
821 is_cell_around_parent_cell_present_and_useful[2][0][1] = ((uid_cells_around_parent_cell(2, 0, 1) != -1) && (flags_cells_around_parent_cell(2, 0, 1) & ItemFlags::II_Inactive));
822 is_cell_around_parent_cell_present_and_useful[2][0][2] = ((uid_cells_around_parent_cell(2, 0, 2) != -1) && (flags_cells_around_parent_cell(2, 0, 2) & ItemFlags::II_Inactive));
823 is_cell_around_parent_cell_present_and_useful[2][1][0] = ((uid_cells_around_parent_cell(2, 1, 0) != -1) && (flags_cells_around_parent_cell(2, 1, 0) & ItemFlags::II_Inactive));
824 is_cell_around_parent_cell_present_and_useful[2][1][1] = ((uid_cells_around_parent_cell(2, 1, 1) != -1) && (flags_cells_around_parent_cell(2, 1, 1) & ItemFlags::II_Inactive));
825 is_cell_around_parent_cell_present_and_useful[2][1][2] = ((uid_cells_around_parent_cell(2, 1, 2) != -1) && (flags_cells_around_parent_cell(2, 1, 2) & ItemFlags::II_Inactive));
826 is_cell_around_parent_cell_present_and_useful[2][2][0] = ((uid_cells_around_parent_cell(2, 2, 0) != -1) && (flags_cells_around_parent_cell(2, 2, 0) & ItemFlags::II_Inactive));
827 is_cell_around_parent_cell_present_and_useful[2][2][1] = ((uid_cells_around_parent_cell(2, 2, 1) != -1) && (flags_cells_around_parent_cell(2, 2, 1) & ItemFlags::II_Inactive));
828 is_cell_around_parent_cell_present_and_useful[2][2][2] = ((uid_cells_around_parent_cell(2, 2, 2) != -1) && (flags_cells_around_parent_cell(2, 2, 2) & ItemFlags::II_Inactive));
829
830 // In addition to looking at whether each surrounding parent cell exists and possesses (II_Inactive) or will possess (II_Refine) children...
831 // ... we look at whether each surrounding parent cell is present in our subdomain, whether it is a ghost cell or not.
832 auto is_cell_around_parent_cell_in_subdomain = [&](const Integer z, const Integer y, const Integer x) {
833 return is_cell_around_parent_cell_present_and_useful[z][y][x] && (flags_cells_around_parent_cell(z, y, x) & ItemFlags::II_UserMark1);
834 };
835
836 // ... we look at whether each surrounding parent cell is owned by the same owner as our parent cell.
837 auto is_cell_around_parent_cell_same_owner = [&](const Integer z, const Integer y, const Integer x) {
838 return is_cell_around_parent_cell_present_and_useful[z][y][x] && (owner_cells_around_parent_cell(z, y, x) == owner_cells_around_parent_cell(1, 1, 1));
839 };
840
841 // ... we look at whether each surrounding parent cell has a different owner compared to our parent cell.
842 auto is_cell_around_parent_cell_different_owner = [&](const Integer z, const Integer y, const Integer x) {
843 return is_cell_around_parent_cell_present_and_useful[z][y][x] && (owner_cells_around_parent_cell(z, y, x) != owner_cells_around_parent_cell(1, 1, 1));
844 };
845
846 // We iterate over all child cells.
847 for (CartCoord k = child_coord.z; k < child_coord.z + pattern; ++k) {
848 for (CartCoord j = child_coord.y; j < child_coord.y + pattern; ++j) {
849 for (CartCoord i = child_coord.x; i < child_coord.x + pattern; ++i) {
850 parent_cells.add(parent_cell.localId());
851 total_nb_cells++;
852
853 const Int64 child_cell_uid = m_num_mng->cellUniqueId(CartCoord3(i, j, k), parent_cell_level + 1);
854 // debug() << "Child -- x : " << i << " -- y : " << j << " -- z : " << k << " -- level : " << parent_cell_level + 1 << " -- uid : " << child_cell_uid;
855
856 m_num_mng->cellNodeUniqueIds(CartCoord3(i, j, k), parent_cell_level + 1, child_nodes_uids);
857 m_num_mng->cellFaceUniqueIds(CartCoord3(i, j, k), parent_cell_level + 1, child_faces_uids);
858
859 constexpr Int64 type_cell = IT_Hexaedron8;
860 constexpr Int64 type_face = IT_Quad4;
861
862 // Cell part.
863 cells_infos.add(type_cell);
864 cells_infos.add(child_cell_uid);
865 for (Int32 nc = 0; nc < m_num_mng->nbNodeByCell(); nc++) {
866 cells_infos.add(child_nodes_uids[nc]);
867 }
868
869 // Face part.
870 for (Int32 l = 0; l < m_num_mng->nbFaceByCell(); ++l) {
871 Int32 child_face_owner = -1;
872 bool is_new_face = false;
873
874 // Two parts:
875 // First, we check if we should create face l. To do this, we must check if it is present on the
876 // neighboring cell.
877 // For left/bottom/rear, the principle is the same. If the child cell is to the far left/bottom/rear of the parent cell, we check
878 // if there is a parent cell to the left/bottom/rear. Otherwise, we create the face. If yes, we check the mask to know if we
879 // should create the face.
880 // For right/top/front, the principle is different from left/bottom/rear. We only follow the mask if we are to the far right/top/front
881 // of the parent cell. Otherwise, we always create the right/top/front faces.
882 // Finally, we use the "is_cell_around_parent_cell_in_subdomain" array. If the neighboring parent cell is in
883 // our subdomain, then the faces shared with our parent cell may already exist, in which case, no duplicate.
884 if (
885 ((i == child_coord.x && !is_cell_around_parent_cell_in_subdomain(1, 1, 0)) || mask_face_if_cell_left[l]) &&
886 ((i != (child_coord.x + pattern - 1) || !is_cell_around_parent_cell_in_subdomain(1, 1, 2)) || mask_face_if_cell_right[l]) &&
887 ((j == child_coord.y && !is_cell_around_parent_cell_in_subdomain(1, 0, 1)) || mask_face_if_cell_bottom[l]) &&
888 ((j != (child_coord.y + pattern - 1) || !is_cell_around_parent_cell_in_subdomain(1, 2, 1)) || mask_face_if_cell_top[l]) &&
889 ((k == child_coord.z && !is_cell_around_parent_cell_in_subdomain(0, 1, 1)) || mask_face_if_cell_rear[l]) &&
890 ((k != (child_coord.z + pattern - 1) || !is_cell_around_parent_cell_in_subdomain(2, 1, 1)) || mask_face_if_cell_front[l])) {
891 is_new_face = true;
892 faces_infos.add(type_face);
893 faces_infos.add(child_faces_uids[l]);
894
895 // We retrieve the position of the face nodes in the "ua_node_uid" array.
896 ConstArrayView<Int32> nodes_in_face_l;
897 switch (l) {
898 case 0:
899 nodes_in_face_l = ConstArrayView<Int32>::create(nodes_in_face_0, nb_nodes_in_face);
900 break;
901 case 1:
902 nodes_in_face_l = ConstArrayView<Int32>::create(nodes_in_face_1, nb_nodes_in_face);
903 break;
904 case 2:
905 nodes_in_face_l = ConstArrayView<Int32>::create(nodes_in_face_2, nb_nodes_in_face);
906 break;
907 case 3:
908 nodes_in_face_l = ConstArrayView<Int32>::create(nodes_in_face_3, nb_nodes_in_face);
909 break;
910 case 4:
911 nodes_in_face_l = ConstArrayView<Int32>::create(nodes_in_face_4, nb_nodes_in_face);
912 break;
913 case 5:
914 nodes_in_face_l = ConstArrayView<Int32>::create(nodes_in_face_5, nb_nodes_in_face);
915 break;
916 default:
917 ARCANE_FATAL("Bizarre...");
918 }
919 for (Integer nc : nodes_in_face_l) {
920 faces_infos.add(child_nodes_uids[nc]);
921 }
922 total_nb_faces++;
923
924 // By default, parent_cell is the owner of the new face.
925 child_face_owner = owner_cells_around_parent_cell(1, 1, 1);
926 }
927
928 // Second part.
929 // We must now find the correct owner for the face. Aside from the "is_cell_around_parent_cell_same_owner" array,
930 // the condition is identical to the one above.
931 // The change of array is important because from here, we are sure that the face we are interested in exists.
932 // The new array allows us to know if the neighboring cell is also ours or not. If not, then
933 // an owner change is possible, according to the priorities defined above. We do not need to know
934 // if the cell is present in the subdomain.
935 if (
936 ((i == child_coord.x && !is_cell_around_parent_cell_same_owner(1, 1, 0)) || mask_face_if_cell_left[l]) &&
937 ((i != (child_coord.x + pattern - 1) || !is_cell_around_parent_cell_same_owner(1, 1, 2)) || mask_face_if_cell_right[l]) &&
938 ((j == child_coord.y && !is_cell_around_parent_cell_same_owner(1, 0, 1)) || mask_face_if_cell_bottom[l]) &&
939 ((j != (child_coord.y + pattern - 1) || !is_cell_around_parent_cell_same_owner(1, 2, 1)) || mask_face_if_cell_top[l]) &&
940 ((k == child_coord.z && !is_cell_around_parent_cell_same_owner(0, 1, 1)) || mask_face_if_cell_rear[l]) &&
941 ((k != (child_coord.z + pattern - 1) || !is_cell_around_parent_cell_same_owner(2, 1, 1)) || mask_face_if_cell_front[l])) {
942 // Here, the construction of the conditions is the same every time.
943 // The first boolean (i == child_coord_x) checks if the child is located
944 // on the correct side of the parent cell.
945 // The second boolean (!mask_face_if_cell_left[l]) tells us if face l is indeed
946 // the shared face with the neighboring parent cell.
947 // The third boolean (is_cell_around_parent_cell_different_owner(1, 0)) checks if there is a
948 // neighboring cell that takes ownership of the face or to whom we take ownership.
949
950 // Furthermore, there are two different cases depending on the priorities defined above:
951 // - either we are not the priority, so we assign the priority owner to our face,
952 // - or we are the priority, so we position ourselves as the owner of the face and we must notify
953 // all other processes (the former owner process as well as processes that might
954 // have the ghost face).
955
956 // Finally, in the case of owner change, only the process (re)taking ownership must
957 // make a communication about this. Processes only possessing the ghost face must not
958 // make a communication (but they can locally define the correct owner, TODO Possible Optimization?).
959
960 // To the left, priority 12 < 13 so it takes ownership of the face.
961 if (i == child_coord.x && (!mask_face_if_cell_left[l]) && is_cell_around_parent_cell_different_owner(1, 1, 0)) {
962 child_face_owner = owner_cells_around_parent_cell(1, 1, 0);
963 }
964
965 // At the bottom, priority 10 < 13 so it takes ownership of the face.
966 else if (j == child_coord.y && (!mask_face_if_cell_bottom[l]) && is_cell_around_parent_cell_different_owner(1, 0, 1)) {
967 child_face_owner = owner_cells_around_parent_cell(1, 0, 1);
968 }
969
970 // At the rear, priority 4 < 13 so it takes ownership of the face.
971 else if (k == child_coord.z && (!mask_face_if_cell_rear[l]) && is_cell_around_parent_cell_different_owner(0, 1, 1)) {
972 child_face_owner = owner_cells_around_parent_cell(0, 1, 1);
973 }
974
975 // Otherwise, parent_cell is the owner of the face.
976 else {
977
978 // Otherwise, it is an internal face, so it belongs to parent_cell.
979 child_face_owner = owner_cells_around_parent_cell(1, 1, 1);
980 }
981 }
982
983 // If there is a face creation and/or an owner change.
984 if (child_face_owner != -1) {
985 face_uid_to_owner[child_faces_uids[l]] = child_face_owner;
986
987 // When there is an owner change without face creation,
988 // we must set aside the uniqueIds of these faces to be able to
989 // iterate over them later.
990 if (!is_new_face) {
991 face_uid_change_owner_only.add(child_faces_uids[l]);
992 // debug() << "Child face (change owner) -- x : " << i
993 // << " -- y : " << j
994 // << " -- z : " << k
995 // << " -- level : " << parent_cell_level + 1
996 // << " -- face : " << l
997 // << " -- uid_face : " << child_faces_uids[l]
998 // << " -- owner : " << child_face_owner;
999 }
1000 else {
1001 // debug() << "Child face (create face) -- x : " << i
1002 // << " -- y : " << j
1003 // << " -- z : " << k
1004 // << " -- level : " << parent_cell_level + 1
1005 // << " -- face : " << l
1006 // << " -- uid_face : " << child_faces_uids[l]
1007 // << " -- owner : " << child_face_owner;
1008 }
1009 }
1010 }
1011
1012 // Node part.
1013 // This part is quite similar to the face part, except that there can be
1014 // more possible owners.
1015 for (Int32 l = 0; l < m_num_mng->nbNodeByCell(); ++l) {
1016 Int32 child_node_owner = -1;
1017 bool is_new_node = false;
1018
1019 // Two parts:
1020 // First, we check if we must create node l. To do this, we must check if it is present on the
1021 // neighboring cell.
1022 // For left/bottom/rear, the principle is the same. If the child cell is entirely to the left/bottom/rear of the parent cell, we check
1023 // if there is a parent cell to the left/bottom/rear. Otherwise, we create the node. If yes, we check the mask to know if we
1024 // must create the node.
1025 // For right/top/front, the principle is different from left/bottom/rear. We only follow the mask if the child cell is entirely to the right/top/front
1026 // of the parent cell. Otherwise, we always create the right/top/front nodes.
1027 // Finally, we use the "is_cell_around_parent_cell_in_subdomain" array. If the neighboring parent cell is in
1028 // our subdomain, then the nodes common with our parent cell may already exist; in this case,
1029 // no duplicate.
1030 if (
1031 ((i == child_coord.x && !is_cell_around_parent_cell_in_subdomain(1, 1, 0)) || mask_node_if_cell_left[l]) &&
1032 ((i != (child_coord.x + pattern - 1) || !is_cell_around_parent_cell_in_subdomain(1, 1, 2)) || mask_node_if_cell_right[l]) &&
1033 ((j == child_coord.y && !is_cell_around_parent_cell_in_subdomain(1, 0, 1)) || mask_node_if_cell_bottom[l]) &&
1034 ((j != (child_coord.y + pattern - 1) || !is_cell_around_parent_cell_in_subdomain(1, 2, 1)) || mask_node_if_cell_top[l]) &&
1035 ((k == child_coord.z && !is_cell_around_parent_cell_in_subdomain(0, 1, 1)) || mask_node_if_cell_rear[l]) &&
1036 ((k != (child_coord.z + pattern - 1) || !is_cell_around_parent_cell_in_subdomain(2, 1, 1)) || mask_node_if_cell_front[l])) {
1037 is_new_node = true;
1038 nodes_infos.add(child_nodes_uids[l]);
1039 total_nb_nodes++;
1040
1041 // By default, parent_cell is the owner of the new node.
1042 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1043 }
1044
1045 // Second part.
1046 // We must now find the correct owner for the node. Aside from the "is_cell_around_parent_cell_same_owner" array,
1047 // the condition is identical to the one above.
1048 // The change of array is important because from here, we are sure that the node we are interested in exists.
1049 // The new array allows us to know if the neighboring cell is also ours or not. If not, then
1050 // an owner change is possible, according to the priorities defined above. We do not need to know
1051 // if the cell is present in the subdomain.
1052 if (
1053 ((i == child_coord.x && !is_cell_around_parent_cell_same_owner(1, 1, 0)) || mask_node_if_cell_left[l]) &&
1054 ((i != (child_coord.x + pattern - 1) || !is_cell_around_parent_cell_same_owner(1, 1, 2)) || mask_node_if_cell_right[l]) &&
1055 ((j == child_coord.y && !is_cell_around_parent_cell_same_owner(1, 0, 1)) || mask_node_if_cell_bottom[l]) &&
1056 ((j != (child_coord.y + pattern - 1) || !is_cell_around_parent_cell_same_owner(1, 2, 1)) || mask_node_if_cell_top[l]) &&
1057 ((k == child_coord.z && !is_cell_around_parent_cell_same_owner(0, 1, 1)) || mask_node_if_cell_rear[l]) &&
1058 ((k != (child_coord.z + pattern - 1) || !is_cell_around_parent_cell_same_owner(2, 1, 1)) || mask_node_if_cell_front[l])) {
1059
1060 // Compared to faces that only have two possible owners, a node can
1061 // have up to eight.
1062
1063 // If the node is on the left face of the parent cell.
1064 if (i == child_coord.x && (!mask_node_if_cell_left[l])) {
1065
1066 // If the node is on the bottom face of the parent cell.
1067 // So the node is on the left-bottom edge.
1068 if (j == child_coord.y && (!mask_node_if_cell_bottom[l])) {
1069
1070 // If the node is on the rear face of the parent cell.
1071 // So the node is on the left, bottom, and rear (same position as the parent cell node).
1072 if (k == child_coord.z && (!mask_node_if_cell_rear[l])) {
1073
1074 // Priority 0 < 13.
1075 if (is_cell_around_parent_cell_different_owner(0, 0, 0)) {
1076 child_node_owner = owner_cells_around_parent_cell(0, 0, 0);
1077 }
1078
1079 // Priority 1 < 13.
1080 else if (is_cell_around_parent_cell_different_owner(0, 0, 1)) {
1081 child_node_owner = owner_cells_around_parent_cell(0, 0, 1);
1082 }
1083
1084 // Priority 3 < 13.
1085 else if (is_cell_around_parent_cell_different_owner(0, 1, 0)) {
1086 child_node_owner = owner_cells_around_parent_cell(0, 1, 0);
1087 }
1088
1089 // Priority 4 < 13.
1090 else if (is_cell_around_parent_cell_different_owner(0, 1, 1)) {
1091 child_node_owner = owner_cells_around_parent_cell(0, 1, 1);
1092 }
1093
1094 // Priority 9 < 13.
1095 else if (is_cell_around_parent_cell_different_owner(1, 0, 0)) {
1096 child_node_owner = owner_cells_around_parent_cell(1, 0, 0);
1097 }
1098
1099 // Priority 10 < 13.
1100 else if (is_cell_around_parent_cell_different_owner(1, 0, 1)) {
1101 child_node_owner = owner_cells_around_parent_cell(1, 0, 1);
1102 }
1103
1104 // Priority 12 < 13.
1105 else if (is_cell_around_parent_cell_different_owner(1, 1, 0)) {
1106 child_node_owner = owner_cells_around_parent_cell(1, 1, 0);
1107 }
1108
1109 // No cells around.
1110 else {
1111 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1112 }
1113 }
1114
1115 // If the node is on the front face of the parent cell.
1116 // So the node is on the left, bottom, and front (same position as the parent cell node).
1117 else if (k == (child_coord.z + pattern - 1) && (!mask_node_if_cell_front[l])) {
1118
1119 // Priority 9 < 13.
1120 if (is_cell_around_parent_cell_different_owner(1, 0, 0)) {
1121 child_node_owner = owner_cells_around_parent_cell(1, 0, 0);
1122 }
1123
1124 // Priority 10 < 13.
1125 else if (is_cell_around_parent_cell_different_owner(1, 0, 1)) {
1126 child_node_owner = owner_cells_around_parent_cell(1, 0, 1);
1127 }
1128
1129 // Priority 12 < 13.
1130 else if (is_cell_around_parent_cell_different_owner(1, 1, 0)) {
1131 child_node_owner = owner_cells_around_parent_cell(1, 1, 0);
1132 }
1133
1134 // Otherwise, parent_cell is the owner of the node.
1135 else {
1136 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1137 }
1138 }
1139
1140 // Otherwise the node is somewhere on the left-bottom edge...
1141 else {
1142
1143 // Priority 9 < 13.
1144 if (is_cell_around_parent_cell_different_owner(1, 0, 0)) {
1145 child_node_owner = owner_cells_around_parent_cell(1, 0, 0);
1146 }
1147
1148 // Priority 10 < 13.
1149 else if (is_cell_around_parent_cell_different_owner(1, 0, 1)) {
1150 child_node_owner = owner_cells_around_parent_cell(1, 0, 1);
1151 }
1152
1153 // Priority 12 < 13.
1154 else if (is_cell_around_parent_cell_different_owner(1, 1, 0)) {
1155 child_node_owner = owner_cells_around_parent_cell(1, 1, 0);
1156 }
1157
1158 // No cells around.
1159 else {
1160 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1161 }
1162 }
1163 }
1164
1165 // If the node is on the top face of the parent cell.
1166 // So the node is on the left-top edge.
1167 else if (j == (child_coord.y + pattern - 1) && (!mask_node_if_cell_top[l])) {
1168
1169 // If the node is on the rear face of the parent cell.
1170 // So the node is on the left, top, and rear (same position as the parent cell node).
1171 if (k == child_coord.z && (!mask_node_if_cell_rear[l])) {
1172
1173 // Priority 3 < 13.
1174 if (is_cell_around_parent_cell_different_owner(0, 1, 0)) {
1175 child_node_owner = owner_cells_around_parent_cell(0, 1, 0);
1176 }
1177
1178 // Priority 4 < 13.
1179 else if (is_cell_around_parent_cell_different_owner(0, 1, 1)) {
1180 child_node_owner = owner_cells_around_parent_cell(0, 1, 1);
1181 }
1182
1183 // Priority 6 < 13.
1184 else if (is_cell_around_parent_cell_different_owner(0, 2, 0)) {
1185 child_node_owner = owner_cells_around_parent_cell(0, 2, 0);
1186 }
1187
1188 // Priority 7 < 13.
1189 else if (is_cell_around_parent_cell_different_owner(0, 2, 1)) {
1190 child_node_owner = owner_cells_around_parent_cell(0, 2, 1);
1191 }
1192
1193 // Priority 12 < 13.
1194 else if (is_cell_around_parent_cell_different_owner(1, 1, 0)) {
1195 child_node_owner = owner_cells_around_parent_cell(1, 1, 0);
1196 }
1197
1198 // Otherwise, parent_cell is the owner of the node.
1199 else {
1200 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1201 }
1202 }
1203
1204 // If the node is on the front face of the parent cell.
1205 // So the node is on the left, top, and front (same position as the parent cell node).
1206 else if (k == (child_coord.z + pattern - 1) && (!mask_node_if_cell_front[l])) {
1207
1208 // Priority 4 < 13.
1209 if (is_cell_around_parent_cell_different_owner(1, 1, 0)) {
1210 child_node_owner = owner_cells_around_parent_cell(1, 1, 0);
1211 }
1212
1213 // Otherwise, parent_cell is the owner of the node.
1214 else {
1215 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1216 }
1217 }
1218
1219 // Otherwise the node is somewhere on the left-top edge...
1220 else {
1221
1222 // Priority 12 < 13.
1223 if (is_cell_around_parent_cell_different_owner(1, 1, 0)) {
1224 child_node_owner = owner_cells_around_parent_cell(1, 1, 0);
1225 }
1226
1227 // Otherwise, parent_cell is the owner of the node.
1228 else {
1229 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1230 }
1231 }
1232 }
1233
1234 // Otherwise the node is neither on the left-bottom edge nor on the left-top edge.
1235 else {
1236
1237 // If the node is somewhere on the left-rear edge.
1238 if (k == child_coord.z && (!mask_node_if_cell_rear[l])) {
1239
1240 // Priority 3 < 13.
1241 if (is_cell_around_parent_cell_different_owner(0, 1, 0)) {
1242 child_node_owner = owner_cells_around_parent_cell(0, 1, 0);
1243 }
1244
1245 // Priority 4 < 13.
1246 else if (is_cell_around_parent_cell_different_owner(0, 1, 1)) {
1247 child_node_owner = owner_cells_around_parent_cell(0, 1, 1);
1248 }
1249
1250 // Priority 12 < 13.
1251 else if (is_cell_around_parent_cell_different_owner(1, 1, 0)) {
1252 child_node_owner = owner_cells_around_parent_cell(1, 1, 0);
1253 }
1254
1255 // No cells around.
1256 else {
1257 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1258 }
1259 }
1260
1261 // If the node is somewhere on the left-front edge.
1262 else if (k == (child_coord.z + pattern - 1) && (!mask_node_if_cell_front[l])) {
1263
1264 // Priority 12 < 13.
1265 if (is_cell_around_parent_cell_different_owner(1, 1, 0)) {
1266 child_node_owner = owner_cells_around_parent_cell(1, 1, 0);
1267 }
1268
1269 // Otherwise, parent_cell is the owner of the node.
1270 else {
1271 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1272 }
1273 }
1274
1275 // Otherwise the node is somewhere on the left face...
1276 else {
1277
1278 // Priority 12 < 13.
1279 if (is_cell_around_parent_cell_different_owner(1, 1, 0)) {
1280 child_node_owner = owner_cells_around_parent_cell(1, 1, 0);
1281 }
1282
1283 // Parent_cell is the owner.
1284 else {
1285 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1286 }
1287 }
1288 }
1289 }
1290
1291 // From here, we have explored all nodes and all edges of the left parent face.
1292
1293 // If the node is on the right face of the parent cell.
1294 else if (i == (child_coord.x + pattern - 1) && (!mask_node_if_cell_right[l])) {
1295
1296 // If the node is on the bottom face of the parent cell.
1297 // So the node is on the right-bottom edge.
1298 if (j == child_coord.y && (!mask_node_if_cell_bottom[l])) {
1299
1300 // If the node is on the rear face of the parent cell.
1301 // So the node is on the right, bottom, and rear (same position as the parent cell node).
1302 if (k == child_coord.z && (!mask_node_if_cell_rear[l])) {
1303
1304 // Priority 1 < 13.
1305 if (is_cell_around_parent_cell_different_owner(0, 0, 1)) {
1306 child_node_owner = owner_cells_around_parent_cell(0, 0, 1);
1307 }
1308
1309 // Priority 2 < 13.
1310 else if (is_cell_around_parent_cell_different_owner(0, 0, 2)) {
1311 child_node_owner = owner_cells_around_parent_cell(0, 0, 2);
1312 }
1313
1314 // Priority 4 < 13.
1315 else if (is_cell_around_parent_cell_different_owner(0, 1, 1)) {
1316 child_node_owner = owner_cells_around_parent_cell(0, 1, 1);
1317 }
1318
1319 // Priority 5 < 13.
1320 else if (is_cell_around_parent_cell_different_owner(0, 1, 2)) {
1321 child_node_owner = owner_cells_around_parent_cell(0, 1, 2);
1322 }
1323
1324 // Priority 10 < 13.
1325 else if (is_cell_around_parent_cell_different_owner(1, 0, 1)) {
1326 child_node_owner = owner_cells_around_parent_cell(1, 0, 1);
1327 }
1328
1329 // Priority 11 < 13.
1330 else if (is_cell_around_parent_cell_different_owner(1, 0, 2)) {
1331 child_node_owner = owner_cells_around_parent_cell(1, 0, 2);
1332 }
1333
1334 // Otherwise, parent_cell is the owner of the node.
1335 else {
1336 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1337 }
1338 }
1339
1340 // If the node is on the front face of the parent cell.
1341 // So the node is on the right, bottom, and front (same position as the parent cell node).
1342 else if (k == (child_coord.z + pattern - 1) && (!mask_node_if_cell_front[l])) {
1343
1344 // Priority 10 < 13.
1345 if (is_cell_around_parent_cell_different_owner(1, 0, 1)) {
1346 child_node_owner = owner_cells_around_parent_cell(1, 0, 1);
1347 }
1348
1349 // Priority 11 < 13.
1350 else if (is_cell_around_parent_cell_different_owner(1, 0, 2)) {
1351 child_node_owner = owner_cells_around_parent_cell(1, 0, 2);
1352 }
1353
1354 // Otherwise, parent_cell is the owner of the node.
1355 else {
1356 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1357 }
1358 }
1359
1360 // Otherwise the node is somewhere on the right-bottom edge...
1361 else {
1362
1363 // Priority 10 < 13.
1364 if (is_cell_around_parent_cell_different_owner(1, 0, 1)) {
1365 child_node_owner = owner_cells_around_parent_cell(1, 0, 1);
1366 }
1367
1368 // Priority 11 < 13.
1369 else if (is_cell_around_parent_cell_different_owner(1, 0, 2)) {
1370 child_node_owner = owner_cells_around_parent_cell(1, 0, 2);
1371 }
1372
1373 // Otherwise, parent_cell is the owner of the node.
1374 else {
1375 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1376 }
1377 }
1378 }
1379
1380 // If the node is on the top face of the parent cell.
1381 // So node on the top right edge.
1382 else if (j == (child_coord.y + pattern - 1) && (!mask_node_if_cell_top[l])) {
1383
1384 // If the node is on the rear face of the parent cell.
1385 // So node on the right, top, rear (same position as the parent cell's node).
1386 if (k == child_coord.z && (!mask_node_if_cell_rear[l])) {
1387
1388 // Priority 4 < 13.
1389 if (is_cell_around_parent_cell_different_owner(0, 1, 1)) {
1390 child_node_owner = owner_cells_around_parent_cell(0, 1, 1);
1391 }
1392
1393 // Priority 5 < 13.
1394 else if (is_cell_around_parent_cell_different_owner(0, 1, 2)) {
1395 child_node_owner = owner_cells_around_parent_cell(0, 1, 2);
1396 }
1397
1398 // Priority 7 < 13.
1399 else if (is_cell_around_parent_cell_different_owner(0, 2, 1)) {
1400 child_node_owner = owner_cells_around_parent_cell(0, 2, 1);
1401 }
1402
1403 // Priority 8 < 13.
1404 else if (is_cell_around_parent_cell_different_owner(0, 2, 2)) {
1405 child_node_owner = owner_cells_around_parent_cell(0, 2, 2);
1406 }
1407
1408 // Otherwise, parent_cell is the owner of the node.
1409 else {
1410 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1411 }
1412 }
1413
1414 // If the node is on the front face of the parent cell.
1415 // So node on the right, top, front (same position as the parent cell's node).
1416 else if (k == (child_coord.z + pattern - 1) && (!mask_node_if_cell_front[l])) {
1417 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1418 }
1419
1420 // Otherwise the node is somewhere on the top right edge...
1421 else {
1422 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1423 }
1424 }
1425
1426 // Otherwise the node is neither on the bottom right edge nor on the top right edge.
1427 else {
1428 // If the node is somewhere on the rear right edge.
1429 if (k == child_coord.z && (!mask_node_if_cell_rear[l])) {
1430
1431 // Priority 4 < 13.
1432 if (is_cell_around_parent_cell_different_owner(0, 1, 1)) {
1433 child_node_owner = owner_cells_around_parent_cell(0, 1, 1);
1434 }
1435
1436 // Priority 5 < 13.
1437 else if (is_cell_around_parent_cell_different_owner(0, 1, 2)) {
1438 child_node_owner = owner_cells_around_parent_cell(0, 1, 2);
1439 }
1440
1441 // Otherwise, parent_cell is the owner of the node.
1442 else {
1443 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1444 }
1445 }
1446
1447 // If the node is somewhere on the front right edge.
1448 else if (k == (child_coord.z + pattern - 1) && (!mask_node_if_cell_front[l])) {
1449 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1450 }
1451
1452 // Otherwise the node is somewhere on the right face...
1453 else {
1454 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1455 }
1456 }
1457 }
1458
1459 // From here, we have explored all nodes of the parent cell and all edges
1460 // of the parent right face (and left).
1461 // So only four edges and four faces remain to be explored.
1462
1463 // Otherwise the node is neither on the left face nor on the right face.
1464 else {
1465
1466 // If the node is on the bottom face of the parent cell.
1467 if (j == child_coord.y && (!mask_node_if_cell_bottom[l])) {
1468
1469 // If the node is on the rear face of the parent cell.
1470 // So node on the bottom rear edge.
1471 if (k == child_coord.z && (!mask_node_if_cell_rear[l])) {
1472
1473 // Priority 1 < 13.
1474 if (is_cell_around_parent_cell_different_owner(0, 0, 1)) {
1475 child_node_owner = owner_cells_around_parent_cell(0, 0, 1);
1476 }
1477
1478 // Priority 4 < 13.
1479 else if (is_cell_around_parent_cell_different_owner(0, 1, 1)) {
1480 child_node_owner = owner_cells_around_parent_cell(0, 1, 1);
1481 }
1482
1483 // Priority 10 < 13.
1484 else if (is_cell_around_parent_cell_different_owner(1, 0, 1)) {
1485 child_node_owner = owner_cells_around_parent_cell(1, 0, 1);
1486 }
1487
1488 // No cells around.
1489 else {
1490 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1491 }
1492 }
1493
1494 // If the node is on the front face of the parent cell.
1495 // So node on the bottom front edge.
1496 else if (k == (child_coord.z + pattern - 1) && (!mask_node_if_cell_front[l])) {
1497
1498 // Priority 10 < 13.
1499 if (is_cell_around_parent_cell_different_owner(1, 0, 1)) {
1500 child_node_owner = owner_cells_around_parent_cell(1, 0, 1);
1501 }
1502
1503 // Otherwise, parent_cell is the owner of the node.
1504 else {
1505 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1506 }
1507 }
1508
1509 // Otherwise the node is somewhere on the bottom face...
1510 else {
1511
1512 // Priority 10 < 13.
1513 if (is_cell_around_parent_cell_different_owner(1, 0, 1)) {
1514 child_node_owner = owner_cells_around_parent_cell(1, 0, 1);
1515 }
1516
1517 // Parent_cell is the owner.
1518 else {
1519 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1520 }
1521 }
1522 }
1523
1524 // If the node is on the top face of the parent cell.
1525 else if (j == (child_coord.y + pattern - 1) && (!mask_node_if_cell_top[l])) {
1526
1527 // If the node is on the rear face of the parent cell.
1528 // So node on the top rear edge.
1529 if (k == child_coord.z && (!mask_node_if_cell_rear[l])) {
1530
1531 // Priority 4 < 13.
1532 if (is_cell_around_parent_cell_different_owner(0, 1, 1)) {
1533 child_node_owner = owner_cells_around_parent_cell(0, 1, 1);
1534 }
1535
1536 // Priority 7 < 13.
1537 else if (is_cell_around_parent_cell_different_owner(0, 2, 1)) {
1538 child_node_owner = owner_cells_around_parent_cell(0, 2, 1);
1539 }
1540
1541 // Otherwise, parent_cell is the owner of the node.
1542 else {
1543 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1544 }
1545 }
1546
1547 // If the node is on the front face of the parent cell.
1548 // So node on the top front edge.
1549 else if (k == (child_coord.z + pattern - 1) && (!mask_node_if_cell_front[l])) {
1550 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1551 }
1552
1553 // Otherwise the node is somewhere on the top face...
1554 else {
1555 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1556 }
1557 }
1558
1559 // Only two faces remain, the rear face and the front face...
1560 else {
1561
1562 // If the node is somewhere on the rear face...
1563 if (k == child_coord.z && (!mask_node_if_cell_rear[l])) {
1564
1565 // Priority 4 < 13.
1566 if (is_cell_around_parent_cell_different_owner(0, 1, 1)) {
1567 child_node_owner = owner_cells_around_parent_cell(0, 1, 1);
1568 }
1569
1570 // Parent_cell is the owner.
1571 else {
1572 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1573 }
1574 }
1575
1576 // If the node is somewhere on the front face...
1577 else if (k == (child_coord.z + pattern - 1) && (!mask_node_if_cell_front[l])) {
1578 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1579 }
1580
1581 // Otherwise, the node is inside the parent cell.
1582 else {
1583 child_node_owner = owner_cells_around_parent_cell(1, 1, 1);
1584 }
1585 }
1586 }
1587 }
1588
1589 // If there is a node creation and/or an owner change.
1590 if (child_node_owner != -1) {
1591 node_uid_to_owner[child_nodes_uids[l]] = child_node_owner;
1592
1593 // When there is an owner change without node creation,
1594 // we must set aside the uniqueIds of these nodes to be able to
1595 // iterate over them later.
1596 if (!is_new_node) {
1597 node_uid_change_owner_only.add(child_nodes_uids[l]);
1598 // debug() << "Child node (change owner) -- x : " << i
1599 // << " -- y : " << j
1600 // << " -- z : " << k
1601 // << " -- level : " << parent_cell_level + 1
1602 // << " -- node : " << l
1603 // << " -- uid_node : " << child_nodes_uids[l]
1604 // << " -- owner : " << child_node_owner;
1605 }
1606 else {
1607 // debug() << "Child node (create node) -- x : " << i
1608 // << " -- y : " << j
1609 // << " -- z : " << k
1610 // << " -- level : " << parent_cell_level + 1
1611 // << " -- node : " << l
1612 // << " -- uid_node : " << child_nodes_uids[l]
1613 // << " -- owner : " << child_node_owner;
1614 }
1615 }
1616 }
1617 }
1618 }
1619 }
1620 }
1621 }
1622 else {
1623 ARCANE_FATAL("Bad dimension");
1624 }
1625
1626 // Nodes
1627 {
1628 debug() << "Nb new nodes in patch : " << total_nb_nodes;
1629 {
1630 const Integer nb_node_owner_change = node_uid_change_owner_only.size();
1631
1632 // This array will contain the localIds of the new nodes but also the localIds
1633 // of the nodes that are just changing owners.
1634 UniqueArray<Int32> nodes_lid(total_nb_nodes + nb_node_owner_change);
1635
1636 // We create the nodes. We put the localIds of the new nodes at the beginning of the array.
1637 m_mesh->modifier()->addNodes(nodes_infos, nodes_lid.subView(0, total_nb_nodes));
1638
1639 // We look for the localIds of the nodes that change owners and put them at the end of the array.
1640 m_mesh->nodeFamily()->itemsUniqueIdToLocalId(nodes_lid.subView(total_nb_nodes, nb_node_owner_change), node_uid_change_owner_only, true);
1641
1642 UniqueArray<Int64> uid_child_nodes(total_nb_nodes + nb_node_owner_change);
1643 UniqueArray<Int32> lid_child_nodes(total_nb_nodes + nb_node_owner_change);
1644 Integer index = 0;
1645
1646 // We assign the correct owners to the nodes.
1647 ENUMERATE_ (Node, inode, m_mesh->nodeFamily()->view(nodes_lid)) {
1648 Node node = *inode;
1649 node.mutableItemBase().setOwner(node_uid_to_owner[node.uniqueId()], my_rank);
1650
1651 if (node_uid_to_owner[node.uniqueId()] == my_rank) {
1653 }
1654 // TODO: Fix this in the directly concerned part.
1655 else {
1657 }
1658 // Note, node.level() == -1 here.
1659 uid_child_nodes[index++] = m_num_mng->parentNodeUniqueIdOfNode(node.uniqueId(), max_level + 1, false);
1660 }
1661
1662 m_mesh->nodeFamily()->itemsUniqueIdToLocalId(lid_child_nodes, uid_child_nodes, false);
1663 NodeInfoListView nodes(m_mesh->nodeFamily());
1664
1665 index = 0;
1666 ENUMERATE_ (Node, inode, m_mesh->nodeFamily()->view(nodes_lid)) {
1667 const Int32 child_lid = lid_child_nodes[index++];
1668 if (child_lid == NULL_ITEM_ID) {
1669 continue;
1670 }
1671
1672 Node parent = nodes[child_lid];
1673 Node child = *inode;
1674
1675 m_mesh->modifier()->addParentNodeToNode(child, parent);
1676 m_mesh->modifier()->addChildNodeToNode(parent, child);
1677 }
1678 }
1679 m_mesh->nodeFamily()->notifyItemsOwnerChanged();
1680 }
1681
1682 // Faces
1683 {
1684 debug() << "Nb new faces in patch : " << total_nb_faces;
1685 {
1686 const Integer nb_face_owner_change = face_uid_change_owner_only.size();
1687
1688 // This array will contain the localIds of the new faces but also the localIds
1689 // of the faces that are just changing owners.
1690 UniqueArray<Int32> faces_lid(total_nb_faces + nb_face_owner_change);
1691
1692 // We create the faces. We put the localIds of the new faces at the beginning of the array.
1693 m_mesh->modifier()->addFaces(total_nb_faces, faces_infos, faces_lid.subView(0, total_nb_faces));
1694
1695 // We look for the localIds of the faces that change owners and put them at the end of the array.
1696 m_mesh->faceFamily()->itemsUniqueIdToLocalId(faces_lid.subView(total_nb_faces, nb_face_owner_change), face_uid_change_owner_only, true);
1697
1698 UniqueArray<Int64> uid_parent_faces(total_nb_faces + nb_face_owner_change);
1699 UniqueArray<Int32> lid_parent_faces(total_nb_faces + nb_face_owner_change);
1700 Integer index = 0;
1701
1702 // We assign the correct owners to the faces.
1703 ENUMERATE_ (Face, iface, m_mesh->faceFamily()->view(faces_lid)) {
1704 Face face = *iface;
1705 face.mutableItemBase().setOwner(face_uid_to_owner[face.uniqueId()], my_rank);
1706
1707 if (face_uid_to_owner[face.uniqueId()] == my_rank) {
1709 }
1710 // TODO: Fix this in the directly concerned part.
1711 else {
1713 }
1714 // Note, face.level() == -1 here.
1715 uid_parent_faces[index++] = m_num_mng->parentFaceUniqueIdOfFace(face.uniqueId(), max_level + 1, false);
1716 // debug() << "Parent of : " << face.uniqueId() << " is : " << uid_child_faces[index - 1];
1717 }
1718
1719 m_mesh->faceFamily()->itemsUniqueIdToLocalId(lid_parent_faces, uid_parent_faces, false);
1720 FaceInfoListView faces(m_mesh->faceFamily());
1721
1722 index = 0;
1723 ENUMERATE_ (Face, iface, m_mesh->faceFamily()->view(faces_lid)) {
1724 const Int32 child_lid = lid_parent_faces[index++];
1725 if (child_lid == NULL_ITEM_ID) {
1726 continue;
1727 }
1728
1729 Face parent = faces[child_lid];
1730 Face child = *iface;
1731
1732 m_mesh->modifier()->addParentFaceToFace(child, parent);
1733 m_mesh->modifier()->addChildFaceToFace(parent, child);
1734 }
1735 }
1736 m_mesh->faceFamily()->notifyItemsOwnerChanged();
1737 }
1738
1739 // Cells
1740 {
1741 debug() << "Nb new cells in patch : " << total_nb_cells;
1742
1743 UniqueArray<Int32> cells_lid(total_nb_cells);
1744 m_mesh->modifier()->addCells(total_nb_cells, cells_infos, cells_lid);
1745
1746 // Iteration over the new cells.
1747 CellInfoListView cells(m_mesh->cellFamily());
1748 for (Integer i = 0; i < total_nb_cells; ++i) {
1749 Cell child = cells[cells_lid[i]];
1750 Cell parent = cells[parent_cells[i]];
1751
1752 child.mutableItemBase().setOwner(parent.owner(), my_rank);
1753
1755
1756 if (parent.owner() == my_rank) {
1758 }
1759
1760 if (parent.itemBase().flags() & ItemFlags::II_Shared) {
1762 }
1763
1764 m_mesh->modifier()->addParentCellToCell(child, parent);
1765 m_mesh->modifier()->addChildCellToCell(parent, child);
1766 }
1767
1768 // Iteration over the parent cells.
1769 for (Cell cell : cell_to_refine_internals) {
1770 cell.mutableItemBase().removeFlags(ItemFlags::II_Refine);
1771 cell.mutableItemBase().addFlags(ItemFlags::II_JustRefined | ItemFlags::II_Inactive);
1772 }
1773 m_mesh->cellFamily()->notifyItemsOwnerChanged();
1774 }
1775
1776 m_mesh->modifier()->endUpdate();
1777
1778 // We position the nodes in space.
1779 for (Cell parent_cell : cell_to_refine_internals) {
1780 m_num_mng->setChildNodeCoordinates(parent_cell);
1781 // We add the "II_Shared" flag to the nodes and faces of shared cells.
1782 if (parent_cell.mutableItemBase().flags() & ItemFlags::II_Shared) {
1783 for (Int32 i = 0; i < parent_cell.nbHChildren(); ++i) {
1784 Cell child_cell = parent_cell.hChild(i);
1785 for (Node node : child_cell.nodes()) {
1786 if (node.mutableItemBase().flags() & ItemFlags::II_Own) {
1787 node.mutableItemBase().addFlags(ItemFlags::II_Shared);
1788 }
1789 }
1790
1791 for (Face face : child_cell.faces()) {
1792 if (face.mutableItemBase().flags() & ItemFlags::II_Own) {
1793 face.mutableItemBase().addFlags(ItemFlags::II_Shared);
1794 }
1795 }
1796 }
1797 }
1798 }
1799
1800 // Recalculate synchronization information.
1801 m_mesh->computeSynchronizeInfos();
1802
1803 // ENUMERATE_(Cell, icell, m_mesh->allCells()){
1804 // debug() << "\t" << *icell;
1805 // for(Node node : icell->nodes()){
1806 // debug() << "\t\t" << node;
1807 // }
1808 // for(Face face : icell->faces()){
1809 // debug() << "\t\t\t" << face;
1810 // }
1811 // }
1812 // info() << "Summary:";
1813 // ENUMERATE_ (Cell, icell, m_mesh->allCells()) {
1814 // debug() << "\tCell uniqueId : " << icell->uniqueId() << " -- level : " << icell->level() << " -- nbChildren : " << icell->nbHChildren();
1815 // for (Integer i = 0; i < icell->nbHChildren(); ++i) {
1816 // debug() << "\t\tChild uniqueId : " << icell->hChild(i).uniqueId() << " -- level : " << icell->hChild(i).level() << " -- nbChildren : " << icell->hChild(i).nbHChildren();
1817 // }
1818 // }
1819 // info() << "Node summary:";
1820 // ENUMERATE_ (Node, inode, m_mesh->allNodes()) {
1821 // debug() << "\tNode uniqueId : " << inode->uniqueId() << " -- level : " << inode->level() << " -- nbChildren : " << inode->nbHChildren();
1822 // for (Integer i = 0; i < inode->nbHChildren(); ++i) {
1823 // debug() << "\t\tNode Child uniqueId : " << inode->hChild(i).uniqueId() << " -- level : " << inode->hChild(i).level() << " -- nbChildren : " << inode->hChild(i).nbHChildren();
1824 // }
1825 // }
1826 //
1827 // info() << "Résumé :";
1828 // ENUMERATE_ (Face, iface, m_mesh->allFaces()) {
1829 // debug() << "\tFace uniqueId : " << iface->uniqueId() << " -- level : " << iface->level() << " -- nbChildren : " << iface->nbHChildren();
1830 // for (Integer i = 0; i < iface->nbHChildren(); ++i) {
1831 // debug() << "\t\tChild uniqueId : " << iface->hChild(i).uniqueId() << " -- level : " << iface->hChild(i).level() << " -- nbChildren : " << iface->hChild(i).nbHChildren();
1832 // }
1833 // }
1834}
1835
1836/*---------------------------------------------------------------------------*/
1837/*---------------------------------------------------------------------------*/
1838
1839void CartesianMeshAMRPatchMng::
1840createSubLevel()
1841{
1842 IParallelMng* pm = m_mesh->parallelMng();
1843 Int32 nb_rank = pm->commSize();
1844 Int32 my_rank = pm->commRank();
1845
1846 UniqueArray<Int64> cell_uid_to_create;
1847
1848 // TODO: Replace around_parent_cells_uid_to_owner with parent_to_child_cells?
1849 std::unordered_map<Int64, Int32> around_parent_cells_uid_to_owner;
1850 std::unordered_map<Int64, bool> around_parent_cells_uid_is_in_subdomain;
1851 std::unordered_map<Int64, UniqueArray<Cell>> parent_to_child_cells;
1852
1853 std::unordered_map<Int64, Int32> node_uid_to_owner;
1854 std::unordered_map<Int64, Int32> face_uid_to_owner;
1855
1856 // We are going to create level -1.
1857 // Note that at the end of the method, we will replace this level
1858 // at 0.
1859 m_num_mng->prepareLevel(-1);
1860
1861 // We create one or more layers of ghost cells
1862 // to prevent a parent cell from not having the same
1863 // number of child cells.
1864 // ----------
1865 // CartesianMeshCoarsening2::_doDoubleGhostLayers()
1866 IMeshModifier* mesh_modifier = m_mesh->modifier();
1867 IGhostLayerMng* gm = m_mesh->ghostLayerMng();
1868 // We must use version 3 at least to support
1869 // multiple layers of ghost cells
1870 Int32 version = gm->builderVersion();
1871 if (version < 3)
1872 gm->setBuilderVersion(3);
1873 Int32 nb_ghost_layer = gm->nbGhostLayer();
1874 // TODO AH: This line would allow for fewer ghost cells and
1875 // prevent their deletion if unnecessary. But the behavior
1876 // would be different from the historical AMR.
1877 //gm->setNbGhostLayer(nb_ghost_layer + (nb_ghost_layer % m_num_mng->pattern()));
1878 // Historical AMR behavior.
1879 gm->setNbGhostLayer(nb_ghost_layer * 2);
1880 mesh_modifier->setDynamic(true);
1881 mesh_modifier->updateGhostLayers();
1882 // Restore the initial number of ghost layers
1883 gm->setNbGhostLayer(nb_ghost_layer);
1884 // CartesianMeshCoarsening2::_doDoubleGhostLayers()
1885 // ----------
1886
1887 // We retrieve the unique IDs of the parents to be created.
1888 ENUMERATE_ (Cell, icell, m_mesh->allLevelCells(0)) {
1889 Cell cell = *icell;
1890
1891 Int64 parent_uid = m_num_mng->parentCellUniqueIdOfCell(cell);
1892
1893 // We avoid duplicates.
1894 if (!cell_uid_to_create.contains(parent_uid)) {
1895 cell_uid_to_create.add(parent_uid);
1896 // We take the opportunity to save the owners of the future cells
1897 // which will be the same owners as the child cells.
1898 around_parent_cells_uid_to_owner[parent_uid] = cell.owner();
1899 around_parent_cells_uid_is_in_subdomain[parent_uid] = true;
1900 }
1901 else {
1902 // This can happen if the partitioning is not suitable.
1903 if (around_parent_cells_uid_to_owner[parent_uid] != cell.owner()) {
1904 ARCANE_FATAL("Pb owner -- Two+ children, two+ different owners, same parent\n"
1905 "The ground patch size in x, y (and z if 3D) must be a multiple of four (need partitionner update to support multiple of two)\n"
1906 "CellUID : {0} -- CellOwner : {1} -- OtherChildOwner : {2}",
1907 cell.uniqueId(), cell.owner(), around_parent_cells_uid_to_owner[parent_uid]);
1908 }
1909 }
1910
1911 // We must save the children of the parents to create the connectivities
1912 // at the end.
1913 parent_to_child_cells[parent_uid].add(cell);
1914 }
1915
1916 // info() << cell_uid_to_create;
1917 // for (const auto& [key, value] : parent_to_child_cells) {
1918 // info() << "Parent : " << key << " -- Children : " << value;
1919 // }
1920
1921 UniqueArray<Int64> cells_infos;
1922 UniqueArray<Int64> faces_infos;
1923 UniqueArray<Int64> nodes_infos;
1924
1925 Integer total_nb_cells = 0;
1926 Integer total_nb_nodes = 0;
1927 Integer total_nb_faces = 0;
1928
1929 // Two arrays allowing retrieval of the unique IDs of nodes and faces
1930 // for each parent cell upon every call to getNodeUids()/getFaceUids().
1931 UniqueArray<Int64> parent_nodes_uids(m_num_mng->nbNodeByCell());
1932 UniqueArray<Int64> parent_faces_uids(m_num_mng->nbFaceByCell());
1933
1934 // Part exchanging information about cells around the patch
1935 // (to replace ghost cells).
1936 {
1937 // Array that will contain the uids of the cells whose information we need.
1938 UniqueArray<Int64> uid_of_cells_needed;
1939 {
1940 UniqueArray<Int64> cell_uids_around((m_mesh->dimension() == 2) ? 9 : 27);
1941 for (Int64 parent_cell : cell_uid_to_create) {
1942 m_num_mng->cellUniqueIdsAroundCell(parent_cell, -1, cell_uids_around);
1943 for (Int64 cell_uid : cell_uids_around) {
1944 // If -1 then there are no cells at this position.
1945 if (cell_uid == -1)
1946 continue;
1947
1948 // IF we have the cell, we do not need to request information.
1949 if (around_parent_cells_uid_to_owner.contains(cell_uid))
1950 continue;
1951
1952 // TODO: Meh
1953 if (!uid_of_cells_needed.contains(cell_uid)) {
1954 uid_of_cells_needed.add(cell_uid);
1955
1956 // If we need the information, it means we don't possess it :-)
1957 // We take the opportunity to record this information to distinguish between
1958 // ghost cells for which we possess the items (faces/nodes) and those for which
1959 // we possess nothing.
1960 around_parent_cells_uid_is_in_subdomain[cell_uid] = false;
1961 }
1962 }
1963 }
1964 }
1965
1966 // We share the necessary cell uids from everyone.
1967 UniqueArray<Int64> uid_of_cells_needed_all_procs;
1968 pm->allGatherVariable(uid_of_cells_needed, uid_of_cells_needed_all_procs);
1969
1970 UniqueArray<Int32> owner_of_cells_needed_all_procs(uid_of_cells_needed_all_procs.size());
1971
1972 {
1973 // We record the owner of the cells that we possess.
1974 for (Integer i = 0; i < uid_of_cells_needed_all_procs.size(); ++i) {
1975 if (around_parent_cells_uid_to_owner.contains(uid_of_cells_needed_all_procs[i])) {
1976 owner_of_cells_needed_all_procs[i] = around_parent_cells_uid_to_owner[uid_of_cells_needed_all_procs[i]];
1977 }
1978 else {
1979 // ReduceMax will eliminate this -1.
1980 owner_of_cells_needed_all_procs[i] = -1;
1981 }
1982 }
1983 }
1984
1985 // We retrieve the owners of all necessary cells.
1986 pm->reduce(Parallel::eReduceType::ReduceMax, owner_of_cells_needed_all_procs);
1987
1988 // We only process the owners of the necessary cells for us.
1989 {
1990 Integer size_uid_of_cells_needed = uid_of_cells_needed.size();
1991 Integer my_pos_in_all_procs_arrays = 0;
1992 UniqueArray<Integer> size_uid_of_cells_needed_per_proc(nb_rank);
1993 ArrayView<Integer> av(1, &size_uid_of_cells_needed);
1994 pm->allGather(av, size_uid_of_cells_needed_per_proc);
1995
1996 // We skip the cells from all procs before us.
1997 for (Integer i = 0; i < my_rank; ++i) {
1998 my_pos_in_all_procs_arrays += size_uid_of_cells_needed_per_proc[i];
1999 }
2000
2001 // We record the necessary owners.
2002 ArrayView<Int32> owner_of_cells_needed = owner_of_cells_needed_all_procs.subView(my_pos_in_all_procs_arrays, size_uid_of_cells_needed);
2003 for (Integer i = 0; i < size_uid_of_cells_needed; ++i) {
2004 around_parent_cells_uid_to_owner[uid_of_cells_needed[i]] = owner_of_cells_needed[i];
2005
2006 // In refinement, there can be multiple levels of differences between patches.
2007 // In coarsening, this is impossible since level 0 has no "holes."
2008 if (owner_of_cells_needed[i] == -1) {
2009 ARCANE_FATAL("In coarsening, this is normally impossible");
2010 }
2011 }
2012 }
2013 }
2014
2015 if (m_mesh->dimension() == 2) {
2016
2017 // Masks allowing us to know if we should create a face/node (true)
2018 // or if we should look at the adjacent cell first (false).
2019 // Reminder that Arcane's face traversal is in the NumPad order {2, 6, 8, 4}.
2020 constexpr bool mask_face_if_cell_left[] = { true, true, true, false };
2021 constexpr bool mask_face_if_cell_bottom[] = { false, true, true, true };
2022
2023 // Reminder that Arcane's node traversal is in the NumPad order {1, 3, 9, 7}.
2024 constexpr bool mask_node_if_cell_left[] = { false, true, true, false };
2025 constexpr bool mask_node_if_cell_bottom[] = { false, false, true, true };
2026
2027 FixedArray<Int64, 9> cells_uid_around;
2028 FixedArray<Int32, 9> owner_cells_around_parent_cell_1d;
2029 FixedArray<bool, 9> is_not_in_subdomain_cells_around_parent_cell_1d;
2030
2031 // For refinement, we would traverse the existing parent cells.
2032 // Here, the parent cells do not exist yet, so we traverse the uids.
2033 for (Int64 parent_cell_uid : cell_uid_to_create) {
2034
2035 m_num_mng->cellUniqueIdsAroundCell(parent_cell_uid, -1, cells_uid_around.view());
2036
2037 ConstArray2View owner_cells_around_parent_cell(owner_cells_around_parent_cell_1d.data(), 3, 3);
2038 // Be careful with the "not" in the variable name.
2039 ConstArray2View is_not_in_subdomain_cells_around_parent_cell(is_not_in_subdomain_cells_around_parent_cell_1d.data(), 3, 3);
2040
2041 for (Integer i = 0; i < 9; ++i) {
2042 Int64 uid_cell = cells_uid_around[i];
2043 // If uid_cell != -1 then there might be a cell (but we don't know if it is actually present).
2044 // If around_parent_cells_uid_to_owner[uid_cell] != -1 then there is indeed a cell.
2045 if (uid_cell != -1 && around_parent_cells_uid_to_owner[uid_cell] != -1) {
2046 owner_cells_around_parent_cell_1d[i] = around_parent_cells_uid_to_owner[uid_cell];
2047 is_not_in_subdomain_cells_around_parent_cell_1d[i] = !around_parent_cells_uid_is_in_subdomain[uid_cell];
2048 }
2049 else {
2050 cells_uid_around[i] = -1;
2051 owner_cells_around_parent_cell_1d[i] = -1;
2052 is_not_in_subdomain_cells_around_parent_cell_1d[i] = true;
2053 }
2054 }
2055
2056 // These two lambdas are different.
2057 // When a parent_cell does not exist, there is -1 in the appropriate array,
2058 // so the first lambda will necessarily return true while the second returns false.
2059 auto is_cell_around_parent_cell_different_owner = [&](const Integer y, const Integer x) {
2060 return (owner_cells_around_parent_cell(y, x) != owner_cells_around_parent_cell(1, 1));
2061 };
2062
2063 auto is_cell_around_parent_cell_exist_and_different_owner = [&](const Integer y, const Integer x) {
2064 return (owner_cells_around_parent_cell(y, x) != -1 && (owner_cells_around_parent_cell(y, x) != owner_cells_around_parent_cell(1, 1)));
2065 };
2066
2067 total_nb_cells++;
2068 // debug() << "Parent"
2069 // << " -- x : " << m_num_mng->cellUniqueIdToCoordX(parent_cell_uid, -1)
2070 // << " -- y : " << m_num_mng->cellUniqueIdToCoordY(parent_cell_uid, -1)
2071 // << " -- level : " << -1
2072 // << " -- uid : " << parent_cell_uid;
2073
2074 // We retrieve the unique IDs of the nodes and faces to be created.
2075 m_num_mng->cellNodeUniqueIds(parent_cell_uid, -1, parent_nodes_uids);
2076 m_num_mng->cellFaceUniqueIds(parent_cell_uid, -1, parent_faces_uids);
2077
2078 constexpr Integer type_cell = IT_Quad4;
2079 constexpr Integer type_face = IT_Line2;
2080
2081 // Cell Part.
2082 cells_infos.add(type_cell);
2083 cells_infos.add(parent_cell_uid);
2084 for (Integer nc = 0; nc < m_num_mng->nbNodeByCell(); nc++) {
2085 cells_infos.add(parent_nodes_uids[nc]);
2086 }
2087
2088 // Face Part.
2089 for (Integer l = 0; l < m_num_mng->nbFaceByCell(); ++l) {
2090 // We check if we should process the face.
2091 // If mask_face_if_cell_left[l] == false, we must check if the cell to the left is ours or not
2092 // or if the cell to the left is in our subdomain or not.
2093 // If this cell is not ours and/or is not in our subdomain,
2094 // we must create the face as a ghost face.
2095 if (
2096 (mask_face_if_cell_left[l] || is_cell_around_parent_cell_different_owner(1, 0) || is_not_in_subdomain_cells_around_parent_cell(1, 0)) &&
2097 (mask_face_if_cell_bottom[l] || is_cell_around_parent_cell_different_owner(0, 1) || is_not_in_subdomain_cells_around_parent_cell(0, 1))) {
2098 Integer parent_face_owner = -1;
2099 faces_infos.add(type_face);
2100 faces_infos.add(parent_faces_uids[l]);
2101
2102 // The face nodes are always nodes l and l+1
2103 // because we use the same traversal for both cases.
2104 for (Integer nc = l; nc < l + 2; nc++) {
2105 faces_infos.add(parent_nodes_uids[nc % m_num_mng->nbNodeByCell()]);
2106 }
2107 total_nb_faces++;
2108
2109 if ((!mask_face_if_cell_left[l]) && is_cell_around_parent_cell_exist_and_different_owner(1, 0)) {
2110 parent_face_owner = owner_cells_around_parent_cell(1, 0);
2111 }
2112 else if ((!mask_face_if_cell_bottom[l]) && is_cell_around_parent_cell_exist_and_different_owner(0, 1)) {
2113 parent_face_owner = owner_cells_around_parent_cell(0, 1);
2114 }
2115 else {
2116 parent_face_owner = owner_cells_around_parent_cell(1, 1);
2117 }
2118 face_uid_to_owner[parent_faces_uids[l]] = parent_face_owner;
2119 // debug() << "Parent face (create face) -- parent_cell_uid : " << parent_cell_uid
2120 // << " -- level : " << -1
2121 // << " -- face : " << l
2122 // << " -- uid_face : " << parent_faces_uids[l]
2123 // << " -- owner : " << parent_face_owner;
2124 }
2125 }
2126
2127 // Node Part.
2128 // This part is quite similar to the face part, apart from the fact that there can be
2129 // more possible owners.
2130 for (Integer l = 0; l < m_num_mng->nbNodeByCell(); ++l) {
2131 if (
2132 (mask_node_if_cell_left[l] || is_cell_around_parent_cell_different_owner(1, 0) || is_not_in_subdomain_cells_around_parent_cell(1, 0)) &&
2133 (mask_node_if_cell_bottom[l] || is_cell_around_parent_cell_different_owner(0, 1) || is_not_in_subdomain_cells_around_parent_cell(0, 1))) {
2134 Integer parent_node_owner = -1;
2135 nodes_infos.add(parent_nodes_uids[l]);
2136 total_nb_nodes++;
2137
2138 if ((!mask_node_if_cell_left[l])) {
2139 if ((!mask_node_if_cell_bottom[l])) {
2140 if (is_cell_around_parent_cell_exist_and_different_owner(0, 0)) {
2141 parent_node_owner = owner_cells_around_parent_cell(0, 0);
2142 }
2143 else if (is_cell_around_parent_cell_exist_and_different_owner(0, 1)) {
2144 parent_node_owner = owner_cells_around_parent_cell(0, 1);
2145 }
2146 else if (is_cell_around_parent_cell_exist_and_different_owner(1, 0)) {
2147 parent_node_owner = owner_cells_around_parent_cell(1, 0);
2148 }
2149 else {
2150 parent_node_owner = owner_cells_around_parent_cell(1, 1);
2151 }
2152 }
2153 else {
2154 if (is_cell_around_parent_cell_exist_and_different_owner(1, 0)) {
2155 parent_node_owner = owner_cells_around_parent_cell(1, 0);
2156 }
2157 else {
2158 parent_node_owner = owner_cells_around_parent_cell(1, 1);
2159 }
2160 }
2161 }
2162 else {
2163 if ((!mask_node_if_cell_bottom[l])) {
2164 if (is_cell_around_parent_cell_exist_and_different_owner(0, 1)) {
2165 parent_node_owner = owner_cells_around_parent_cell(0, 1);
2166 }
2167 else if (is_cell_around_parent_cell_exist_and_different_owner(0, 2)) {
2168 parent_node_owner = owner_cells_around_parent_cell(0, 2);
2169 }
2170 else {
2171 parent_node_owner = owner_cells_around_parent_cell(1, 1);
2172 }
2173 }
2174 else {
2175 parent_node_owner = owner_cells_around_parent_cell(1, 1);
2176 }
2177 }
2178
2179 node_uid_to_owner[parent_nodes_uids[l]] = parent_node_owner;
2180 // debug() << "Parent node (create node) -- parent_cell_uid : " << parent_cell_uid
2181 // << " -- level : " << -1
2182 // << " -- node : " << l
2183 // << " -- uid_node : " << parent_nodes_uids[l]
2184 // << " -- owner : " << parent_node_owner;
2185 }
2186 }
2187 }
2188 }
2189 else if (m_mesh->dimension() == 3) {
2190
2191 // Masks allowing us to know if we should create a face/node (true)
2192 // or if we should look at the adjacent cell first (false).
2193 constexpr bool mask_node_if_cell_left[] = { false, true, true, false, false, true, true, false };
2194 constexpr bool mask_node_if_cell_bottom[] = { false, false, true, true, false, false, true, true };
2195 constexpr bool mask_node_if_cell_rear[] = { false, false, false, false, true, true, true, true };
2196
2197 constexpr bool mask_face_if_cell_left[] = { true, false, true, true, true, true };
2198 constexpr bool mask_face_if_cell_bottom[] = { true, true, false, true, true, true };
2199 constexpr bool mask_face_if_cell_rear[] = { false, true, true, true, true, true };
2200
2201 // Small difference compared to 2D. For 2D, the position of the face nodes
2202 // in the "parent_nodes_uids" array is always the same (l and l+1, see 2D).
2203 // For 3D, this is not the case, so we have arrays to have a correspondence
2204 // between the nodes of each face and the position of the nodes in the "parent_nodes_uids" array.
2205 // (Example: for face 1 (same enumeration order as Arcane), we must take the
2206 // "nodes_in_face_1" array and thus the nodes "parent_nodes_uids[0]", "parent_nodes_uids[3]",
2207 // "parent_nodes_uids[7]" and "parent_nodes_uids[4]").
2208 constexpr Integer nodes_in_face_0[] = { 0, 1, 2, 3 };
2209 constexpr Integer nodes_in_face_1[] = { 0, 3, 7, 4 };
2210 constexpr Integer nodes_in_face_2[] = { 0, 1, 5, 4 };
2211 constexpr Integer nodes_in_face_3[] = { 4, 5, 6, 7 };
2212 constexpr Integer nodes_in_face_4[] = { 1, 2, 6, 5 };
2213 constexpr Integer nodes_in_face_5[] = { 3, 2, 6, 7 };
2214
2215 constexpr Integer nb_nodes_in_face = 4;
2216 FixedArray<Int64, 27> cells_uid_around;
2217 FixedArray<Int32, 27> owner_cells_around_parent_cell_1d;
2218 FixedArray<bool, 27> is_not_in_subdomain_cells_around_parent_cell_1d;
2219
2220 // For refinement, we would traverse the existing parent cells.
2221 // Here, the parent cells do not exist yet, so we traverse the uids.
2222 for (Int64 parent_cell_uid : cell_uid_to_create) {
2223
2224 m_num_mng->cellUniqueIdsAroundCell(parent_cell_uid, -1, cells_uid_around.view());
2225
2226 ConstArray3View owner_cells_around_parent_cell(owner_cells_around_parent_cell_1d.data(), 3, 3, 3);
2227 // Be careful with the "not" in the variable name.
2228 ConstArray3View is_not_in_subdomain_cells_around_parent_cell(is_not_in_subdomain_cells_around_parent_cell_1d.data(), 3, 3, 3);
2229
2230 for (Integer i = 0; i < 27; ++i) {
2231 Int64 uid_cell = cells_uid_around[i];
2232 // If uid_cell != -1 then there might be a cell (but we don't know if it is actually present).
2233 // If around_parent_cells_uid_to_owner[uid_cell] != -1 then there is indeed a cell.
2234 if (uid_cell != -1 && around_parent_cells_uid_to_owner[uid_cell] != -1) {
2235 owner_cells_around_parent_cell_1d[i] = around_parent_cells_uid_to_owner[uid_cell];
2236 is_not_in_subdomain_cells_around_parent_cell_1d[i] = !around_parent_cells_uid_is_in_subdomain[uid_cell];
2237 }
2238 else {
2239 cells_uid_around[i] = -1;
2240 owner_cells_around_parent_cell_1d[i] = -1;
2241 is_not_in_subdomain_cells_around_parent_cell_1d[i] = true;
2242 }
2243 }
2244
2245 // These two lambdas are different.
2246 // When a parent_cell does not exist, there is -1 in the appropriate array,
2247 // so the first lambda will necessarily return true while the second returns false.
2248 auto is_cell_around_parent_cell_different_owner = [&](const Integer z, const Integer y, const Integer x) {
2249 return (owner_cells_around_parent_cell(z, y, x) != owner_cells_around_parent_cell(1, 1, 1));
2250 };
2251
2252 auto is_cell_around_parent_cell_exist_and_different_owner = [&](const Integer z, const Integer y, const Integer x) {
2253 return (owner_cells_around_parent_cell(z, y, x) != -1 && (owner_cells_around_parent_cell(z, y, x) != owner_cells_around_parent_cell(1, 1, 1)));
2254 };
2255
2256 total_nb_cells++;
2257 // debug() << "Parent"
2258 // << " -- x : " << m_num_mng->cellUniqueIdToCoordX(parent_cell_uid, -1)
2259 // << " -- y : " << m_num_mng->cellUniqueIdToCoordY(parent_cell_uid, -1)
2260 // << " -- z : " << m_num_mng->cellUniqueIdToCoordZ(parent_cell_uid, -1)
2261 // << " -- level : " << -1
2262 // << " -- uid : " << parent_cell_uid;
2263
2264 // We retrieve the unique IDs of the nodes and faces to be created.
2265 m_num_mng->cellNodeUniqueIds(parent_cell_uid, -1, parent_nodes_uids);
2266 m_num_mng->cellFaceUniqueIds(parent_cell_uid, -1, parent_faces_uids);
2267
2268 constexpr Integer type_cell = IT_Hexaedron8;
2269 constexpr Integer type_face = IT_Quad4;
2270
2271 // Cell Part.
2272 cells_infos.add(type_cell);
2273 cells_infos.add(parent_cell_uid);
2274 for (Integer nc = 0; nc < m_num_mng->nbNodeByCell(); nc++) {
2275 cells_infos.add(parent_nodes_uids[nc]);
2276 }
2277
2278 // Face Part.
2279 for (Integer l = 0; l < m_num_mng->nbFaceByCell(); ++l) {
2280 // We check if we should process the face.
2281 // If mask_face_if_cell_left[l] == false, we must check if the cell on the left belongs to us or not
2282 // or if the cell on the left is in our subdomain or not.
2283 // If this cell is not ours and/or is not in our subdomain,
2284 // we must create the face as a ghost face.
2285 if (
2286 (mask_face_if_cell_left[l] || is_cell_around_parent_cell_different_owner(1, 1, 0) || is_not_in_subdomain_cells_around_parent_cell(1, 1, 0)) &&
2287 (mask_face_if_cell_bottom[l] || is_cell_around_parent_cell_different_owner(1, 0, 1) || is_not_in_subdomain_cells_around_parent_cell(1, 0, 1)) &&
2288 (mask_face_if_cell_rear[l] || is_cell_around_parent_cell_different_owner(0, 1, 1) || is_not_in_subdomain_cells_around_parent_cell(0, 1, 1))) {
2289 Integer parent_face_owner = -1;
2290 faces_infos.add(type_face);
2291 faces_infos.add(parent_faces_uids[l]);
2292
2293 // We retrieve the position of the face nodes in the "ua_node_uid" array.
2294 ConstArrayView<Integer> nodes_in_face_l;
2295 switch (l) {
2296 case 0:
2297 nodes_in_face_l = ConstArrayView<Integer>::create(nodes_in_face_0, nb_nodes_in_face);
2298 break;
2299 case 1:
2300 nodes_in_face_l = ConstArrayView<Integer>::create(nodes_in_face_1, nb_nodes_in_face);
2301 break;
2302 case 2:
2303 nodes_in_face_l = ConstArrayView<Integer>::create(nodes_in_face_2, nb_nodes_in_face);
2304 break;
2305 case 3:
2306 nodes_in_face_l = ConstArrayView<Integer>::create(nodes_in_face_3, nb_nodes_in_face);
2307 break;
2308 case 4:
2309 nodes_in_face_l = ConstArrayView<Integer>::create(nodes_in_face_4, nb_nodes_in_face);
2310 break;
2311 case 5:
2312 nodes_in_face_l = ConstArrayView<Integer>::create(nodes_in_face_5, nb_nodes_in_face);
2313 break;
2314 default:
2315 ARCANE_FATAL("Bizarre...");
2316 }
2317 for (Integer nc : nodes_in_face_l) {
2318 faces_infos.add(parent_nodes_uids[nc]);
2319 }
2320 total_nb_faces++;
2321
2322 if ((!mask_face_if_cell_left[l]) && is_cell_around_parent_cell_exist_and_different_owner(1, 1, 0)) {
2323 parent_face_owner = owner_cells_around_parent_cell(1, 1, 0);
2324 }
2325 else if ((!mask_face_if_cell_bottom[l]) && is_cell_around_parent_cell_exist_and_different_owner(1, 0, 1)) {
2326 parent_face_owner = owner_cells_around_parent_cell(1, 0, 1);
2327 }
2328 else if ((!mask_face_if_cell_rear[l]) && is_cell_around_parent_cell_exist_and_different_owner(0, 1, 1)) {
2329 parent_face_owner = owner_cells_around_parent_cell(0, 1, 1);
2330 }
2331 else {
2332 parent_face_owner = owner_cells_around_parent_cell(1, 1, 1);
2333 }
2334 face_uid_to_owner[parent_faces_uids[l]] = parent_face_owner;
2335 // debug() << "Parent face (create face) -- parent_cell_uid : " << parent_cell_uid
2336 // << " -- level : " << -1
2337 // << " -- face : " << l
2338 // << " -- uid_face : " << parent_faces_uids[l]
2339 // << " -- owner : " << parent_face_owner;
2340 }
2341 }
2342
2343 // Node Part.
2344 // This part is quite similar to the face part, except that there can be
2345 // more possible owners.
2346 for (Integer l = 0; l < m_num_mng->nbNodeByCell(); ++l) {
2347 if (
2348 (mask_node_if_cell_left[l] || is_cell_around_parent_cell_different_owner(1, 1, 0) || is_not_in_subdomain_cells_around_parent_cell(1, 1, 0)) &&
2349 (mask_node_if_cell_bottom[l] || is_cell_around_parent_cell_different_owner(1, 0, 1) || is_not_in_subdomain_cells_around_parent_cell(1, 0, 1)) &&
2350 (mask_node_if_cell_rear[l] || is_cell_around_parent_cell_different_owner(0, 1, 1) || is_not_in_subdomain_cells_around_parent_cell(0, 1, 1))) {
2351 Integer parent_node_owner = -1;
2352 nodes_infos.add(parent_nodes_uids[l]);
2353 total_nb_nodes++;
2354
2355 if ((!mask_node_if_cell_left[l])) {
2356 if ((!mask_node_if_cell_bottom[l])) {
2357 if ((!mask_node_if_cell_rear[l])) {
2358
2359 if (is_cell_around_parent_cell_exist_and_different_owner(0, 0, 0)) {
2360 parent_node_owner = owner_cells_around_parent_cell(0, 0, 0);
2361 }
2362 else if (is_cell_around_parent_cell_exist_and_different_owner(0, 0, 1)) {
2363 parent_node_owner = owner_cells_around_parent_cell(0, 0, 1);
2364 }
2365 else if (is_cell_around_parent_cell_exist_and_different_owner(0, 1, 0)) {
2366 parent_node_owner = owner_cells_around_parent_cell(0, 1, 0);
2367 }
2368 else if (is_cell_around_parent_cell_exist_and_different_owner(0, 1, 1)) {
2369 parent_node_owner = owner_cells_around_parent_cell(0, 1, 1);
2370 }
2371 else if (is_cell_around_parent_cell_exist_and_different_owner(1, 0, 0)) {
2372 parent_node_owner = owner_cells_around_parent_cell(1, 0, 0);
2373 }
2374 else if (is_cell_around_parent_cell_exist_and_different_owner(1, 0, 1)) {
2375 parent_node_owner = owner_cells_around_parent_cell(1, 0, 1);
2376 }
2377 else if (is_cell_around_parent_cell_exist_and_different_owner(1, 1, 0)) {
2378 parent_node_owner = owner_cells_around_parent_cell(1, 1, 0);
2379 }
2380 else {
2381 parent_node_owner = owner_cells_around_parent_cell(1, 1, 1);
2382 }
2383 }
2384 else {
2385 if (is_cell_around_parent_cell_exist_and_different_owner(1, 0, 0)) {
2386 parent_node_owner = owner_cells_around_parent_cell(1, 0, 0);
2387 }
2388 else if (is_cell_around_parent_cell_exist_and_different_owner(1, 0, 1)) {
2389 parent_node_owner = owner_cells_around_parent_cell(1, 0, 1);
2390 }
2391 else if (is_cell_around_parent_cell_exist_and_different_owner(1, 1, 0)) {
2392 parent_node_owner = owner_cells_around_parent_cell(1, 1, 0);
2393 }
2394 else {
2395 parent_node_owner = owner_cells_around_parent_cell(1, 1, 1);
2396 }
2397 }
2398 }
2399 else {
2400 if ((!mask_node_if_cell_rear[l])) {
2401 if (is_cell_around_parent_cell_exist_and_different_owner(0, 1, 0)) {
2402 parent_node_owner = owner_cells_around_parent_cell(0, 1, 0);
2403 }
2404 else if (is_cell_around_parent_cell_exist_and_different_owner(0, 1, 1)) {
2405 parent_node_owner = owner_cells_around_parent_cell(0, 1, 1);
2406 }
2407 else if (is_cell_around_parent_cell_exist_and_different_owner(0, 2, 0)) {
2408 parent_node_owner = owner_cells_around_parent_cell(0, 2, 0);
2409 }
2410 else if (is_cell_around_parent_cell_exist_and_different_owner(0, 2, 1)) {
2411 parent_node_owner = owner_cells_around_parent_cell(0, 2, 1);
2412 }
2413 else if (is_cell_around_parent_cell_exist_and_different_owner(1, 1, 0)) {
2414 parent_node_owner = owner_cells_around_parent_cell(1, 1, 0);
2415 }
2416 else {
2417 parent_node_owner = owner_cells_around_parent_cell(1, 1, 1);
2418 }
2419 }
2420 else {
2421 if (is_cell_around_parent_cell_exist_and_different_owner(1, 1, 0)) {
2422 parent_node_owner = owner_cells_around_parent_cell(1, 1, 0);
2423 }
2424 else {
2425 parent_node_owner = owner_cells_around_parent_cell(1, 1, 1);
2426 }
2427 }
2428 }
2429 }
2430 else {
2431 if ((!mask_node_if_cell_bottom[l])) {
2432 if ((!mask_node_if_cell_rear[l])) {
2433 if (is_cell_around_parent_cell_exist_and_different_owner(0, 0, 1)) {
2434 parent_node_owner = owner_cells_around_parent_cell(0, 0, 1);
2435 }
2436 else if (is_cell_around_parent_cell_exist_and_different_owner(0, 0, 2)) {
2437 parent_node_owner = owner_cells_around_parent_cell(0, 0, 2);
2438 }
2439 else if (is_cell_around_parent_cell_exist_and_different_owner(0, 1, 1)) {
2440 parent_node_owner = owner_cells_around_parent_cell(0, 1, 1);
2441 }
2442 else if (is_cell_around_parent_cell_exist_and_different_owner(0, 1, 2)) {
2443 parent_node_owner = owner_cells_around_parent_cell(0, 1, 2);
2444 }
2445 else if (is_cell_around_parent_cell_exist_and_different_owner(1, 0, 1)) {
2446 parent_node_owner = owner_cells_around_parent_cell(1, 0, 1);
2447 }
2448 else if (is_cell_around_parent_cell_exist_and_different_owner(1, 0, 2)) {
2449 parent_node_owner = owner_cells_around_parent_cell(1, 0, 2);
2450 }
2451 else {
2452 parent_node_owner = owner_cells_around_parent_cell(1, 1, 1);
2453 }
2454 }
2455 else {
2456 if (is_cell_around_parent_cell_exist_and_different_owner(1, 0, 1)) {
2457 parent_node_owner = owner_cells_around_parent_cell(1, 0, 1);
2458 }
2459 else if (is_cell_around_parent_cell_exist_and_different_owner(1, 0, 2)) {
2460 parent_node_owner = owner_cells_around_parent_cell(1, 0, 2);
2461 }
2462 else {
2463 parent_node_owner = owner_cells_around_parent_cell(1, 1, 1);
2464 }
2465 }
2466 }
2467 else {
2468 if ((!mask_node_if_cell_rear[l])) {
2469 if (is_cell_around_parent_cell_exist_and_different_owner(0, 1, 1)) {
2470 parent_node_owner = owner_cells_around_parent_cell(0, 1, 1);
2471 }
2472 else if (is_cell_around_parent_cell_exist_and_different_owner(0, 1, 2)) {
2473 parent_node_owner = owner_cells_around_parent_cell(0, 1, 2);
2474 }
2475 else if (is_cell_around_parent_cell_exist_and_different_owner(0, 2, 1)) {
2476 parent_node_owner = owner_cells_around_parent_cell(0, 2, 1);
2477 }
2478 else if (is_cell_around_parent_cell_exist_and_different_owner(0, 2, 2)) {
2479 parent_node_owner = owner_cells_around_parent_cell(0, 2, 2);
2480 }
2481 else {
2482 parent_node_owner = owner_cells_around_parent_cell(1, 1, 1);
2483 }
2484 }
2485 else {
2486 parent_node_owner = owner_cells_around_parent_cell(1, 1, 1);
2487 }
2488 }
2489 }
2490
2491 node_uid_to_owner[parent_nodes_uids[l]] = parent_node_owner;
2492 // debug() << "Parent node (create node) -- parent_cell_uid : " << parent_cell_uid
2493 // << " -- level : " << -1
2494 // << " -- node : " << l
2495 // << " -- uid_node : " << parent_nodes_uids[l]
2496 // << " -- owner : " << parent_node_owner;
2497 }
2498 }
2499 }
2500 }
2501 else {
2502 ARCANE_FATAL("Bad dimension");
2503 }
2504
2505 // Nodes
2506 {
2507 debug() << "Nb new nodes in patch : " << total_nb_nodes;
2508 {
2509 // This array will contain the localIds of the new nodes.
2510 UniqueArray<Int32> nodes_lid(total_nb_nodes);
2511
2512 // We create the nodes. We put the localIds of the new nodes at the beginning of the array.
2513 m_mesh->modifier()->addNodes(nodes_infos, nodes_lid);
2514
2515 UniqueArray<Int64> uid_child_nodes(total_nb_nodes);
2516 UniqueArray<Int32> lid_child_nodes(total_nb_nodes);
2517 Integer index = 0;
2518
2519 // We assign the correct owners to the nodes.
2520 ENUMERATE_ (Node, inode, m_mesh->nodeFamily()->view(nodes_lid)) {
2521 Node node = *inode;
2522
2523 ARCANE_ASSERT((node_uid_to_owner.contains(node.uniqueId())), ("No owner found for node"));
2524 ARCANE_ASSERT((node_uid_to_owner[node.uniqueId()] < nb_rank && node_uid_to_owner[node.uniqueId()] >= 0), ("Bad owner found for node"));
2525
2526 node.mutableItemBase().setOwner(node_uid_to_owner[node.uniqueId()], my_rank);
2527
2528 if (node_uid_to_owner[node.uniqueId()] == my_rank) {
2530 }
2531
2532 uid_child_nodes[index++] = m_num_mng->childNodeUniqueIdOfNode(node.uniqueId(), -1);
2533 }
2534 m_mesh->nodeFamily()->itemsUniqueIdToLocalId(lid_child_nodes, uid_child_nodes, false);
2535 NodeInfoListView nodes(m_mesh->nodeFamily());
2536
2537 index = 0;
2538 ENUMERATE_ (Node, inode, m_mesh->nodeFamily()->view(nodes_lid)) {
2539 const Int32 child_lid = lid_child_nodes[index++];
2540 if (child_lid == NULL_ITEM_ID) {
2541 continue;
2542 }
2543
2544 Node child = nodes[child_lid];
2545 Node parent = *inode;
2546
2547 m_mesh->modifier()->addParentNodeToNode(child, parent);
2548 m_mesh->modifier()->addChildNodeToNode(parent, child);
2549 }
2550 }
2551
2552 m_mesh->nodeFamily()->notifyItemsOwnerChanged();
2553 }
2554
2555 // Faces
2556 {
2557 debug() << "Nb new faces in patch : " << total_nb_faces;
2558 {
2559 Integer nb_child = (m_mesh->dimension() == 2 ? 2 : 4);
2560 UniqueArray<Int32> faces_lid(total_nb_faces);
2561
2562 m_mesh->modifier()->addFaces(total_nb_faces, faces_infos, faces_lid);
2563
2564 UniqueArray<Int64> uid_child_faces(total_nb_faces * m_num_mng->nbFaceByCell());
2565 UniqueArray<Int32> lid_child_faces(total_nb_faces * m_num_mng->nbFaceByCell());
2566 Integer index = 0;
2567
2568 // We assign the correct owners to the faces.
2569 ENUMERATE_ (Face, iface, m_mesh->faceFamily()->view(faces_lid)) {
2570 Face face = *iface;
2571
2572 ARCANE_ASSERT((face_uid_to_owner.contains(face.uniqueId())), ("No owner found for face"));
2573 ARCANE_ASSERT((face_uid_to_owner[face.uniqueId()] < nb_rank && face_uid_to_owner[face.uniqueId()] >= 0), ("Bad owner found for face"));
2574
2575 face.mutableItemBase().setOwner(face_uid_to_owner[face.uniqueId()], my_rank);
2576
2577 if (face_uid_to_owner[face.uniqueId()] == my_rank) {
2579 }
2580
2581 for (Integer i = 0; i < nb_child; ++i) {
2582 uid_child_faces[index++] = m_num_mng->childFaceUniqueIdOfFace(face.uniqueId(), -1, i);
2583 }
2584 }
2585
2586 m_mesh->faceFamily()->itemsUniqueIdToLocalId(lid_child_faces, uid_child_faces, false);
2587 FaceInfoListView faces(m_mesh->faceFamily());
2588
2589 index = 0;
2590 ENUMERATE_ (Face, iface, m_mesh->faceFamily()->view(faces_lid)) {
2591 for (Integer i = 0; i < nb_child; ++i) {
2592 const Int32 child_lid = lid_child_faces[index++];
2593 if (child_lid == NULL_ITEM_ID) {
2594 continue;
2595 }
2596
2597 Face child = faces[child_lid];
2598 Face parent = *iface;
2599
2600 m_mesh->modifier()->addParentFaceToFace(child, parent);
2601 m_mesh->modifier()->addChildFaceToFace(parent, child);
2602 }
2603 }
2604 }
2605
2606 m_mesh->faceFamily()->notifyItemsOwnerChanged();
2607 }
2608
2609 // Cells
2610 UniqueArray<Int32> cells_lid(total_nb_cells);
2611 {
2612 debug() << "Nb new cells in patch : " << total_nb_cells;
2613
2614 m_mesh->modifier()->addCells(total_nb_cells, cells_infos, cells_lid);
2615
2616 // Iterating over the new cells.
2617 CellInfoListView cells(m_mesh->cellFamily());
2618 for (Integer i = 0; i < total_nb_cells; ++i) {
2619 Cell parent = cells[cells_lid[i]];
2620
2621 parent.mutableItemBase().setOwner(around_parent_cells_uid_to_owner[parent.uniqueId()], my_rank);
2622
2626
2627 if (around_parent_cells_uid_to_owner[parent.uniqueId()] == my_rank) {
2629 }
2630 if (parent_to_child_cells[parent.uniqueId()][0].itemBase().flags() & ItemFlags::II_Shared) {
2632 }
2633 for (Cell child : parent_to_child_cells[parent.uniqueId()]) {
2634 m_mesh->modifier()->addParentCellToCell(child, parent);
2635 m_mesh->modifier()->addChildCellToCell(parent, child);
2636 }
2637 }
2638 m_mesh->cellFamily()->notifyItemsOwnerChanged();
2639 }
2640
2641 m_mesh->modifier()->endUpdate();
2642 m_num_mng->updateFirstLevel();
2643
2644 // We position the nodes in space.
2645 CellInfoListView cells(m_mesh->cellFamily());
2646 for (Integer i = 0; i < total_nb_cells; ++i) {
2647 Cell parent_cell = cells[cells_lid[i]];
2648 m_num_mng->setParentNodeCoordinates(parent_cell);
2649
2650 // We add the "II_Shared" flag to the nodes and faces of shared cells.
2651 if (parent_cell.mutableItemBase().flags() & ItemFlags::II_Shared) {
2652 for (Node node : parent_cell.nodes()) {
2653 if (node.mutableItemBase().flags() & ItemFlags::II_Own) {
2654 node.mutableItemBase().addFlags(ItemFlags::II_Shared);
2655 }
2656 }
2657 for (Face face : parent_cell.faces()) {
2658 if (face.mutableItemBase().flags() & ItemFlags::II_Own) {
2659 face.mutableItemBase().addFlags(ItemFlags::II_Shared);
2660 }
2661 }
2662 }
2663 }
2664
2665 // Recalculate synchronization information
2666 // This is not necessary for AMR because this information will be recalculated
2667 // during refinement, but since we do not know if we will perform refinement
2668 // afterward, it is better to calculate this information in all cases.
2669 m_mesh->computeSynchronizeInfos();
2670
2671 // ENUMERATE_(Cell, icell, m_mesh->allCells()){
2672 // debug() << "\t" << *icell;
2673 // for(Node node : icell->nodes()){
2674 // debug() << "\t\t" << node;
2675 // }
2676 // for(Face face : icell->faces()){
2677 // debug() << "\t\t\t" << face;
2678 // }
2679 // }
2680 // info() << "Summary:";
2681 // ENUMERATE_ (Cell, icell, m_mesh->allCells()) {
2682 // debug() << "\tCell uniqueId : " << icell->uniqueId() << " -- level : " << icell->level() << " -- nbChildren : " << icell->nbHChildren();
2683 // for (Integer i = 0; i < icell->nbHChildren(); ++i) {
2684 // debug() << "\t\tChild uniqueId : " << icell->hChild(i).uniqueId() << " -- level : " << icell->hChild(i).level() << " -- nbChildren : " << icell->hChild(i).nbHChildren();
2685 // }
2686 // }
2687 // info() << "Node summary:";
2688 // ENUMERATE_ (Node, inode, m_mesh->allNodes()) {
2689 // debug() << "\tNode uniqueId : " << inode->uniqueId() << " -- level : " << inode->level() << " -- nbChildren : " << inode->nbHChildren();
2690 // for (Integer i = 0; i < inode->nbHChildren(); ++i) {
2691 // debug() << "\t\tNode Child uniqueId : " << inode->hChild(i).uniqueId() << " -- level : " << inode->hChild(i).level() << " -- nbChildren : " << inode->hChild(i).nbHChildren();
2692 // }
2693 // }
2694 //
2695 // info() << "Face summary:";
2696 // ENUMERATE_ (Face, iface, m_mesh->allFaces()) {
2697 // debug() << "\tFace uniqueId : " << iface->uniqueId() << " -- level : " << iface->level() << " -- nbChildren : " << iface->nbHChildren();
2698 // for (Integer i = 0; i < iface->nbHChildren(); ++i) {
2699 // debug() << "\t\tChild uniqueId : " << iface->hChild(i).uniqueId() << " -- level : " << iface->hChild(i).level() << " -- nbChildren : " << iface->hChild(i).nbHChildren();
2700 // }
2701 // }
2702}
2703
2704/*---------------------------------------------------------------------------*/
2705/*---------------------------------------------------------------------------*/
2706
2707void CartesianMeshAMRPatchMng::
2708coarsen(bool update_parent_flag)
2709{
2710 // We start by listing the cells to coarsen.
2711 UniqueArray<Cell> cells_to_coarsen_internal;
2712 ENUMERATE_ (Cell, icell, m_mesh->allActiveCells()) {
2713 Cell cell = *icell;
2714 if (cell.itemBase().flags() & ItemFlags::II_Coarsen) {
2715 if (cell.level() == 0) {
2716 ARCANE_FATAL("Cannot coarse level-0 cell");
2717 }
2718
2719 Cell parent = cell.hParent();
2720
2721 if (update_parent_flag) {
2725 }
2726
2727 // For a level n-1 cell, if one of its child cells must be coarsened,
2728 // then all its child cells must be coarsened.
2729 for (Integer i = 0; i < parent.nbHChildren(); ++i) {
2730 Cell child = parent.hChild(i);
2731 if (!(child.mutableItemBase().flags() & ItemFlags::II_Coarsen)) {
2732 ARCANE_FATAL("Parent cannot have children with coarse flag and children without coarse flag -- Parent uid: {0} -- Child uid: {1}", parent.uniqueId(), child.uniqueId());
2733 }
2734 }
2735 if (parent.mutableItemBase().flags() & ItemFlags::II_Coarsen) {
2736 ARCANE_FATAL("Cannot coarse parent and child in same time");
2737 }
2738 if (cell.nbHChildren() != 0) {
2739 ARCANE_FATAL("For now, cannot coarse cell with children");
2740 }
2741 cells_to_coarsen_internal.add(cell);
2742 }
2743 }
2744
2745 // Maps replacing ghost cells.
2746 std::unordered_map<Int64, Integer> around_cells_uid_to_owner;
2747 std::unordered_map<Int64, Int32> around_cells_uid_to_flags;
2748
2749 {
2750 // We only need these two flags for surrounding cells.
2751 // (II_Coarsen to know if surrounding cells are also to be de-refined)
2752 // (II_Inactive to know if surrounding cells are already refined (to check that there is no more than one level of difference))
2754 _shareInfosOfCellsAroundPatch(cells_to_coarsen_internal, around_cells_uid_to_owner, around_cells_uid_to_flags, useful_flags);
2755 }
2756
2757 // Before deleting the cells, we must change the owners of the faces/nodes between the
2758 // cells to be deleted and the remaining cells.
2759 if (m_mesh->dimension() == 2) {
2760 FixedArray<Int64, 9> uid_cells_around_cell_1d;
2761 FixedArray<Int32, 9> owner_cells_around_cell_1d;
2762 FixedArray<Int32, 9> flags_cells_around_cell_1d;
2763
2764 for (Cell cell_to_coarsen : cells_to_coarsen_internal) {
2765 const Int64 cell_to_coarsen_uid = cell_to_coarsen.uniqueId();
2766 m_num_mng->cellUniqueIdsAroundCell(cell_to_coarsen, uid_cells_around_cell_1d.view());
2767
2768 {
2769 Integer nb_cells_to_coarsen_or_empty_around = 0;
2770
2771 for (Integer i = 0; i < 9; ++i) {
2772 Int64 uid_cell = uid_cells_around_cell_1d[i];
2773 // If uid_cell != -1 then there might be a cell (but we don't know if it is actually present).
2774 // If around_cells_uid_to_owner[uid_cell] != -1 then there is indeed a cell.
2775 if (uid_cell != -1 && around_cells_uid_to_owner[uid_cell] != -1) {
2776 owner_cells_around_cell_1d[i] = around_cells_uid_to_owner[uid_cell];
2777 flags_cells_around_cell_1d[i] = around_cells_uid_to_flags[uid_cell];
2778
2779 if (flags_cells_around_cell_1d[i] & ItemFlags::II_Coarsen) {
2780 nb_cells_to_coarsen_or_empty_around++;
2781 }
2782 }
2783 else {
2784 uid_cells_around_cell_1d[i] = -1;
2785 owner_cells_around_cell_1d[i] = -1;
2786 flags_cells_around_cell_1d[i] = 0;
2787
2788 nb_cells_to_coarsen_or_empty_around++;
2789 }
2790 }
2791
2792 // If all cells around us are either non-existent or
2793 // to be deleted, there is no need to look for new owners for our items.
2794 // Our cell is to be de-refined, so nb_cells_to_coarsen_or_empty_around >= 1.
2795 if (nb_cells_to_coarsen_or_empty_around == 9) {
2796 continue;
2797 }
2798 }
2799
2800 // The owner of our cell.
2801 Int32 cell_to_coarsen_owner = owner_cells_around_cell_1d[4];
2802
2803 {
2804 // We provide the face position in the surrounding cells array
2805 // according to the face index assigned by Arcane.
2806 // (See comment tagged "arcane_order_to_around_2d").
2807 // cell_to_coarsen.face(0) = uid_cells_around_cell_1d[1]
2808 // cell_to_coarsen.face(1) = uid_cells_around_cell_1d[5]
2809 // ...
2810 constexpr Integer arcane_order_to_pos_around[] = { 1, 5, 7, 3 };
2811
2812 Integer count = -1;
2813
2814 for (Face face : cell_to_coarsen.faces()) {
2815 count++;
2816 Int64 other_cell_uid = uid_cells_around_cell_1d[arcane_order_to_pos_around[count]];
2817 if (other_cell_uid == -1) {
2818 // We are at the boundary of the mesh or there is no cell of the same level next to it,
2819 // no need to change the face owner (it will be deleted).
2820 continue;
2821 }
2822 Int32 other_cell_flag = flags_cells_around_cell_1d[arcane_order_to_pos_around[count]];
2823
2824 if (other_cell_flag & ItemFlags::II_Coarsen) {
2825 // The adjacent cell will also be deleted, no need to change the face owner.
2826 continue;
2827 }
2828 if (other_cell_flag & ItemFlags::II_Inactive) {
2829 // The adjacent cell has children. There will therefore be at least two levels of
2830 // refinement difference.
2831 ARCANE_FATAL("Max one level diff between two cells is allowed -- Uid of Cell to be coarseing: {0} -- Uid of Opposite cell with children: {1}", cell_to_coarsen_uid, other_cell_uid);
2832 }
2833 Int32 other_cell_owner = owner_cells_around_cell_1d[arcane_order_to_pos_around[count]];
2834 if (other_cell_owner != cell_to_coarsen_owner) {
2835 // The adjacent cell exists and belongs to someone else. We give it the face.
2836 face.mutableItemBase().setOwner(other_cell_owner, cell_to_coarsen_owner);
2837 }
2838 }
2839 }
2840
2841 {
2842 Integer count = -1;
2843
2844 // Here, it's more complicated.
2845 // Each element of the level 0 array designates a node.
2846 // Like for faces, the order is described in the comment tagged "arcane_order_to_around_2d".
2847 //
2848 // Furthermore, there is the priority aspect.
2849 // A node is present in four cells. Three cells will potentially be "surviving".
2850 // We must determine who this node will belong to among these three cells.
2851 // To do this, we use the priorities described in the comment
2852 // tagged "priority_owner_2d".
2853 //
2854 // Example: Node #0 is present on four surrounding cells with priorities: P0, P1, P3, P4.
2855 // Cell P4 (ours) will be deleted.
2856 // In array #0, we put the three priorities (from lowest to highest).
2857 // Then, we iterate over these three cells (always from lowest to highest).
2858 // If cell i is "surviving", it takes ownership.
2859 // Finally, the cell with the highest priority will have the node.
2860 // If no cell takes ownership, then the node will be deleted.
2861 //
2862 constexpr Integer priority_and_pos_of_cells_around_node[4][3] = { { 3, 1, 0 }, { 5, 2, 1 }, { 8, 7, 5 }, { 7, 6, 3 } };
2863
2864 for (Node node : cell_to_coarsen.nodes()) {
2865 count++;
2866 Integer final_owner = -1;
2867 for (Integer other_cell = 0; other_cell < 3; ++other_cell) {
2868 Int64 other_cell_uid = uid_cells_around_cell_1d[priority_and_pos_of_cells_around_node[count][other_cell]];
2869 if (other_cell_uid == -1) {
2870 // We are at the boundary of the mesh or there is no cell of the same level next to it,
2871 // the node will not take an owner.
2872 continue;
2873 }
2874 Int32 other_cell_flag = flags_cells_around_cell_1d[priority_and_pos_of_cells_around_node[count][other_cell]];
2875
2876 if (other_cell_flag & ItemFlags::II_Coarsen) {
2877 // The adjacent cell will also be deleted, it cannot take
2878 // ownership of our node.
2879 continue;
2880 }
2881 if (other_cell_flag & ItemFlags::II_Inactive) {
2882 // The adjacent cell has children. There will therefore be at least two levels of
2883 // refinement difference.
2884 ARCANE_FATAL("Max one level diff between two cells is allowed -- Uid of Cell to be coarseing: {0} -- Uid of Opposite cell with children: {1}", cell_to_coarsen_uid, other_cell_uid);
2885 }
2886 Int32 other_cell_owner = owner_cells_around_cell_1d[priority_and_pos_of_cells_around_node[count][other_cell]];
2887 if (other_cell_owner != cell_to_coarsen_owner) {
2888 // The adjacent cell exists and belongs to someone else. We give it the node.
2889 final_owner = other_cell_owner;
2890 }
2891 }
2892 if (final_owner != -1) {
2893 node.mutableItemBase().setOwner(final_owner, cell_to_coarsen_owner);
2894 }
2895 }
2896 }
2897 }
2898 }
2899 else if (m_mesh->dimension() == 3) {
2900 FixedArray<Int64, 27> uid_cells_around_cell_1d;
2901 FixedArray<Int32, 27> owner_cells_around_cell_1d;
2902 FixedArray<Int32, 27> flags_cells_around_cell_1d;
2903
2904 for (Cell cell_to_coarsen : cells_to_coarsen_internal) {
2905 const Int64 cell_to_coarsen_uid = cell_to_coarsen.uniqueId();
2906 m_num_mng->cellUniqueIdsAroundCell(cell_to_coarsen, uid_cells_around_cell_1d.view());
2907
2908 {
2909 Integer nb_cells_to_coarsen_or_empty_around = 0;
2910
2911 for (Integer i = 0; i < 27; ++i) {
2912 Int64 uid_cell = uid_cells_around_cell_1d[i];
2913 // If uid_cell != -1 then there might be a cell (but we don't know if it is actually present).
2914 // If around_cells_uid_to_owner[uid_cell] != -1 then there is indeed a cell.
2915 if (uid_cell != -1 && around_cells_uid_to_owner[uid_cell] != -1) {
2916 owner_cells_around_cell_1d[i] = around_cells_uid_to_owner[uid_cell];
2917 flags_cells_around_cell_1d[i] = around_cells_uid_to_flags[uid_cell];
2918
2919 if (flags_cells_around_cell_1d[i] & ItemFlags::II_Coarsen) {
2920 nb_cells_to_coarsen_or_empty_around++;
2921 }
2922 }
2923 else {
2924 uid_cells_around_cell_1d[i] = -1;
2925 owner_cells_around_cell_1d[i] = -1;
2926 flags_cells_around_cell_1d[i] = 0;
2927
2928 nb_cells_to_coarsen_or_empty_around++;
2929 }
2930 }
2931
2932 // If all cells around us are either non-existent or
2933 // to be deleted, there is no need to look for new owners for our items.
2934 // Our cell is to be de-refined, so nb_cells_to_coarsen_or_empty_around >= 1.
2935 if (nb_cells_to_coarsen_or_empty_around == 27) {
2936 continue;
2937 }
2938 }
2939
2940 // The owner of our cell.
2941 Int32 cell_to_coarsen_owner = owner_cells_around_cell_1d[13];
2942
2943 {
2944 // We provide the face position in the surrounding cells array
2945 // according to the face index assigned by Arcane.
2946 // (See comment tagged "arcane_order_to_around_3d").
2947 // cell_to_coarsen.face(0) = uid_cells_around_cell_1d[4]
2948 // cell_to_coarsen.face(1) = uid_cells_around_cell_1d[12]
2949 // ...
2950 constexpr Integer arcane_order_to_pos_around[] = { 4, 12, 10, 22, 14, 16 };
2951
2952 Integer count = -1;
2953
2954 for (Face face : cell_to_coarsen.faces()) {
2955 count++;
2956 Int64 other_cell_uid = uid_cells_around_cell_1d[arcane_order_to_pos_around[count]];
2957 if (other_cell_uid == -1) {
2958 // We are at the boundary of the mesh or there is no cell of the same level next to it,
2959 // no need to change the face owner (it will be deleted).
2960 continue;
2961 }
2962 Int32 other_cell_flag = flags_cells_around_cell_1d[arcane_order_to_pos_around[count]];
2963
2964 if (other_cell_flag & ItemFlags::II_Coarsen) {
2965 // The adjacent cell will also be deleted, no need to change the face owner.
2966 continue;
2967 }
2968 if (other_cell_flag & ItemFlags::II_Inactive) {
2969 // The adjacent cell has children. There will therefore be at least two levels of
2970 // refinement difference.
2971 ARCANE_FATAL("Max one level diff between two cells is allowed -- Uid of Cell to be coarseing: {0} -- Uid of Opposite cell with children: {1}", cell_to_coarsen_uid, other_cell_uid);
2972 }
2973 Int32 other_cell_owner = owner_cells_around_cell_1d[arcane_order_to_pos_around[count]];
2974 if (other_cell_owner != cell_to_coarsen_owner) {
2975 // The adjacent cell exists and belongs to someone else. We give it the face.
2976 face.mutableItemBase().setOwner(other_cell_owner, cell_to_coarsen_owner);
2977 }
2978 }
2979 }
2980
2981 {
2982 Integer count = -1;
2983
2984 // Each element of the level 0 array designates a node.
2985 // Like for faces, the order is described in the comment tagged "arcane_order_to_around_3d".
2986 //
2987 // Furthermore, there is the priority aspect.
2988 // A node is present in eight cells. Seven cells will potentially be "surviving".
2989 // We must determine who this node will belong to among these seven cells.
2990 // To do this, we use the priorities described in the comment
2991 // tagged "priority_owner_3d".
2992 //
2993 // Example: Node #0 is present on eight surrounding cells with priorities: P12, P10, P9, ...
2994 // Cell P13 (ours) will be deleted.
2995 // In array #0, we put the seven priorities (from lowest to highest).
2996 // Then, we iterate over these seven cells (always from lowest to highest).
2997 // If cell i is "surviving", it takes ownership.
2998 // Finally, the cell with the highest priority will have the node.
2999 // If no cell takes ownership, then the node will be deleted.
3000 //
3001 constexpr Integer priority_and_pos_of_cells_around_node[8][7] = {
3002 { 12, 10, 9, 4, 3, 1, 0 },
3003 { 14, 11, 10, 5, 4, 2, 1 },
3004 { 17, 16, 14, 8, 7, 5, 4 },
3005 { 16, 15, 12, 7, 6, 4, 3 },
3006 { 22, 21, 19, 18, 12, 10, 9 },
3007 { 23, 22, 20, 19, 14, 11, 10 },
3008 { 26, 25, 23, 22, 17, 16, 14 },
3009 { 25, 24, 22, 21, 16, 15, 12 }
3010 };
3011
3012 for (Node node : cell_to_coarsen.nodes()) {
3013 count++;
3014 Integer final_owner = -1;
3015 for (Integer other_cell = 0; other_cell < 7; ++other_cell) {
3016 Int64 other_cell_uid = uid_cells_around_cell_1d[priority_and_pos_of_cells_around_node[count][other_cell]];
3017 if (other_cell_uid == -1) {
3018 // We are at the boundary of the mesh or there is no cell of the same level next to it,
3019 // the node will not take an owner.
3020 continue;
3021 }
3022 Int32 other_cell_flag = flags_cells_around_cell_1d[priority_and_pos_of_cells_around_node[count][other_cell]];
3023
3024 if (other_cell_flag & ItemFlags::II_Coarsen) {
3025 // The adjacent cell will also be deleted, it cannot take
3026 // ownership of our node.
3027 continue;
3028 }
3029 if (other_cell_flag & ItemFlags::II_Inactive) {
3030 // The adjacent cell has children. There will therefore be at least two levels of
3031 // refinement difference.
3032 ARCANE_FATAL("Max one level diff between two cells is allowed -- Uid of Cell to be coarseing: {0} -- Uid of Opposite cell with children: {1}", cell_to_coarsen_uid, other_cell_uid);
3033 }
3034 Int32 other_cell_owner = owner_cells_around_cell_1d[priority_and_pos_of_cells_around_node[count][other_cell]];
3035 if (other_cell_owner != cell_to_coarsen_owner) {
3036 // The adjacent cell exists and belongs to someone else. We give it the node.
3037 node.mutableItemBase().setOwner(other_cell_owner, cell_to_coarsen_owner);
3038 }
3039 }
3040 if (final_owner != -1) {
3041 node.mutableItemBase().setOwner(final_owner, cell_to_coarsen_owner);
3042 }
3043 }
3044 }
3045 }
3046 }
3047
3048 else {
3049 ARCANE_FATAL("Bad dimension");
3050 }
3051
3052 UniqueArray<Int32> local_ids;
3053 for (Cell cell : cells_to_coarsen_internal) {
3054 local_ids.add(cell.localId());
3055 }
3056 m_mesh->modifier()->removeCells(local_ids);
3057 m_mesh->nodeFamily()->notifyItemsOwnerChanged();
3058 m_mesh->faceFamily()->notifyItemsOwnerChanged();
3059 m_mesh->modifier()->endUpdate();
3060 m_mesh->cellFamily()->computeSynchronizeInfos();
3061 m_mesh->nodeFamily()->computeSynchronizeInfos();
3062 m_mesh->faceFamily()->computeSynchronizeInfos();
3063 m_mesh->modifier()->setDynamic(true);
3064
3065 UniqueArray<Int64> ghost_cell_to_refine;
3066 UniqueArray<Int64> ghost_cell_to_coarsen;
3067
3068 if (!update_parent_flag) {
3069 // If materials are active, a material recalculation must be forced because the
3070 // cell groups have been modified, and thus the list of constituents as well.
3072 if (mm)
3073 mm->forceRecompute();
3074 }
3075
3076 m_mesh->modifier()->updateGhostLayerFromParent(ghost_cell_to_refine, ghost_cell_to_coarsen, true);
3077}
3078
3079/*---------------------------------------------------------------------------*/
3080/*---------------------------------------------------------------------------*/
3081
3091void CartesianMeshAMRPatchMng::
3092_shareInfosOfCellsAroundPatch(ConstArrayView<Cell> patch_cells, std::unordered_map<Int64, Integer>& around_cells_uid_to_owner, std::unordered_map<Int64, Int32>& around_cells_uid_to_flags, Int32 useful_flags) const
3093{
3094 IParallelMng* pm = m_mesh->parallelMng();
3095 Int32 my_rank = pm->commRank();
3096 Int32 nb_rank = pm->commSize();
3097
3098 // Part exchanging information about cells around the patch
3099 // (to replace ghost cells).
3100
3101 // We fill the array with our info, for the other processes.
3102 ENUMERATE_ (Cell, icell, m_mesh->ownCells()) {
3103 Cell cell = *icell;
3104 around_cells_uid_to_owner[cell.uniqueId()] = my_rank;
3105 around_cells_uid_to_flags[cell.uniqueId()] = ((cell.itemBase().flags() & useful_flags) + ItemFlags::II_UserMark1);
3106 }
3107
3108 ENUMERATE_ (Cell, icell, m_mesh->allCells().ghost()) {
3109 Cell cell = *icell;
3110 around_cells_uid_to_owner[cell.uniqueId()] = cell.owner();
3111 around_cells_uid_to_flags[cell.uniqueId()] = ((cell.itemBase().flags() & useful_flags) + ItemFlags::II_UserMark1);
3112 }
3113
3114 // Array that will contain the uids of the cells whose info we need.
3115 UniqueArray<Int64> uid_of_cells_needed;
3116 {
3117 UniqueArray<Int64> cell_uids_around((m_mesh->dimension() == 2) ? 9 : 27);
3118 for (Cell cell : patch_cells) {
3119 m_num_mng->cellUniqueIdsAroundCell(cell, cell_uids_around);
3120 for (Int64 cell_uid : cell_uids_around) {
3121 // If -1 then there are no cells at this position.
3122 if (cell_uid == -1)
3123 continue;
3124
3125 // IF we have the cell, we don't need to request info.
3126 if (around_cells_uid_to_owner.contains(cell_uid))
3127 continue;
3128
3129 uid_of_cells_needed.add(cell_uid);
3130 }
3131 }
3132 }
3133
3134 UniqueArray<Int64> uid_of_cells_needed_all_procs;
3135 pm->allGatherVariable(uid_of_cells_needed, uid_of_cells_needed_all_procs);
3136
3137 UniqueArray<Int32> flags_of_cells_needed_all_procs(uid_of_cells_needed_all_procs.size());
3138 UniqueArray<Int32> owner_of_cells_needed_all_procs(uid_of_cells_needed_all_procs.size());
3139
3140 {
3141 UniqueArray<Int32> local_ids(uid_of_cells_needed_all_procs.size());
3142 m_mesh->cellFamily()->itemsUniqueIdToLocalId(local_ids, uid_of_cells_needed_all_procs, false);
3143 Integer compt = 0;
3144 ENUMERATE_ (Cell, icell, m_mesh->cellFamily()->view(local_ids)) {
3145 // isOwn is important since there might be ghost cells.
3146 if (!icell->null() && icell->isOwn()) {
3147 owner_of_cells_needed_all_procs[compt] = my_rank;
3148 flags_of_cells_needed_all_procs[compt] = (icell->itemBase().flags() & useful_flags);
3149 }
3150 else {
3151 owner_of_cells_needed_all_procs[compt] = -1;
3152 flags_of_cells_needed_all_procs[compt] = 0;
3153 }
3154 compt++;
3155 }
3156 }
3157
3158 pm->reduce(Parallel::eReduceType::ReduceMax, owner_of_cells_needed_all_procs);
3159 pm->reduce(Parallel::eReduceType::ReduceMax, flags_of_cells_needed_all_procs);
3160
3161 // From this point, if the parent_cells are at level 0, the array
3162 // "owner_of_cells_needed_all_procs" should no longer contain "-1".
3163 // If the parent_cells are at level 1 or higher, there may be "-1"
3164 // because the surrounding cells are not necessarily all refined.
3165 // (example: we are doing level 2, so we look at level 1 parent cells around.
3166 // It is possible that the adjacent cell has never been refined, so it does not have
3167 // level 1 cells. Since the cell does not exist, no process can set an owner,
3168 // so the owner array will contain "-1").
3169
3170 // We retrieve the info of the surrounding cells that interest us.
3171 {
3172 Integer size_uid_of_cells_needed = uid_of_cells_needed.size();
3173 Integer my_pos_in_all_procs_arrays = 0;
3174 UniqueArray<Integer> size_uid_of_cells_needed_per_proc(nb_rank);
3175 ArrayView<Integer> av(1, &size_uid_of_cells_needed);
3176 pm->allGather(av, size_uid_of_cells_needed_per_proc);
3177
3178 for (Integer i = 0; i < my_rank; ++i) {
3179 my_pos_in_all_procs_arrays += size_uid_of_cells_needed_per_proc[i];
3180 }
3181
3182 ArrayView<Int32> owner_of_cells_needed = owner_of_cells_needed_all_procs.subView(my_pos_in_all_procs_arrays, size_uid_of_cells_needed);
3183 ArrayView<Int32> flags_of_cells_needed = flags_of_cells_needed_all_procs.subView(my_pos_in_all_procs_arrays, size_uid_of_cells_needed);
3184 for (Integer i = 0; i < size_uid_of_cells_needed; ++i) {
3185 around_cells_uid_to_owner[uid_of_cells_needed[i]] = owner_of_cells_needed[i];
3186 around_cells_uid_to_flags[uid_of_cells_needed[i]] = flags_of_cells_needed[i];
3187 }
3188 }
3189}
3190
3191/*---------------------------------------------------------------------------*/
3192/*---------------------------------------------------------------------------*/
3193
3194} // End namespace Arcane
3195
3196/*---------------------------------------------------------------------------*/
3197/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
#define ENUMERATE_(type, name, group)
Generic enumerator for an entity group.
Integer size() const
Number of elements in the vector.
bool contains(ConstReferenceType v) const
True if the array contains the value element v.
Modifiable view of an array of type T.
void add(ConstReferenceType val)
Adds element val to the end of the array.
void reserve(Int64 new_capacity)
Reserves memory for new_capacity elements.
ArrayView< T > subView(Int64 abegin, Integer asize)
Sub-view starting from element abegin and containing asize elements.
void _shareInfosOfCellsAroundPatch(ConstArrayView< Cell > patch_cells, std::unordered_map< Int64, Integer > &around_cells_uid_to_owner, std::unordered_map< Int64, Int32 > &around_cells_uid_to_flags, Int32 useful_flags) const
Method allowing retrieval of owners and flags of cells around patch_cells.
View of cell information.
Cell of a mesh.
Definition Item.h:1300
FaceConnectedListViewType faces() const
List of faces of the cell.
Definition Item.h:1403
Int32 nbHChildren() const
Number of children for AMR.
Definition Item.h:1438
Cell hChild(Int32 i) const
i-th AMR child
Definition Item.h:1441
Int32 level() const
Definition Item.h:1473
Cell hParent() const
Definition Item.h:1432
Constant view of an array of type T.
static constexpr ThatClass create(const_pointer ptr, Integer asize) noexcept
View of face information.
Face of a cell.
Definition Item.h:1032
constexpr __host__ __device__ ArrayView< T > view()
Modifiable view of the array.
Interface for Cartesian mesh numbering manager.
virtual void setBuilderVersion(Integer n)=0
Sets the version of the ghost cell builder. For now (version 3.3), the possible values are 2,...
virtual Integer nbGhostLayer() const =0
Number of ghost layers.
virtual Integer builderVersion() const =0
Ghost cell builder version.
virtual void setNbGhostLayer(Integer n)=0
Sets the number of ghost layers.
Mesh modification interface.
virtual void updateGhostLayers()=0
Updates the ghost layer.
virtual void setDynamic(bool v)=0
Sets the property indicating whether the mesh can evolve.
Interface of the parallelism manager for a subdomain.
virtual Int32 commRank() const =0
Rank of this instance in the communicator.
virtual void allGatherVariable(ConstArrayView< char > send_buf, Array< char > &recv_buf)=0
Performs an all-gather operation across all processors.
virtual Int32 commSize() const =0
Number of instances in the communicator.
virtual void allGather(ConstArrayView< char > send_buf, ArrayView< char > recv_buf)=0
Performs an all-gather operation across all processors. This is a collective operation....
virtual char reduce(eReduceType rt, char v)=0
Performs a reduction of type rt on the real v and returns the value.
Int32 flags() const
Flags of the entity.
@ II_Inactive
The entity is inactive //COARSEN_INACTIVE,.
Definition ItemFlags.h:80
@ II_Refine
The entity is marked for refinement.
Definition ItemFlags.h:77
@ II_JustAdded
The entity has just been added.
Definition ItemFlags.h:62
@ II_Shared
The entity is shared by another subdomain.
Definition ItemFlags.h:59
@ II_JustRefined
The entity has just been refined.
Definition ItemFlags.h:78
@ II_Own
The entity is a domain-specific entity.
Definition ItemFlags.h:56
@ II_CoarsenInactive
The entity is inactive and has children tagged for coarsening.
Definition ItemFlags.h:81
@ II_Coarsen
The entity is marked for coarsening.
Definition ItemFlags.h:75
@ II_JustCoarsened
The entity has just been coarsened.
Definition ItemFlags.h:79
@ II_UserMark1
User mark.
Definition ItemFlags.h:94
NodeConnectedListViewType nodes() const
List of nodes of the entity.
Definition Item.h:843
impl::MutableItemBase mutableItemBase() const
Mutable internal part of the entity.
Definition Item.h:394
Int32 owner() const
Owner subdomain number of the entity.
Definition Item.h:252
ItemUniqueId uniqueId() const
Unique identifier across all domains.
Definition Item.h:239
impl::ItemBase itemBase() const
Internal part of the entity.
Definition Item.h:383
Interface for the material and environment manager of a mesh.
virtual void forceRecompute()=0
Forces the recalculation of material information.
static IMeshMaterialMng * getReference(const MeshHandleOrMesh &mesh_handle, bool create=true)
Retrieves or creates the reference associated with mesh.
void setOwner(Integer suid, Int32 current_sub_domain)
Sets the sub-domain number of the entity owner.
void addFlags(Int32 added_flags)
Adds the flags added_flags to those of the entity.
void removeFlags(Int32 removed_flags)
Removes the flags removed_flags from those of the entity.
View of node information.
Node of a mesh.
Definition Item.h:598
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flow for a debug message.
1D data vector with value semantics (STL style).
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Int32 CartCoord
Represents a coordinate of an element in the Cartesian grid (in X or Y or Z).
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
Int32x2 CartCoord2
Represents the 2D coordinates of an element in the Cartesian grid {x, y}.
std::int32_t Int32
Signed integer type of 32 bits.
Int32x3 CartCoord3
Represents the 3D coordinates of an element in the Cartesian grid {x, y, z}.