Arcane  v3.16.0.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
CartesianMeshCoarsening2.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2024 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/* Déraffinement d'un maillage cartésien. */
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
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/*---------------------------------------------------------------------------*/
100void CartesianMeshCoarsening2::
101_doDoubleGhostLayers()
102{
103 IMesh* mesh = m_cartesian_mesh->mesh();
104 IMeshModifier* mesh_modifier = mesh->modifier();
105 IGhostLayerMng* gm = mesh->ghostLayerMng();
106 // Il faut au moins utiliser la version 3 pour pouvoir supporter
107 // plusieurs couches de mailles fantômes
108 Int32 version = gm->builderVersion();
109 if (version < 3)
110 gm->setBuilderVersion(3);
111 Int32 nb_ghost_layer = gm->nbGhostLayer();
112 gm->setNbGhostLayer(nb_ghost_layer * 2);
113 mesh_modifier->setDynamic(true);
114 mesh_modifier->updateGhostLayers();
115 // Remet le nombre initial de couches de mailles fantômes
116 gm->setNbGhostLayer(nb_ghost_layer);
117
118 // Comme le nombre d'entités a été modifié, il faut recalculer les directions
119 m_cartesian_mesh->computeDirections();
120
121 // Écrit le nouveau maillage
122 _writeMeshSVG("double_ghost");
123}
124
125/*---------------------------------------------------------------------------*/
126/*---------------------------------------------------------------------------*/
127
128void CartesianMeshCoarsening2::
129createCoarseCells()
130{
131 if (m_is_create_coarse_called)
132 ARCANE_FATAL("This method has already been called");
133 m_is_create_coarse_called = true;
134
135 const bool is_verbose = m_verbosity_level > 0;
136 IMesh* mesh = m_cartesian_mesh->mesh();
137 IParallelMng* pm = mesh->parallelMng();
138 Integer nb_patch = m_cartesian_mesh->nbPatch();
139 if (nb_patch != 1)
140 ARCANE_FATAL("This method is only valid for 1 patch (nb_patch={0})", nb_patch);
141
142 if (!mesh->isAmrActivated())
143 ARCANE_FATAL("AMR is not activated for this case");
144
145 Integer nb_dir = mesh->dimension();
146 if (nb_dir != 2 && nb_dir != 3)
147 ARCANE_FATAL("This method is only valid for 2D or 3D mesh (dim={0})", nb_dir);
148
149 info() << "CoarseCartesianMesh nb_direction=" << nb_dir;
150
151 for (Integer idir = 0; idir < nb_dir; ++idir) {
152 CellDirectionMng cdm(m_cartesian_mesh->cellDirection(idir));
153 Int32 nb_own_cell = cdm.ownNbCell();
154 info() << "NB_OWN_CELL dir=" << idir << " n=" << nb_own_cell;
155 if ((nb_own_cell % 2) != 0)
156 ARCANE_FATAL("Invalid number of cells ({0}) for direction {1}. Should be a multiple of 2",
157 nb_own_cell, idir);
158 }
159
160 _writeMeshSVG("orig");
161
162 // Double la couche de mailles fantômes
164
165 if (is_verbose) {
167 ENUMERATE_ (Cell, icell, mesh->allCells()) {
168 Cell cell = *icell;
169 info() << "Orig cell=" << ItemPrinter(cell) << " Face0=" << cell.face(0).uniqueId()
170 << " Face1=" << cell.face(1).uniqueId() << " level=" << cell.level();
171 Int32 nb_node = cell.nbNode();
172 uids.resize(nb_node);
173 for (Int32 i = 0; i < nb_node; ++i)
174 uids[i] = cell.node(i).uniqueId();
175 info() << "Orig cell_uid=" << cell.uniqueId() << " Nodes=" << uids;
176 Int32 nb_face = cell.nbFace();
177 uids.resize(nb_face);
178 for (Int32 i = 0; i < nb_face; ++i)
179 uids[i] = cell.face(i).uniqueId();
180 info() << "Orig cell_uid=" << cell.uniqueId() << " Faces=" << uids;
181 }
182 }
183
184 // Calcul l'offset pour la création des uniqueId().
185 // On prend comme offset le max des uniqueId() des faces et des mailles.
186 // A terme avec la numérotation cartésienne partout, on pourra déterminer
187 // directement cette valeur
188 Int64 max_cell_uid = _getMaxUniqueId(mesh->allCells());
189 Int64 max_face_uid = _getMaxUniqueId(mesh->allFaces());
190 const Int64 coarse_grid_cell_offset = 1 + pm->reduce(Parallel::ReduceMax, math::max(max_cell_uid, max_face_uid));
191 m_first_own_cell_unique_id_offset = coarse_grid_cell_offset;
192 info() << "FirstCellUniqueIdOffset=" << m_first_own_cell_unique_id_offset;
193 if (nb_dir == 3)
195 else if (nb_dir == 2)
197 else
198 ARCANE_FATAL("Invalid dimension '{0}'", nb_dir);
199
200 mesh->modifier()->endUpdate();
201
202 if (is_verbose) {
203 ENUMERATE_ (Cell, icell, mesh->allCells()) {
204 Cell cell = *icell;
205 info() << "Final cell=" << ItemPrinter(cell) << " Face0=" << cell.face(0).uniqueId()
206 << " Face1=" << cell.face(1).uniqueId() << " level=" << cell.level();
207 }
208 }
209
211
212 // Affiche les statistiques du nouveau maillage
213 {
214 MeshStats ms(traceMng(), mesh, mesh->parallelMng());
215 ms.dumpStats();
216 }
217
219 {
220 CellGroup parent_cells = mesh->allLevelCells(0);
221 m_cartesian_mesh->_internalApi()->addPatchFromExistingChildren(parent_cells.view().localIds());
222 }
223
224 // Recalcule les informations de synchronisation
225 // Cela n'est pas nécessaire pour l'AMR car ces informations seront recalculées
226 // lors du raffinement mais comme on ne sais pas si on va faire du raffinement
227 // après il est préférable de calculer ces informations dans tous les cas.
228 mesh->computeSynchronizeInfos();
229
230 // Il faut recalculer les nouvelles directions après les modifications
231 // et l'ajout de patch.
232 m_cartesian_mesh->computeDirections();
233
234 _writeMeshSVG("coarse");
235}
236
237/*---------------------------------------------------------------------------*/
238/*---------------------------------------------------------------------------*/
239
240void CartesianMeshCoarsening2::
241_createCoarseCells2D()
242{
243 const bool is_verbose = m_verbosity_level > 0;
244 IMesh* mesh = m_cartesian_mesh->mesh();
245 IParallelMng* pm = mesh->parallelMng();
246 const Int32 my_rank = pm->commRank();
247
248 CellDirectionMng cdm_x(m_cartesian_mesh->cellDirection(0));
249 CellDirectionMng cdm_y(m_cartesian_mesh->cellDirection(1));
250
251 const Int64 global_nb_cell_x = cdm_x.globalNbCell();
252 const Int64 global_nb_cell_y = cdm_y.globalNbCell();
253 CartesianGridDimension refined_grid_dim(global_nb_cell_x, global_nb_cell_y);
254 CartesianGridDimension coarse_grid_dim(global_nb_cell_x / 2, global_nb_cell_y / 2);
255 CartesianGridDimension::CellUniqueIdComputer2D refined_cell_uid_computer(refined_grid_dim.getCellComputer2D(0));
256 CartesianGridDimension::NodeUniqueIdComputer2D refined_node_uid_computer(refined_grid_dim.getNodeComputer2D(0));
257 CartesianGridDimension::CellUniqueIdComputer2D coarse_cell_uid_computer(coarse_grid_dim.getCellComputer2D(m_first_own_cell_unique_id_offset));
258 CartesianGridDimension::FaceUniqueIdComputer2D coarse_face_uid_computer(coarse_grid_dim.getFaceComputer2D(m_first_own_cell_unique_id_offset));
259
260 // Pour les mailles et faces grossières, les noeuds existent déjà
261 // On ne peut donc pas utiliser la connectivité cartésienne de la grille grossière
262 // pour eux (on pourra le faire lorsque l'AMR par patch avec duplication sera active)
263 // En attendant on utilise la numérotation de la grille raffinée.
264
265 // TODO: Calculer en avance le nombre de faces et de mailles et allouer en conséquence.
266 UniqueArray<Int64> faces_infos;
267 UniqueArray<Int64> cells_infos;
268 Int32 nb_coarse_face = 0;
269 Int32 nb_coarse_cell = 0;
271 UniqueArray<Cell> first_child_cells;
272
273 UniqueArray<Int64> refined_cells_lids;
274 UniqueArray<Int32> coarse_cells_owner;
275 UniqueArray<Int32> coarse_faces_owner;
276
277 ENUMERATE_ (Cell, icell, mesh->allCells()) {
278 Cell cell = *icell;
279 Int64 cell_uid = cell.uniqueId();
280 Int64x3 cell_xy = refined_cell_uid_computer.compute(cell_uid);
281 const Int64 cell_x = cell_xy.x;
282 const Int64 cell_y = cell_xy.y;
283 // Nécessaire pour le recalcul des mailles fantômes. On considère ces
284 // mailles comme si elles venaient juste d'être raffinées.
286 // Comme on déraffine par 2, ne prend que les mailles dont les coordoonnées
287 // topologiques sont paires
288 if ((cell_x % 2) != 0 || (cell_y % 2) != 0)
289 continue;
290 if (is_verbose)
291 info() << "CellToCoarse refined_uid=" << cell_uid << " x=" << cell_x << " y=" << cell_y;
292 coarse_cells_owner.add(cell.owner());
293 const Int64 coarse_cell_x = cell_x / 2;
294 const Int64 coarse_cell_y = cell_y / 2;
295 std::array<Int64, 4> node_uids_container;
296 ArrayView<Int64> node_uids(node_uids_container);
297 node_uids[0] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 0);
298 node_uids[1] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 0);
299 node_uids[2] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 2);
300 node_uids[3] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 2);
301 if (is_verbose)
302 info() << "CELLNodes uid=" << node_uids;
303 std::array<Int64, 4> coarse_face_uids = coarse_face_uid_computer.computeForCell(coarse_cell_x, coarse_cell_y);
304 const ItemTypeInfo* cell_type = cell.typeInfo();
305 // Ajoute les 4 faces
306 for (Int32 z = 0; z < 4; ++z) {
307 ItemTypeInfo::LocalFace lface = cell_type->localFace(z);
308 faces_infos.add(IT_Line2);
309 faces_infos.add(coarse_face_uids[z]);
310 Int64 node_uid0 = node_uids[lface.node(0)];
311 Int64 node_uid1 = node_uids[lface.node(1)];
312
313 if (node_uid0 > node_uid1)
314 std::swap(node_uid0, node_uid1);
315 if (is_verbose)
316 info() << "ADD_FACE coarse_uid=" << coarse_face_uids[z] << " n0=" << node_uid0 << " n1=" << node_uid1;
317 faces_infos.add(node_uid0);
318 faces_infos.add(node_uid1);
319 ++nb_coarse_face;
320 }
321 // Ajoute la maille
322 {
323 cells_infos.add(IT_Quad4);
324 Int64 coarse_cell_uid = coarse_cell_uid_computer.compute(coarse_cell_x, coarse_cell_y);
325 cells_infos.add(coarse_cell_uid);
326 if (is_verbose)
327 info() << "CoarseCellUid=" << coarse_cell_uid;
328 m_coarse_cells_uid.add(coarse_cell_uid);
329 for (Int32 z = 0; z < 4; ++z)
330 cells_infos.add(node_uids[z]);
331 ++nb_coarse_cell;
332 first_child_cells.add(cell);
333 }
334 // A partir de la première sous-maille, on peut connaitre les 3 autres
335 // car elles sont respectivement à droite, en haut à droite et en haut.
336 {
337 std::array<Int32, 4> sub_cell_lids_container;
338 ArrayView<Int32> sub_lids(sub_cell_lids_container);
339 Cell cell1 = cdm_x[cell].next();
340 // Vérifie la validité des sous-mailles.
341 // Normalement il ne devrait pas y avoir de problèmes sauf si le
342 // nombre de mailles dans chaque direction du sous-domaine
343 // n'est pas un nombre pair.
344 if (cell1.null())
345 ARCANE_FATAL("Bad right cell for cell {0}", ItemPrinter(cell));
346 Cell cell2 = cdm_y[cell1].next();
347 if (cell2.null())
348 ARCANE_FATAL("Bad upper right cell for cell {0}", ItemPrinter(cell));
349 Cell cell3 = cdm_y[cell].next();
350 if (cell3.null())
351 ARCANE_FATAL("Bad upper cell for cell {0}", ItemPrinter(cell));
352 sub_lids[0] = cell.localId();
353 sub_lids[1] = cell1.localId();
354 sub_lids[2] = cell2.localId();
355 sub_lids[3] = cell3.localId();
356 // Il faudra donner un propriétaire aux faces.
357 // Ces nouvelles faces auront le même propriétaire que les faces raffinées
358 // auquelles elles correspondent
359 //info() << "CELL_NB_FACE=" << cell.nbFace() << " " << cell1.nbFace() << " " << cell2.nbFace() << " " << cell3.nbFace();
360 coarse_faces_owner.add(cell.face(0).owner());
361 coarse_faces_owner.add(cell1.face(1).owner());
362 coarse_faces_owner.add(cell2.face(2).owner());
363 coarse_faces_owner.add(cell3.face(3).owner());
364 for (Int32 i = 0; i < 4; ++i)
365 refined_cells_lids.add(sub_lids[i]);
366 }
367 }
368
369 // Construit les faces
370 UniqueArray<Int32> faces_local_ids(nb_coarse_face);
371 mesh->modifier()->addFaces(nb_coarse_face, faces_infos, faces_local_ids);
372
373 // Construit les mailles
374 // Indique qu'on n'a pas le droit de construire à la volée les faces.
375 // Normalement elles ont toutes été ajoutées via addFaces();
376 UniqueArray<Int32> cells_local_ids(nb_coarse_cell);
377 MeshModifierAddCellsArgs add_cells_args(nb_coarse_cell, cells_infos, cells_local_ids);
378 add_cells_args.setAllowBuildFaces(false);
379 mesh->modifier()->addCells(add_cells_args);
380
381 IItemFamily* cell_family = mesh->cellFamily();
382
383 // Maintenant que les mailles grossières sont créées, il faut indiquer
384 // qu'elles sont parentes.
385 using mesh::CellFamily;
386 CellInfoListView cells(mesh->cellFamily());
387 CellFamily* true_cell_family = ARCANE_CHECK_POINTER(dynamic_cast<CellFamily*>(cell_family));
388 std::array<Int32, 4> sub_cell_lids_container;
389 ArrayView<Int32> sub_cell_lids(sub_cell_lids_container);
390 for (Int32 i = 0; i < nb_coarse_cell; ++i) {
391 Int32 coarse_cell_lid = cells_local_ids[i];
392 Cell coarse_cell = cells[coarse_cell_lid];
393 Cell first_child_cell = first_child_cells[i];
394 // A partir de la première sous-maille, on peut connaitre les 3 autres
395 // car elles sont respectivement à droite, en haut à droite et en haut.
396 sub_cell_lids[0] = first_child_cell.localId();
397 sub_cell_lids[1] = cdm_x[first_child_cell].next().localId();
398 sub_cell_lids[2] = cdm_y[CellLocalId(sub_cell_lids[1])].next().localId();
399 sub_cell_lids[3] = cdm_y[first_child_cell].next().localId();
400 if (is_verbose)
401 info() << "AddChildForCoarseCell i=" << i << " coarse=" << ItemPrinter(coarse_cell)
402 << " children_lid=" << sub_cell_lids;
403 for (Int32 z = 0; z < 4; ++z) {
404 Cell child_cell = cells[sub_cell_lids[z]];
405 if (is_verbose)
406 info() << " AddParentCellToCell: z=" << z << " child=" << ItemPrinter(child_cell);
407 true_cell_family->_addParentCellToCell(child_cell, coarse_cell);
408 }
409 true_cell_family->_addChildrenCellsToCell(coarse_cell, sub_cell_lids);
410 }
411
412 // Positionne les propriétaires des nouvelles mailles et faces
413 {
414 IItemFamily* face_family = mesh->faceFamily();
415 Int32 index = 0;
416 ENUMERATE_ (Cell, icell, cell_family->view(cells_local_ids)) {
417 Cell cell = *icell;
418 Int32 owner = coarse_cells_owner[index];
419 cell.mutableItemBase().setOwner(owner, my_rank);
420 const Int64 sub_cell_index = index * 4;
421 for (Int32 z = 0; z < 4; ++z) {
422 cell.face(z).mutableItemBase().setOwner(coarse_faces_owner[sub_cell_index + z], my_rank);
423 }
424 ++index;
425 }
426 cell_family->notifyItemsOwnerChanged();
427 face_family->notifyItemsOwnerChanged();
428 }
429}
430
431/*---------------------------------------------------------------------------*/
432/*---------------------------------------------------------------------------*/
433
434void CartesianMeshCoarsening2::
435_createCoarseCells3D()
436{
437 const bool is_verbose = m_verbosity_level > 0;
438 IMesh* mesh = m_cartesian_mesh->mesh();
439 IParallelMng* pm = mesh->parallelMng();
440 const Int32 my_rank = pm->commRank();
441
442 CellDirectionMng cdm_x(m_cartesian_mesh->cellDirection(0));
443 CellDirectionMng cdm_y(m_cartesian_mesh->cellDirection(1));
444 CellDirectionMng cdm_z(m_cartesian_mesh->cellDirection(2));
445
446 const Int64 global_nb_cell_x = cdm_x.globalNbCell();
447 const Int64 global_nb_cell_y = cdm_y.globalNbCell();
448 const Int64 global_nb_cell_z = cdm_z.globalNbCell();
449 CartesianGridDimension refined_grid_dim(global_nb_cell_x, global_nb_cell_y, global_nb_cell_z);
450 CartesianGridDimension coarse_grid_dim(global_nb_cell_x / 2, global_nb_cell_y / 2, global_nb_cell_z / 2);
451 CartesianGridDimension::CellUniqueIdComputer3D refined_cell_uid_computer(refined_grid_dim.getCellComputer3D(0));
452 CartesianGridDimension::NodeUniqueIdComputer3D refined_node_uid_computer(refined_grid_dim.getNodeComputer3D(0));
453 CartesianGridDimension::CellUniqueIdComputer3D coarse_cell_uid_computer(coarse_grid_dim.getCellComputer3D(m_first_own_cell_unique_id_offset));
454 CartesianGridDimension::FaceUniqueIdComputer3D coarse_face_uid_computer(coarse_grid_dim.getFaceComputer3D(m_first_own_cell_unique_id_offset));
455
456 // Pour les mailles et faces grossières, les noeuds existent déjà
457 // On ne peut donc pas utiliser la connectivité cartésienne de la grille grossière
458 // pour eux (on pourra le faire lorsque l'AMR par patch avec duplication sera active)
459 // En attendant on utilise la numérotation de la grille raffinée.
460
461 // TODO: Calculer en avance le nombre de faces et de mailles et allouer en conséquence.
462 UniqueArray<Int64> faces_infos;
463 UniqueArray<Int64> cells_infos;
464 Int32 nb_coarse_face = 0;
465 Int32 nb_coarse_cell = 0;
467 UniqueArray<Cell> first_child_cells;
468
469 UniqueArray<Int64> refined_cells_lids;
470 UniqueArray<Int32> coarse_cells_owner;
471 UniqueArray<Int32> coarse_faces_owner;
472
473 static constexpr Int32 const_cell_nb_node = 8;
474 static constexpr Int32 const_cell_nb_face = 6;
475 static constexpr Int32 const_cell_nb_sub_cell = 8;
476 static constexpr Int32 const_face_nb_node = 4;
477
478 // Liste des uniqueId() des noeuds des faces créées
479 SmallArray<Int64, const_face_nb_node> face_node_uids(const_face_nb_node);
480 // Liste ordonnée des noeuds des faces créées
481 SmallArray<Int64, const_face_nb_node> face_sorted_node_uids(const_face_nb_node);
482 ENUMERATE_ (Cell, icell, mesh->allCells()) {
483 Cell cell = *icell;
484 Int64 cell_uid = cell.uniqueId();
485 Int64x3 cell_xyz = refined_cell_uid_computer.compute(cell_uid);
486 const Int64 cell_x = cell_xyz.x;
487 const Int64 cell_y = cell_xyz.y;
488 const Int64 cell_z = cell_xyz.z;
489 // Nécessaire pour le recalcul des mailles fantômes. On considère ces
490 // mailles comme si elles venaient juste d'être raffinées.
492 // Comme on déraffine par 2, ne prend que les mailles dont les coordoonnées
493 // topologiques sont paires
494 if ((cell_x % 2) != 0 || (cell_y % 2) != 0 || (cell_z % 2) != 0)
495 continue;
496 if (is_verbose)
497 info() << "CellToCoarse refined_uid=" << cell_uid << " x=" << cell_x << " y=" << cell_y << " z=" << cell_z;
498 coarse_cells_owner.add(cell.owner());
499 const Int64 coarse_cell_x = cell_x / 2;
500 const Int64 coarse_cell_y = cell_y / 2;
501 const Int64 coarse_cell_z = cell_z / 2;
502 std::array<Int64, const_cell_nb_node> node_uids_container;
503 ArrayView<Int64> node_uids(node_uids_container);
504 node_uids[0] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 0, cell_z + 0);
505 node_uids[1] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 0, cell_z + 0);
506 node_uids[2] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 2, cell_z + 0);
507 node_uids[3] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 2, cell_z + 0);
508 node_uids[4] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 0, cell_z + 2);
509 node_uids[5] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 0, cell_z + 2);
510 node_uids[6] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 2, cell_z + 2);
511 node_uids[7] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 2, cell_z + 2);
512 if (is_verbose)
513 info() << "CELLNodes uid=" << node_uids;
514 std::array<Int64, const_cell_nb_face> coarse_face_uids = coarse_face_uid_computer.computeForCell(coarse_cell_x, coarse_cell_y, coarse_cell_z);
515 const ItemTypeInfo* cell_type = cell.typeInfo();
516
517 // Ajoute les 6 faces
518 for (Int32 z = 0; z < const_cell_nb_face; ++z) {
519 ItemTypeInfo::LocalFace lface = cell_type->localFace(z);
520 faces_infos.add(IT_Quad4);
521 faces_infos.add(coarse_face_uids[z]);
522 for (Int32 knode = 0; knode < const_face_nb_node; ++knode)
523 face_node_uids[knode] = node_uids[lface.node(knode)];
524 MeshUtils::reorderNodesOfFace(face_node_uids, face_sorted_node_uids);
525 if (is_verbose)
526 info() << "ADD_FACE coarse_uid=" << coarse_face_uids[z] << " n=" << face_sorted_node_uids;
527 faces_infos.addRange(face_sorted_node_uids);
528 ++nb_coarse_face;
529 }
530
531 // Ajoute la maille
532 {
533 cells_infos.add(IT_Hexaedron8);
534 Int64 coarse_cell_uid = coarse_cell_uid_computer.compute(coarse_cell_x, coarse_cell_y, coarse_cell_z);
535 cells_infos.add(coarse_cell_uid);
536 if (is_verbose)
537 info() << "CoarseCellUid=" << coarse_cell_uid;
538 m_coarse_cells_uid.add(coarse_cell_uid);
539 for (Int32 z = 0; z < const_cell_nb_node; ++z)
540 cells_infos.add(node_uids[z]);
541 ++nb_coarse_cell;
542 first_child_cells.add(cell);
543 }
544
545 // A partir de la première sous-maille, on peut connaitre les 7 autres
546 // car elles sont respectivement à droite, en haut à droite et en haut,
547 // au dessus, au dessus à droit, au dessus en haut à droit et .
548 {
549 std::array<Int32, const_cell_nb_sub_cell> sub_cell_lids_container;
550 ArrayView<Int32> sub_lids(sub_cell_lids_container);
551 Cell cell1 = cdm_x[cell].next();
552 // Vérifie la validité des sous-mailles.
553 // Normalement il ne devrait pas y avoir de problèmes sauf si le
554 // nombre de mailles dans chaque direction du sous-domaine
555 // n'est pas un nombre pair.
556 if (cell1.null())
557 ARCANE_FATAL("Bad right cell for cell {0}", ItemPrinter(cell));
558 Cell cell2 = cdm_y[cell1].next();
559 if (cell2.null())
560 ARCANE_FATAL("Bad upper right cell for cell {0}", ItemPrinter(cell));
561 Cell cell3 = cdm_y[cell].next();
562 if (cell3.null())
563 ARCANE_FATAL("Bad upper cell for cell {0}", ItemPrinter(cell));
564
565 Cell cell4 = cdm_z[cell].next();
566 if (cell4.null())
567 ARCANE_FATAL("Bad top cell for cell {0}", ItemPrinter(cell));
568
569 Cell cell5 = cdm_x[cell4].next();
570 if (cell5.null())
571 ARCANE_FATAL("Bad top right cell for cell {0}", ItemPrinter(cell));
572 Cell cell6 = cdm_y[cell5].next();
573 if (cell6.null())
574 ARCANE_FATAL("Bad top upper right cell for cell {0}", ItemPrinter(cell));
575 Cell cell7 = cdm_y[cell4].next();
576 if (cell7.null())
577 ARCANE_FATAL("Bad top upper cell for cell {0}", ItemPrinter(cell));
578
579 sub_lids[0] = cell.localId();
580 sub_lids[1] = cell1.localId();
581 sub_lids[2] = cell2.localId();
582 sub_lids[3] = cell3.localId();
583 sub_lids[4] = cell4.localId();
584 sub_lids[5] = cell5.localId();
585 sub_lids[6] = cell6.localId();
586 sub_lids[7] = cell7.localId();
587 // Il faudra donner un propriétaire aux faces.
588 // Ces nouvelles faces auront le même propriétaire que les faces raffinées
589 // auquelles elles correspondent
590 //info() << "CELL_NB_FACE=" << cell.nbFace() << " " << cell1.nbFace() << " " << cell2.nbFace() << " " << cell3.nbFace();
591 coarse_faces_owner.add(cell.face(0).owner());
592 coarse_faces_owner.add(cell1.face(1).owner());
593 coarse_faces_owner.add(cell2.face(2).owner());
594 coarse_faces_owner.add(cell3.face(3).owner());
595
596 coarse_faces_owner.add(cell4.face(4).owner());
597 coarse_faces_owner.add(cell5.face(5).owner());
598
599 for (Int32 i = 0; i < const_cell_nb_sub_cell; ++i)
600 refined_cells_lids.add(sub_lids[i]);
601 }
602 }
603
604 // Construit les faces
605 UniqueArray<Int32> faces_local_ids(nb_coarse_face);
606 mesh->modifier()->addFaces(nb_coarse_face, faces_infos, faces_local_ids);
607
608 // Construit les mailles
609 // Indique qu'on n'a pas le droit de construire à la volée les faces.
610 // Normalement elles ont toutes été ajoutées via addFaces();
611 UniqueArray<Int32> cells_local_ids(nb_coarse_cell);
612 MeshModifierAddCellsArgs add_cells_args(nb_coarse_cell, cells_infos, cells_local_ids);
613 add_cells_args.setAllowBuildFaces(false);
614 mesh->modifier()->addCells(add_cells_args);
615
616 IItemFamily* cell_family = mesh->cellFamily();
617
618 // Maintenant que les mailles grossières sont créées, il faut indiquer
619 // qu'elles sont parentes.
620 using mesh::CellFamily;
621 CellInfoListView cells(mesh->cellFamily());
622 CellFamily* true_cell_family = ARCANE_CHECK_POINTER(dynamic_cast<CellFamily*>(cell_family));
623 std::array<Int32, const_cell_nb_sub_cell> sub_cell_lids_container;
624 ArrayView<Int32> sub_cell_lids(sub_cell_lids_container);
625 for (Int32 i = 0; i < nb_coarse_cell; ++i) {
626 Int32 coarse_cell_lid = cells_local_ids[i];
627 Cell coarse_cell = cells[coarse_cell_lid];
628 Cell first_child_cell = first_child_cells[i];
629 // A partir de la première sous-maille, on peut connaitre les 3 autres
630 // car elles sont respectivement à droite, en haut à droite et en haut.
631 sub_cell_lids[0] = first_child_cell.localId();
632 sub_cell_lids[1] = cdm_x[first_child_cell].next().localId();
633 sub_cell_lids[2] = cdm_y[CellLocalId(sub_cell_lids[1])].next().localId();
634 sub_cell_lids[3] = cdm_y[first_child_cell].next().localId();
635
636 Cell top_first_child_cell = cdm_z[first_child_cell].next();
637 sub_cell_lids[4] = top_first_child_cell.localId();
638 sub_cell_lids[5] = cdm_x[top_first_child_cell].next().localId();
639 sub_cell_lids[6] = cdm_y[CellLocalId(sub_cell_lids[5])].next().localId();
640 sub_cell_lids[7] = cdm_y[top_first_child_cell].next().localId();
641
642 if (is_verbose)
643 info() << "AddChildForCoarseCell i=" << i << " coarse=" << ItemPrinter(coarse_cell)
644 << " children_lid=" << sub_cell_lids;
645 for (Int32 z = 0; z < const_cell_nb_sub_cell; ++z) {
646 Cell child_cell = cells[sub_cell_lids[z]];
647 if (is_verbose)
648 info() << " AddParentCellToCell: z=" << z << " child=" << ItemPrinter(child_cell);
649 true_cell_family->_addParentCellToCell(child_cell, coarse_cell);
650 }
651 true_cell_family->_addChildrenCellsToCell(coarse_cell, sub_cell_lids);
652 }
653
654 // Positionne les propriétaires des nouvelles mailles et faces
655 {
656 IItemFamily* face_family = mesh->faceFamily();
657 Int32 index = 0;
658 ENUMERATE_ (Cell, icell, cell_family->view(cells_local_ids)) {
659 Cell cell = *icell;
660 Int32 owner = coarse_cells_owner[index];
661 cell.mutableItemBase().setOwner(owner, my_rank);
662 const Int64 sub_cell_index = index * const_cell_nb_face;
663 for (Int32 z = 0; z < const_cell_nb_face; ++z) {
664 cell.face(z).mutableItemBase().setOwner(coarse_faces_owner[sub_cell_index + z], my_rank);
665 }
666 ++index;
667 }
668 cell_family->notifyItemsOwnerChanged();
669 face_family->notifyItemsOwnerChanged();
670 }
671}
672
673/*---------------------------------------------------------------------------*/
674/*---------------------------------------------------------------------------*/
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 // Coefficient de dé-raffinement
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 // Supprime toutes les mailles raffinées ainsi que toutes les mailles fantômes
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 // Reconstruit les mailles fantômes
744 mesh_modifier->setDynamic(true);
745 mesh_modifier->updateGhostLayers();
746
747 // Affiche les statistiques du nouveau maillage
748 {
749 MeshStats ms(traceMng(), mesh, mesh->parallelMng());
750 ms.dumpStats();
751 }
752
753 // Il faut recalculer les nouvelles directions
754 m_cartesian_mesh->computeDirections();
755}
756
757/*---------------------------------------------------------------------------*/
758/*---------------------------------------------------------------------------*/
759
760} // End namespace Arcane
761
762/*---------------------------------------------------------------------------*/
763/*---------------------------------------------------------------------------*/
#define ARCANE_CHECK_POINTER(ptr)
Macro retournant le pointeur ptr s'il est non nul ou lancant une exception s'il est nul.
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ENUMERATE_(type, name, group)
Enumérateur générique d'un groupe d'entité
bool reorderNodesOfFace(Int64ConstArrayView before_ids, Int64ArrayView after_ids)
Réordonne les noeuds d'une face.
Integer size() const
Nombre d'éléments du vecteur.
Vue modifiable d'un tableau d'un type T.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
void addRange(ConstReferenceType val, Int64 n)
Ajoute n élément de valeur val à la fin du tableau.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
Classe pour calculer en 2D le uniqueId() d'une maille en fonction de sa position dans la grille.
Classe pour calculer en 3D le uniqueId() d'une maille en fonction de sa position dans la grille.
Int64 compute(Int64 x, Int64 y, Int64 z)
Calcul le uniqueId() en fonction des coordonnées.
Classe pour calculer en 2D le uniqueId() d'une face en fonction de sa position dans la grille.
std::array< Int64, 4 > computeForCell(Int64 x, Int64 y)
Calcule les uniqueIds() des 4 faces de la mailles de coordonnées topologique (x,y)
Classe pour calculer en 2D le uniqueId() d'une face en fonction de sa position dans la grille.
std::array< Int64, 6 > computeForCell(Int64 x, Int64 y, Int64 z)
Calcule les uniqueIds() des 6 faces de la mailles de coordonnées topologique (x,y,...
Classe pour calculer en 2D le uniqueId() d'un noeud en fonction de sa position dans la grille.
Classe pour calculer en 3D le uniqueId() d'un noeud en fonction de sa position dans la grille.
Informations sur les dimensions d'une grille cartésienne.
CellUniqueIdComputer2D getCellComputer2D(Int64 offset) const
Instance pour calculer les uniqueId() des mailles pour cette grille.
CellUniqueIdComputer3D getCellComputer3D(Int64 offset) const
Instance pour calculer les uniqueId() des mailles pour cette grille.
FaceUniqueIdComputer3D getFaceComputer3D(Int64 offset) const
Instance pour calculer les uniqueId() des faces pour cette grille.
NodeUniqueIdComputer3D getNodeComputer3D(Int64 offset) const
Instance pour calculer les uniqueId() des noeuds pour cette grille.
NodeUniqueIdComputer2D getNodeComputer2D(Int64 offset) const
Instance pour calculer les uniqueId() des noeuds pour cette grille.
FaceUniqueIdComputer2D getFaceComputer2D(Int64 offset) const
Instance pour calculer les uniqueId() des faces pour cette grille.
void _doDoubleGhostLayers()
Double la couche de mailles fantômes du maillage initial.
Int64 _getMaxUniqueId(const ItemGroup &group)
Retourne le max des uniqueId() des entités de group.
void _recomputeMeshGenerationInfo()
Recalcule les informations sur le nombre de mailles par direction.
UniqueArray< Int64 > m_coarse_cells_uid
uniqueId() des mailles grossières
Infos sur les mailles d'une direction spécifique X,Y ou Z d'un maillage structuré.
Int64 globalNbCell() const
Nombre global de mailles dans cette direction.
Int32 ownNbCell() const
Nombre de mailles propres dans cette direction.
Vue sur les informations des mailles.
Maille d'un maillage.
Definition Item.h:1191
Face face(Int32 i) const
i-ème face de la maille
Definition Item.h:1269
Int32 nbFace() const
Nombre de faces de la maille.
Definition Item.h:1266
Int32 level() const
Definition Item.h:1342
Vue constante d'un tableau de type T.
Interface d'un maillage cartésien.
virtual void setBuilderVersion(Integer n)=0
Positionne la version du constructeur de mailles fantômes. Pour l'instant (version 3....
virtual Integer nbGhostLayer() const =0
Nombre de couches fantômes.
virtual Integer builderVersion() const =0
Version du constructeur de mailles fantômes.
virtual void setNbGhostLayer(Integer n)=0
Positionne le nombre de couches fantômes.
Interface d'une famille d'entités.
Definition IItemFamily.h:84
virtual void notifyItemsOwnerChanged()=0
Notifie que les entités propres au sous-domaine de la famille ont été modifiées.
virtual ItemVectorView view(Int32ConstArrayView local_ids)=0
Vue sur les entités.
Interface de modification du maillage.
virtual void updateGhostLayers()=0
Mise à jour de la couche fantôme.
virtual void setDynamic(bool v)=0
Positionne la propriété indiquant si le maillage peut évoluer.
virtual void removeCells(Int32ConstArrayView cells_local_id)=0
Supprime des mailles.
virtual void endUpdate()=0
Notifie l'instance de la fin de la modification du maillage.
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual char reduce(eReduceType rt, char v)=0
Effectue la réduction de type rt sur le réel v et retourne la valeur.
@ II_JustRefined
L'entité vient d'être raffinée.
Definition ItemFlags.h:64
Groupe d'entités de maillage.
Definition ItemGroup.h:49
ItemVectorView view() const
Vue sur les entités du groupe.
Definition ItemGroup.cc:582
Classe utilitaire pour imprimer les infos sur une entité.
Definition ItemPrinter.h:35
Informations locales sur une face d'une maille.
Integer node(Integer i) const
Indice locale dans la maille du i-ème noeud de la face.
Infos sur un type d'entité du maillage.
LocalFace localFace(Integer id) const
Connectivité locale de la i-ème face de la maille.
Int32ConstArrayView localIds() const
Tableau des numéros locaux des entités.
Node node(Int32 i) const
i-ème noeud de l'entité
Definition Item.h:779
Int32 nbNode() const
Nombre de noeuds de l'entité
Definition Item.h:776
Classe de base d'un élément de maillage.
Definition Item.h:83
const ItemTypeInfo * typeInfo() const
Infos sur le type de l'entité.
Definition Item.h:386
impl::MutableItemBase mutableItemBase() const
Partie interne modifiable de l'entité.
Definition Item.h:374
constexpr Int32 localId() const
Identifiant local de l'entité dans le sous-domaine du processeur.
Definition Item.h:219
Int32 owner() const
Numéro du sous-domaine propriétaire de l'entité
Definition Item.h:238
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
Definition Item.h:225
constexpr bool null() const
true si l'entité est nul (i.e. non connecté au maillage)
Definition Item.h:216
Arguments pour IMeshModifier::addCells().
void setAllowBuildFaces(bool v)
Indique si on autorise la création des faces associées.
void dumpStats() override
Imprime des infos sur le maillage.
Definition MeshStats.cc:62
void setOwner(Integer suid, Int32 current_sub_domain)
Positionne le numéro du sous-domaine propriétaire de l'entité.
void addFlags(Int32 added_flags)
Ajoute les flags \added_flags à ceux de l'entité
Exportation d'un maillage au format SVG.
Tableau 1D de données avec buffer pré-alloué sur la pile.
Definition SmallArray.h:89
Chaîne de caractères unicode.
const char * localstr() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:227
TraceMessage info() const
Flot pour un message d'information.
ITraceMng * traceMng() const
Gestionnaire de trace.
Vecteur 1D de données avec sémantique par valeur (style STL).
Famille de mailles.
Definition CellFamily.h:46
T max(const T &a, const T &b, const T &c)
Retourne le maximum de trois éléments.
Definition MathUtils.h:392
ItemGroupT< Cell > CellGroup
Groupe de mailles.
Definition ItemTypes.h:183
@ ReduceMax
Maximum des valeurs.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
std::int32_t Int32
Type entier signé sur 32 bits.