Arcane  4.1.12.0
User documentation
Loading...
Searching...
No Matches
CartesianMeshCoarsening2.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/* CartesianMeshCoarsening.cc (C) 2000-2024 */
9/* */
10/* Coarsening of a Cartesian mesh. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/cartesianmesh/CartesianMeshCoarsening2.h"
15
16#include "arcane/utils/FatalErrorException.h"
17#include "arcane/utils/ValueConvert.h"
18#include "arcane/utils/SmallArray.h"
19
20#include "arcane/core/IMesh.h"
21#include "arcane/core/ItemGroup.h"
22#include "arcane/core/IParallelMng.h"
23#include "arcane/core/CartesianGridDimension.h"
24#include "arcane/core/IMeshModifier.h"
25#include "arcane/core/SimpleSVGMeshExporter.h"
26#include "arcane/core/ItemPrinter.h"
27#include "arcane/core/MeshStats.h"
28#include "arcane/core/IGhostLayerMng.h"
29
30#include "arcane/mesh/CellFamily.h"
31
32#include "arcane/cartesianmesh/ICartesianMesh.h"
33#include "arcane/cartesianmesh/CellDirectionMng.h"
34#include "arcane/cartesianmesh/internal/ICartesianMeshInternal.h"
35
36#include <unordered_set>
37
38/*---------------------------------------------------------------------------*/
39/*---------------------------------------------------------------------------*/
40
41namespace Arcane
42{
43
44/*---------------------------------------------------------------------------*/
45/*---------------------------------------------------------------------------*/
46
47CartesianMeshCoarsening2::
48CartesianMeshCoarsening2(ICartesianMesh* m)
49: TraceAccessor(m->traceMng())
50, m_cartesian_mesh(m)
51{
52 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_CARTESIANMESH_COARSENING_VERBOSITY_LEVEL", true))
53 m_verbosity_level = v.value();
54}
55
56/*---------------------------------------------------------------------------*/
57/*---------------------------------------------------------------------------*/
58
59//! Returns the max of uniqueId() of entities in a group
60Int64 CartesianMeshCoarsening2::
61_getMaxUniqueId(const ItemGroup& group)
62{
63 Int64 max_offset = 0;
64 ENUMERATE_ (Item, iitem, group) {
65 Item item = *iitem;
66 if (max_offset < item.uniqueId())
67 max_offset = item.uniqueId();
68 }
69 return max_offset;
70}
71
72/*---------------------------------------------------------------------------*/
73/*---------------------------------------------------------------------------*/
74
75void CartesianMeshCoarsening2::
76_writeMeshSVG(const String& name)
77{
78 if (m_verbosity_level <= 0)
79 return;
80 IMesh* mesh = m_cartesian_mesh->mesh();
81 if (mesh->dimension() != 2)
82 return;
83 IParallelMng* pm = mesh->parallelMng();
84 const Int32 mesh_rank = pm->commRank();
85 String filename = String::format("mesh_{0}_{1}.svg", name, mesh_rank);
86 info() << "WriteMesh name=" << filename;
87 std::ofstream ofile(filename.localstr());
88 SimpleSVGMeshExporter writer(ofile);
89 writer.write(mesh->allCells());
90}
91
92/*---------------------------------------------------------------------------*/
93/*---------------------------------------------------------------------------*/
94/*!
95 * \brief Doubles the ghost layer of the initial mesh.
96 *
97 * This will then allow for the correct cell ghost layer value for the final coarse mesh.
98 */
99void CartesianMeshCoarsening2::
100_doDoubleGhostLayers()
101{
102 IMesh* mesh = m_cartesian_mesh->mesh();
103 IMeshModifier* mesh_modifier = mesh->modifier();
104 IGhostLayerMng* gm = mesh->ghostLayerMng();
105 // We must at least use version 3 to support
106 // multiple cell ghost layers
107 Int32 version = gm->builderVersion();
108 if (version < 3)
109 gm->setBuilderVersion(3);
110 Int32 nb_ghost_layer = gm->nbGhostLayer();
111 gm->setNbGhostLayer(nb_ghost_layer * 2);
112 mesh_modifier->setDynamic(true);
113 mesh_modifier->updateGhostLayers();
114 // Restores the initial number of ghost layers
115 gm->setNbGhostLayer(nb_ghost_layer);
116
117 // Since the number of entities has been modified, we must recalculate the directions
118 m_cartesian_mesh->computeDirections();
119
120 // Writes the new mesh
121 _writeMeshSVG("double_ghost");
122}
123
124/*---------------------------------------------------------------------------*/
125/*---------------------------------------------------------------------------*/
126
127void CartesianMeshCoarsening2::
128createCoarseCells()
129{
130 if (m_is_create_coarse_called)
131 ARCANE_FATAL("This method has already been called");
132 m_is_create_coarse_called = true;
133
134 const bool is_verbose = m_verbosity_level > 0;
135 IMesh* mesh = m_cartesian_mesh->mesh();
136 IParallelMng* pm = mesh->parallelMng();
137 Integer nb_patch = m_cartesian_mesh->nbPatch();
138 if (nb_patch != 1)
139 ARCANE_FATAL("This method is only valid for 1 patch (nb_patch={0})", nb_patch);
140
141 if (!mesh->isAmrActivated())
142 ARCANE_FATAL("AMR is not activated for this case");
143
144 Integer nb_dir = mesh->dimension();
145 if (nb_dir != 2 && nb_dir != 3)
146 ARCANE_FATAL("This method is only valid for 2D or 3D mesh (dim={0})", nb_dir);
147
148 info() << "CoarseCartesianMesh nb_direction=" << nb_dir;
149
150 for (Integer idir = 0; idir < nb_dir; ++idir) {
151 CellDirectionMng cdm(m_cartesian_mesh->cellDirection(idir));
152 Int32 nb_own_cell = cdm.ownNbCell();
153 info() << "NB_OWN_CELL dir=" << idir << " n=" << nb_own_cell;
154 if ((nb_own_cell % 2) != 0)
155 ARCANE_FATAL("Invalid number of cells ({0}) for direction {1}. Should be a multiple of 2",
156 nb_own_cell, idir);
157 }
158
159 _writeMeshSVG("orig");
160
161 // Doubles the ghost layer
162 _doDoubleGhostLayers();
163
164 if (is_verbose) {
166 ENUMERATE_ (Cell, icell, mesh->allCells()) {
167 Cell cell = *icell;
168 info() << "Orig cell=" << ItemPrinter(cell) << " Face0=" << cell.face(0).uniqueId()
169 << " Face1=" << cell.face(1).uniqueId() << " level=" << cell.level();
170 Int32 nb_node = cell.nbNode();
171 uids.resize(nb_node);
172 for (Int32 i = 0; i < nb_node; ++i)
173 uids[i] = cell.node(i).uniqueId();
174 info() << "Orig cell_uid=" << cell.uniqueId() << " Nodes=" << uids;
175 Int32 nb_face = cell.nbFace();
176 uids.resize(nb_face);
177 for (Int32 i = 0; i < nb_face; ++i)
178 uids[i] = cell.face(i).uniqueId();
179 info() << "Orig cell_uid=" << cell.uniqueId() << " Faces=" << uids;
180 }
181 }
182
183 // Calculate the offset for creating uniqueIds().
184 // We take the max of the uniqueIds() of faces and cells as the offset.
185 // Eventually, with Cartesian numbering everywhere, we will be able to determine
186 // this value directly
187 Int64 max_cell_uid = _getMaxUniqueId(mesh->allCells());
188 Int64 max_face_uid = _getMaxUniqueId(mesh->allFaces());
189 const Int64 coarse_grid_cell_offset = 1 + pm->reduce(Parallel::ReduceMax, math::max(max_cell_uid, max_face_uid));
190 m_first_own_cell_unique_id_offset = coarse_grid_cell_offset;
191 info() << "FirstCellUniqueIdOffset=" << m_first_own_cell_unique_id_offset;
192 if (nb_dir == 3)
193 _createCoarseCells3D();
194 else if (nb_dir == 2)
195 _createCoarseCells2D();
196 else
197 ARCANE_FATAL("Invalid dimension '{0}'", nb_dir);
198
199 mesh->modifier()->endUpdate();
200
201 if (is_verbose) {
202 ENUMERATE_ (Cell, icell, mesh->allCells()) {
203 Cell cell = *icell;
204 info() << "Final cell=" << ItemPrinter(cell) << " Face0=" << cell.face(0).uniqueId()
205 << " Face1=" << cell.face(1).uniqueId() << " level=" << cell.level();
206 }
207 }
208
209 _recomputeMeshGenerationInfo();
210
211 // Displays the statistics of the new mesh
212 {
213 MeshStats ms(traceMng(), mesh, mesh->parallelMng());
214 ms.dumpStats();
215 }
216
217 //! Creates the patch with the child cells
218 {
219 CellGroup parent_cells = mesh->allLevelCells(0);
220 m_cartesian_mesh->_internalApi()->addPatchFromExistingChildren(parent_cells.view().localIds());
221 }
222
223 // Recalculates the synchronization information
224 // This is not necessary for AMR because this information will be recalculated
225 // during refinement, but since we don't know if we will refine
226 // afterwards, it is better to calculate this information in all cases.
227 mesh->computeSynchronizeInfos();
228
229 // We must recalculate the new directions after the modifications
230 // and the addition of the patch.
231 m_cartesian_mesh->computeDirections();
232
233 _writeMeshSVG("coarse");
234}
235
236/*---------------------------------------------------------------------------*/
237/*---------------------------------------------------------------------------*/
238
239void CartesianMeshCoarsening2::
240_createCoarseCells2D()
241{
242 const bool is_verbose = m_verbosity_level > 0;
243 IMesh* mesh = m_cartesian_mesh->mesh();
244 IParallelMng* pm = mesh->parallelMng();
245 const Int32 my_rank = pm->commRank();
246
247 CellDirectionMng cdm_x(m_cartesian_mesh->cellDirection(0));
248 CellDirectionMng cdm_y(m_cartesian_mesh->cellDirection(1));
249
250 const Int64 global_nb_cell_x = cdm_x.globalNbCell();
251 const Int64 global_nb_cell_y = cdm_y.globalNbCell();
252 CartesianGridDimension refined_grid_dim(global_nb_cell_x, global_nb_cell_y);
253 CartesianGridDimension coarse_grid_dim(global_nb_cell_x / 2, global_nb_cell_y / 2);
254 CartesianGridDimension::CellUniqueIdComputer2D refined_cell_uid_computer(refined_grid_dim.getCellComputer2D(0));
255 CartesianGridDimension::NodeUniqueIdComputer2D refined_node_uid_computer(refined_grid_dim.getNodeComputer2D(0));
256 CartesianGridDimension::CellUniqueIdComputer2D coarse_cell_uid_computer(coarse_grid_dim.getCellComputer2D(m_first_own_cell_unique_id_offset));
257 CartesianGridDimension::FaceUniqueIdComputer2D coarse_face_uid_computer(coarse_grid_dim.getFaceComputer2D(m_first_own_cell_unique_id_offset));
258
259 // For the coarse cells and faces, the nodes already exist
260 // Therefore, we cannot use the Cartesian connectivity of the coarse grid
261 // for them (we can do this when patch-based AMR with duplication is active)
262 // For now, we use the numbering of the refined grid.
263
264 // TODO: Calculate the number of faces and cells in advance and allocate accordingly.
265 UniqueArray<Int64> faces_infos;
266 UniqueArray<Int64> cells_infos;
267 Int32 nb_coarse_face = 0;
268 Int32 nb_coarse_cell = 0;
269 //! List of the first child of each coarse cell
270 UniqueArray<Cell> first_child_cells;
271
272 UniqueArray<Int64> refined_cells_lids;
273 UniqueArray<Int32> coarse_cells_owner;
274 UniqueArray<Int32> coarse_faces_owner;
275
276 ENUMERATE_ (Cell, icell, mesh->allCells()) {
277 Cell cell = *icell;
278 Int64 cell_uid = cell.uniqueId();
279 Int64x3 cell_xy = refined_cell_uid_computer.compute(cell_uid);
280 const Int64 cell_x = cell_xy.x;
281 const Int64 cell_y = cell_xy.y;
282 // Necessary for recalculating ghost cells. We consider these
283 // cells as if they were just refined.
285 // Since we coarsen by 2, we only take cells whose topological coordinates
286 // are even
287 if ((cell_x % 2) != 0 || (cell_y % 2) != 0)
288 continue;
289 if (is_verbose)
290 info() << "CellToCoarse refined_uid=" << cell_uid << " x=" << cell_x << " y=" << cell_y;
291 coarse_cells_owner.add(cell.owner());
292 const Int64 coarse_cell_x = cell_x / 2;
293 const Int64 coarse_cell_y = cell_y / 2;
294 std::array<Int64, 4> node_uids_container;
295 ArrayView<Int64> node_uids(node_uids_container);
296 node_uids[0] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 0);
297 node_uids[1] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 0);
298 node_uids[2] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 2);
299 node_uids[3] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 2);
300 if (is_verbose)
301 info() << "CELLNodes uid=" << node_uids;
302 std::array<Int64, 4> coarse_face_uids = coarse_face_uid_computer.computeForCell(coarse_cell_x, coarse_cell_y);
303 const ItemTypeInfo* cell_type = cell.typeInfo();
304 // Adds the 4 faces
305 for (Int32 z = 0; z < 4; ++z) {
306 ItemTypeInfo::LocalFace lface = cell_type->localFace(z);
307 faces_infos.add(IT_Line2);
308 faces_infos.add(coarse_face_uids[z]);
309 Int64 node_uid0 = node_uids[lface.node(0)];
310 Int64 node_uid1 = node_uids[lface.node(1)];
311
312 if (node_uid0 > node_uid1)
313 std::swap(node_uid0, node_uid1);
314 if (is_verbose)
315 info() << "ADD_FACE coarse_uid=" << coarse_face_uids[z] << " n0=" << node_uid0 << " n1=" << node_uid1;
316 faces_infos.add(node_uid0);
317 faces_infos.add(node_uid1);
318 ++nb_coarse_face;
319 }
320 // Adds the cell
321 {
322 cells_infos.add(IT_Quad4);
323 Int64 coarse_cell_uid = coarse_cell_uid_computer.compute(coarse_cell_x, coarse_cell_y);
324 cells_infos.add(coarse_cell_uid);
325 if (is_verbose)
326 info() << "CoarseCellUid=" << coarse_cell_uid;
327 m_coarse_cells_uid.add(coarse_cell_uid);
328 for (Int32 z = 0; z < 4; ++z)
329 cells_infos.add(node_uids[z]);
330 ++nb_coarse_cell;
331 first_child_cells.add(cell);
332 }
333 // From the first sub-cell, we can know the other 3
334 // because they are respectively to the right, upper right, and upper.
335 {
336 std::array<Int32, 4> sub_cell_lids_container;
337 ArrayView<Int32> sub_lids(sub_cell_lids_container);
338 Cell cell1 = cdm_x[cell].next();
339 // Checks the validity of the sub-cells.
340 // Normally there should be no problems unless the
341 // number of cells in each direction of the sub-domain
342 // is not an even number.
343 if (cell1.null())
344 ARCANE_FATAL("Bad right cell for cell {0}", ItemPrinter(cell));
345 Cell cell2 = cdm_y[cell1].next();
346 if (cell2.null())
347 ARCANE_FATAL("Bad upper right cell for cell {0}", ItemPrinter(cell));
348 Cell cell3 = cdm_y[cell].next();
349 if (cell3.null())
350 ARCANE_FATAL("Bad upper cell for cell {0}", ItemPrinter(cell));
351 sub_lids[0] = cell.localId();
352 sub_lids[1] = cell1.localId();
353 sub_lids[2] = cell2.localId();
354 sub_lids[3] = cell3.localId();
355 // We must assign an owner to the faces.
356 // These new faces will have the same owner as the refined faces
357 // they correspond to
358 //info() << "CELL_NB_FACE=" << cell.nbFace() << " " << cell1.nbFace() << " " << cell2.nbFace() << " " << cell3.nbFace();
359 coarse_faces_owner.add(cell.face(0).owner());
360 coarse_faces_owner.add(cell1.face(1).owner());
361 coarse_faces_owner.add(cell2.face(2).owner());
362 coarse_faces_owner.add(cell3.face(3).owner());
363 for (Int32 i = 0; i < 4; ++i)
364 refined_cells_lids.add(sub_lids[i]);
365 }
366 }
367
368 // Builds the faces
369 UniqueArray<Int32> faces_local_ids(nb_coarse_face);
370 mesh->modifier()->addFaces(nb_coarse_face, faces_infos, faces_local_ids);
371
372 // Builds the cells
373 // Indicates that we are not allowed to build the faces on the fly.
374 // Normally they have all been added via addFaces();
375 UniqueArray<Int32> cells_local_ids(nb_coarse_cell);
376 MeshModifierAddCellsArgs add_cells_args(nb_coarse_cell, cells_infos, cells_local_ids);
377 add_cells_args.setAllowBuildFaces(false);
378 mesh->modifier()->addCells(add_cells_args);
379
380 IItemFamily* cell_family = mesh->cellFamily();
381
382 // Now that the coarse cells are created, we must indicate
383 // that they are parent cells.
384 using mesh::CellFamily;
385 CellInfoListView cells(mesh->cellFamily());
386 CellFamily* true_cell_family = ARCANE_CHECK_POINTER(dynamic_cast<CellFamily*>(cell_family));
387 std::array<Int32, 4> sub_cell_lids_container;
388 ArrayView<Int32> sub_cell_lids(sub_cell_lids_container);
389 for (Int32 i = 0; i < nb_coarse_cell; ++i) {
390 Int32 coarse_cell_lid = cells_local_ids[i];
391 Cell coarse_cell = cells[coarse_cell_lid];
392 Cell first_child_cell = first_child_cells[i];
393 // Starting from the first sub-cell, we can know the other 3
394 // because they are respectively to the right, upper right, and upper.
395 sub_cell_lids[0] = first_child_cell.localId();
396 sub_cell_lids[1] = cdm_x[first_child_cell].next().localId();
397 sub_cell_lids[2] = cdm_y[CellLocalId(sub_cell_lids[1])].next().localId();
398 sub_cell_lids[3] = cdm_y[first_child_cell].next().localId();
399 if (is_verbose)
400 info() << "AddChildForCoarseCell i=" << i << " coarse=" << ItemPrinter(coarse_cell)
401 << " children_lid=" << sub_cell_lids;
402 for (Int32 z = 0; z < 4; ++z) {
403 Cell child_cell = cells[sub_cell_lids[z]];
404 if (is_verbose)
405 info() << " AddParentCellToCell: z=" << z << " child=" << ItemPrinter(child_cell);
406 true_cell_family->_addParentCellToCell(child_cell, coarse_cell);
407 }
408 true_cell_family->_addChildrenCellsToCell(coarse_cell, sub_cell_lids);
409 }
410
411 // Positions the owners of the new cells and faces
412 {
413 IItemFamily* face_family = mesh->faceFamily();
414 Int32 index = 0;
415 ENUMERATE_ (Cell, icell, cell_family->view(cells_local_ids)) {
416 Cell cell = *icell;
417 Int32 owner = coarse_cells_owner[index];
418 cell.mutableItemBase().setOwner(owner, my_rank);
419 const Int64 sub_cell_index = index * 4;
420 for (Int32 z = 0; z < 4; ++z) {
421 cell.face(z).mutableItemBase().setOwner(coarse_faces_owner[sub_cell_index + z], my_rank);
422 }
423 ++index;
424 }
425 cell_family->notifyItemsOwnerChanged();
426 face_family->notifyItemsOwnerChanged();
427 }
428}
429
430/*---------------------------------------------------------------------------*/
431/*---------------------------------------------------------------------------*/
432
433void CartesianMeshCoarsening2::
434_createCoarseCells3D()
435{
436 const bool is_verbose = m_verbosity_level > 0;
437 IMesh* mesh = m_cartesian_mesh->mesh();
438 IParallelMng* pm = mesh->parallelMng();
439 const Int32 my_rank = pm->commRank();
440
441 CellDirectionMng cdm_x(m_cartesian_mesh->cellDirection(0));
442 CellDirectionMng cdm_y(m_cartesian_mesh->cellDirection(1));
443 CellDirectionMng cdm_z(m_cartesian_mesh->cellDirection(2));
444
445 const Int64 global_nb_cell_x = cdm_x.globalNbCell();
446 const Int64 global_nb_cell_y = cdm_y.globalNbCell();
447 const Int64 global_nb_cell_z = cdm_z.globalNbCell();
448 CartesianGridDimension refined_grid_dim(global_nb_cell_x, global_nb_cell_y, global_nb_cell_z);
449 CartesianGridDimension coarse_grid_dim(global_nb_cell_x / 2, global_nb_cell_y / 2, global_nb_cell_z / 2);
450 CartesianGridDimension::CellUniqueIdComputer3D refined_cell_uid_computer(refined_grid_dim.getCellComputer3D(0));
451 CartesianGridDimension::NodeUniqueIdComputer3D refined_node_uid_computer(refined_grid_dim.getNodeComputer3D(0));
452 CartesianGridDimension::CellUniqueIdComputer3D coarse_cell_uid_computer(coarse_grid_dim.getCellComputer3D(m_first_own_cell_unique_id_offset));
453 CartesianGridDimension::FaceUniqueIdComputer3D coarse_face_uid_computer(coarse_grid_dim.getFaceComputer3D(m_first_own_cell_unique_id_offset));
454
455 // For the coarse cells and faces, the nodes already exist
456 // Therefore, we cannot use the Cartesian connectivity of the coarse grid
457 // for them (we can do that when AMR by patch with duplication is active)
458 // For now, we use the numbering of the refined grid.
459
460 // TODO: Calculate the number of faces and cells in advance and allocate accordingly.
461 UniqueArray<Int64> faces_infos;
462 UniqueArray<Int64> cells_infos;
463 Int32 nb_coarse_face = 0;
464 Int32 nb_coarse_cell = 0;
465 //! List of the first child of each coarse cell
466 UniqueArray<Cell> first_child_cells;
467
468 UniqueArray<Int64> refined_cells_lids;
469 UniqueArray<Int32> coarse_cells_owner;
470 UniqueArray<Int32> coarse_faces_owner;
471
472 static constexpr Int32 const_cell_nb_node = 8;
473 static constexpr Int32 const_cell_nb_face = 6;
474 static constexpr Int32 const_cell_nb_sub_cell = 8;
475 static constexpr Int32 const_face_nb_node = 4;
476
477 // List of uniqueId() of nodes of created faces
478 SmallArray<Int64, const_face_nb_node> face_node_uids(const_face_nb_node);
479 // Ordered list of nodes of created faces
480 SmallArray<Int64, const_face_nb_node> face_sorted_node_uids(const_face_nb_node);
481 ENUMERATE_ (Cell, icell, mesh->allCells()) {
482 Cell cell = *icell;
483 Int64 cell_uid = cell.uniqueId();
484 Int64x3 cell_xyz = refined_cell_uid_computer.compute(cell_uid);
485 const Int64 cell_x = cell_xyz.x;
486 const Int64 cell_y = cell_xyz.y;
487 const Int64 cell_z = cell_xyz.z;
488 // Necessary for ghost cells recalculation. We consider these
489 // cells as if they have just been refined.
490 cell.mutableItemBase().addFlags(ItemFlags::II_JustRefined);
491 // Since we refine by 2, only take cells whose topological coordinates
492 // are even
493 if ((cell_x % 2) != 0 || (cell_y % 2) != 0 || (cell_z % 2) != 0)
494 continue;
495 if (is_verbose)
496 info() << "CellToCoarse refined_uid=" << cell_uid << " x=" << cell_x << " y=" << cell_y << " z=" << cell_z;
497 coarse_cells_owner.add(cell.owner());
498 const Int64 coarse_cell_x = cell_x / 2;
499 const Int64 coarse_cell_y = cell_y / 2;
500 const Int64 coarse_cell_z = cell_z / 2;
501 std::array<Int64, const_cell_nb_node> node_uids_container;
502 ArrayView<Int64> node_uids(node_uids_container);
503 node_uids[0] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 0, cell_z + 0);
504 node_uids[1] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 0, cell_z + 0);
505 node_uids[2] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 2, cell_z + 0);
506 node_uids[3] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 2, cell_z + 0);
507 node_uids[4] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 0, cell_z + 2);
508 node_uids[5] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 0, cell_z + 2);
509 node_uids[6] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 2, cell_z + 2);
510 node_uids[7] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 2, cell_z + 2);
511 if (is_verbose)
512 info() << "CELLNodes uid=" << node_uids;
513 std::array<Int64, const_cell_nb_face> coarse_face_uids = coarse_face_uid_computer.computeForCell(coarse_cell_x, coarse_cell_y, coarse_cell_z);
514 const ItemTypeInfo* cell_type = cell.typeInfo();
515
516 // Add the 6 faces
517 for (Int32 z = 0; z < const_cell_nb_face; ++z) {
518 ItemTypeInfo::LocalFace lface = cell_type->localFace(z);
519 faces_infos.add(IT_Quad4);
520 faces_infos.add(coarse_face_uids[z]);
521 for (Int32 knode = 0; knode < const_face_nb_node; ++knode)
522 face_node_uids[knode] = node_uids[lface.node(knode)];
523 MeshUtils::reorderNodesOfFace(face_node_uids, face_sorted_node_uids);
524 if (is_verbose)
525 info() << "ADD_FACE coarse_uid=" << coarse_face_uids[z] << " n=" << face_sorted_node_uids;
526 faces_infos.addRange(face_sorted_node_uids);
527 ++nb_coarse_face;
528 }
529
530 // Add the cell
531 {
532 cells_infos.add(IT_Hexaedron8);
533 Int64 coarse_cell_uid = coarse_cell_uid_computer.compute(coarse_cell_x, coarse_cell_y, coarse_cell_z);
534 cells_infos.add(coarse_cell_uid);
535 if (is_verbose)
536 info() << "CoarseCellUid=" << coarse_cell_uid;
537 m_coarse_cells_uid.add(coarse_cell_uid);
538 for (Int32 z = 0; z < const_cell_nb_node; ++z)
539 cells_infos.add(node_uids[z]);
540 ++nb_coarse_cell;
541 first_child_cells.add(cell);
542 }
543
544 // Starting from the first sub-cell, we can know the other 7
545 // because they are respectively to the right, upper right, and upper,
546 // above, above right, above upper right and .
547 {
548 std::array<Int32, const_cell_nb_sub_cell> sub_cell_lids_container;
549 ArrayView<Int32> sub_lids(sub_cell_lids_container);
550 Cell cell1 = cdm_x[cell].next();
551 // Checks the validity of the sub-cells.
552 // Normally there should be no problems unless the
553 // number of cells in each direction of the sub-domain
554 // is not an even number.
555 if (cell1.null())
556 ARCANE_FATAL("Bad right cell for cell {0}", ItemPrinter(cell));
557 Cell cell2 = cdm_y[cell1].next();
558 if (cell2.null())
559 ARCANE_FATAL("Bad upper right cell for cell {0}", ItemPrinter(cell));
560 Cell cell3 = cdm_y[cell].next();
561 if (cell3.null())
562 ARCANE_FATAL("Bad upper cell for cell {0}", ItemPrinter(cell));
563
564 Cell cell4 = cdm_z[cell].next();
565 if (cell4.null())
566 ARCANE_FATAL("Bad top cell for cell {0}", ItemPrinter(cell));
567
568 Cell cell5 = cdm_x[cell4].next();
569 if (cell5.null())
570 ARCANE_FATAL("Bad top right cell for cell {0}", ItemPrinter(cell));
571 Cell cell6 = cdm_y[cell5].next();
572 if (cell6.null())
573 ARCANE_FATAL("Bad top upper right cell for cell {0}", ItemPrinter(cell));
574 Cell cell7 = cdm_y[cell4].next();
575 if (cell7.null())
576 ARCANE_FATAL("Bad top upper cell for cell {0}", ItemPrinter(cell));
577
578 sub_lids[0] = cell.localId();
579 sub_lids[1] = cell1.localId();
580 sub_lids[2] = cell2.localId();
581 sub_lids[3] = cell3.localId();
582 sub_lids[4] = cell4.localId();
583 sub_lids[5] = cell5.localId();
584 sub_lids[6] = cell6.localId();
585 sub_lids[7] = cell7.localId();
586 // We need to assign an owner to the faces.
587 // These new faces will have the same owner as the refined faces
588 // they correspond to
589 //info() << "CELL_NB_FACE=" << cell.nbFace() << " " << cell1.nbFace() << " " << cell2.nbFace() << " " << cell3.nbFace();
590 coarse_faces_owner.add(cell.face(0).owner());
591 coarse_faces_owner.add(cell1.face(1).owner());
592 coarse_faces_owner.add(cell2.face(2).owner());
593 coarse_faces_owner.add(cell3.face(3).owner());
594
595 coarse_faces_owner.add(cell4.face(4).owner());
596 coarse_faces_owner.add(cell5.face(5).owner());
597
598 for (Int32 i = 0; i < const_cell_nb_sub_cell; ++i)
599 refined_cells_lids.add(sub_lids[i]);
600 }
601 }
602
603 // Constructs the faces
604 UniqueArray<Int32> faces_local_ids(nb_coarse_face);
605 mesh->modifier()->addFaces(nb_coarse_face, faces_infos, faces_local_ids);
606
607 // Constructs the cells
608 // Indicates that we do not have the right to build faces on the fly.
609 // Normally they have all been added via addFaces();
610 UniqueArray<Int32> cells_local_ids(nb_coarse_cell);
611 MeshModifierAddCellsArgs add_cells_args(nb_coarse_cell, cells_infos, cells_local_ids);
612 add_cells_args.setAllowBuildFaces(false);
613 mesh->modifier()->addCells(add_cells_args);
614
615 IItemFamily* cell_family = mesh->cellFamily();
616
617 // Now that the coarse cells are created, we must indicate
618 // that they are parent cells.
619 using mesh::CellFamily;
620 CellInfoListView cells(mesh->cellFamily());
621 CellFamily* true_cell_family = ARCANE_CHECK_POINTER(dynamic_cast<CellFamily*>(cell_family));
622 std::array<Int32, const_cell_nb_sub_cell> sub_cell_lids_container;
623 ArrayView<Int32> sub_cell_lids(sub_cell_lids_container);
624 for (Int32 i = 0; i < nb_coarse_cell; ++i) {
625 Int32 coarse_cell_lid = cells_local_ids[i];
626 Cell coarse_cell = cells[coarse_cell_lid];
627 Cell first_child_cell = first_child_cells[i];
628 // Starting from the first sub-cell, we can know the other 3
629 // because they are respectively to the right, upper right, and upper.
630 sub_cell_lids[0] = first_child_cell.localId();
631 sub_cell_lids[1] = cdm_x[first_child_cell].next().localId();
632 sub_cell_lids[2] = cdm_y[CellLocalId(sub_cell_lids[1])].next().localId();
633 sub_cell_lids[3] = cdm_y[first_child_cell].next().localId();
634
635 Cell top_first_child_cell = cdm_z[first_child_cell].next();
636 sub_cell_lids[4] = top_first_child_cell.localId();
637 sub_cell_lids[5] = cdm_x[top_first_child_cell].next().localId();
638 sub_cell_lids[6] = cdm_y[CellLocalId(sub_cell_lids[5])].next().localId();
639 sub_cell_lids[7] = cdm_y[top_first_child_cell].next().localId();
640
641 if (is_verbose)
642 info() << "AddChildForCoarseCell i=" << i << " coarse=" << ItemPrinter(coarse_cell)
643 << " children_lid=" << sub_cell_lids;
644 for (Int32 z = 0; z < const_cell_nb_sub_cell; ++z) {
645 Cell child_cell = cells[sub_cell_lids[z]];
646 if (is_verbose)
647 info() << " AddParentCellToCell: z=" << z << " child=" << ItemPrinter(child_cell);
648 true_cell_family->_addParentCellToCell(child_cell, coarse_cell);
649 }
650 true_cell_family->_addChildrenCellsToCell(coarse_cell, sub_cell_lids);
651 }
652
653 // Positions the owners of the new cells and faces
654 {
655 IItemFamily* face_family = mesh->faceFamily();
656 Int32 index = 0;
657 ENUMERATE_ (Cell, icell, cell_family->view(cells_local_ids)) {
658 Cell cell = *icell;
659 Int32 owner = coarse_cells_owner[index];
660 cell.mutableItemBase().setOwner(owner, my_rank);
661 const Int64 sub_cell_index = index * const_cell_nb_face;
662 for (Int32 z = 0; z < const_cell_nb_face; ++z) {
663 cell.face(z).mutableItemBase().setOwner(coarse_faces_owner[sub_cell_index + z], my_rank);
664 }
665 ++index;
666 }
667 cell_family->notifyItemsOwnerChanged();
668 face_family->notifyItemsOwnerChanged();
669 }
670}
671
672/*---------------------------------------------------------------------------*/
673/*---------------------------------------------------------------------------*/
674
675/*!
676 * \brief Recalculates the information about the number of cells per direction.
677 */
678void CartesianMeshCoarsening2::
679_recomputeMeshGenerationInfo()
680{
681 IMesh* mesh = m_cartesian_mesh->mesh();
682 auto* cmgi = ICartesianMeshGenerationInfo::getReference(mesh, false);
683 if (!cmgi)
684 return;
685
686 // Refinement coefficient
687 const Int32 cf = 2;
688
689 {
690 ConstArrayView<Int64> v = cmgi->ownCellOffsets();
691 cmgi->setOwnCellOffsets(v[0] / cf, v[1] / cf, v[2] / cf);
692 }
693 {
694 ConstArrayView<Int64> v = cmgi->globalNbCells();
695 cmgi->setGlobalNbCells(v[0] / cf, v[1] / cf, v[2] / cf);
696 }
697 {
698 ConstArrayView<Int32> v = cmgi->ownNbCells();
699 cmgi->setOwnNbCells(v[0] / cf, v[1] / cf, v[2] / cf);
700 }
701 cmgi->setFirstOwnCellUniqueId(m_first_own_cell_unique_id_offset);
702}
703
704/*---------------------------------------------------------------------------*/
705/*---------------------------------------------------------------------------*/
706
707void CartesianMeshCoarsening2::
708removeRefinedCells()
709{
710 if (!m_is_create_coarse_called)
711 ARCANE_FATAL("You need to call createCoarseCells() before");
712 if (m_is_remove_refined_called)
713 ARCANE_FATAL("This method has already been called");
714 m_is_remove_refined_called = true;
715
716 const bool is_verbose = m_verbosity_level > 0;
717
718 IMesh* mesh = m_cartesian_mesh->mesh();
719 IMeshModifier* mesh_modifier = mesh->modifier();
720
721 info() << "RemoveRefinedCells nb_coarse_cell=" << m_coarse_cells_uid.size();
722 if (is_verbose)
723 info() << "CoarseCells=" << m_coarse_cells_uid;
724
725 // Remove all refined cells as well as all ghost cells
726 {
727 std::unordered_set<Int64> coarse_cells_set;
728 for (Int64 cell_uid : m_coarse_cells_uid)
729 coarse_cells_set.insert(cell_uid);
730 UniqueArray<Int32> cells_to_remove;
731 ENUMERATE_ (Cell, icell, mesh->allCells()) {
732 Int32 local_id = icell.itemLocalId();
733 Cell cell = *icell;
734 if (coarse_cells_set.find(cell.uniqueId()) == coarse_cells_set.end())
735 cells_to_remove.add(local_id);
736 }
737 if (is_verbose)
738 info() << "CellsToRemove n=" << cells_to_remove.size() << " list=" << cells_to_remove;
739 mesh_modifier->removeCells(cells_to_remove);
740 mesh_modifier->endUpdate();
741 }
742
743 // Reconstruct ghost cells
744 mesh_modifier->setDynamic(true);
745 mesh_modifier->updateGhostLayers();
746
747 // Display statistics of the new mesh
748 {
749 MeshStats ms(traceMng(), mesh, mesh->parallelMng());
750 ms.dumpStats();
751 }
752
753 // We must recalculate the new directions
754 m_cartesian_mesh->computeDirections();
755}
756
757/*---------------------------------------------------------------------------*/
758/*---------------------------------------------------------------------------*/
759
760} // End namespace Arcane
761
762/*---------------------------------------------------------------------------*/
763/*---------------------------------------------------------------------------*/
#define ARCANE_CHECK_POINTER(ptr)
Macro returning the pointer ptr if it is not null or throwing an exception if it is null.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
#define ENUMERATE_(type, name, group)
Generic enumerator for an entity group.
Modifiable view of an array of type T.
void resize(Int64 s)
Changes the number of elements in the array to s.
void add(ConstReferenceType val)
Adds element val to the end of the array.
Information about the dimensions of a Cartesian grid.
Info about the cells in a specific X, Y, or Z direction of a structured mesh.
Int32 ownNbCell() const
Number of own cells in this direction.
Cell of a mesh.
Definition Item.h:1300
Face face(Int32 i) const
i-th face of the cell
Definition Item.h:1400
Int32 nbFace() const
Number of faces of the cell.
Definition Item.h:1397
Int32 level() const
Definition Item.h:1473
virtual IItemFamily * faceFamily()=0
Returns the face family.
virtual IItemFamily * cellFamily()=0
Returns the cell family.
virtual void addFaces(Integer nb_face, Int64ConstArrayView face_infos, Int32ArrayView face_lids=Int32ArrayView())=0
Adds faces.
virtual void addCells(Integer nb_cell, Int64ConstArrayView cell_infos, Int32ArrayView cells_lid=Int32ArrayView())=0
Adds cells.
virtual IMeshModifier * modifier()=0
Associated modifier interface.
Interface of the parallelism manager for a subdomain.
virtual Int32 commRank() const =0
Rank of this instance in the communicator.
virtual char reduce(eReduceType rt, char v)=0
Performs a reduction of type rt on the real v and returns the value.
@ II_JustRefined
The entity has just been refined.
Definition ItemFlags.h:78
ItemVectorView view() const
View of the group entities.
Definition ItemGroup.cc:580
Utility class for printing information about an entity.
Definition ItemPrinter.h:35
Local information about a cell face.
Integer node(Integer i) const
Local index in the cell of the i-th node of the face.
Info on a mesh entity type.
LocalFace localFace(Integer id) const
Local connectivity of the i-th face of the cell.
Int32ConstArrayView localIds() const
Array of local IDs of entities.
Node node(Int32 i) const
i-th node of the entity
Definition Item.h:840
Int32 nbNode() const
Number of nodes of the entity.
Definition Item.h:837
const ItemTypeInfo * typeInfo() const
Information about the entity type.
Definition Item.h:406
impl::MutableItemBase mutableItemBase() const
Mutable internal part of the entity.
Definition Item.h:394
constexpr Int32 localId() const
Local identifier of the entity in the processor subdomain.
Definition Item.h:233
Int32 owner() const
Owner subdomain number of the entity.
Definition Item.h:252
ItemUniqueId uniqueId() const
Unique identifier across all domains.
Definition Item.h:239
void dumpStats() override
Prints mesh information.
Definition MeshStats.cc:63
void addFlags(Int32 added_flags)
Adds the flags added_flags to those of the entity.
1D data array with pre-allocated stack buffer.
TraceMessage info() const
Flow for an information message.
ITraceMng * traceMng() const
Trace manager.
1D data vector with value semantics (STL style).
T max(const T &a, const T &b, const T &c)
Returns the maximum of three elements.
Definition MathUtils.h:407
ItemGroupT< Cell > CellGroup
Group of cells.
Definition ItemTypes.h:184
@ ReduceMax
Maximum of values.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
@ Cell
The mesh is AMR by cell.
Definition MeshKind.h:53
std::int32_t Int32
Signed integer type of 32 bits.