Arcane  v3.14.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
CartesianMeshCoarsening.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2023 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-2023 */
9/* */
10/* Déraffinement d'un maillage cartésien. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/cartesianmesh/CartesianMeshCoarsening.h"
15
16#include "arcane/utils/FatalErrorException.h"
17#include "arcane/utils/ValueConvert.h"
18
19#include "arcane/core/IMesh.h"
20#include "arcane/core/ItemGroup.h"
21#include "arcane/core/IParallelMng.h"
22#include "arcane/core/CartesianGridDimension.h"
23#include "arcane/core/IMeshModifier.h"
24#include "arcane/core/SimpleSVGMeshExporter.h"
25#include "arcane/core/ItemPrinter.h"
26#include "arcane/core/MeshStats.h"
27
28#include "arcane/cartesianmesh/ICartesianMesh.h"
29#include "arcane/cartesianmesh/CellDirectionMng.h"
30
31#include <unordered_set>
32
33/*---------------------------------------------------------------------------*/
34/*---------------------------------------------------------------------------*/
35
36namespace Arcane
37{
38
39/*---------------------------------------------------------------------------*/
40/*---------------------------------------------------------------------------*/
41
42CartesianMeshCoarsening::
43CartesianMeshCoarsening(ICartesianMesh* m)
44: TraceAccessor(m->traceMng())
45, m_cartesian_mesh(m)
46{
47 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_CARTESIANMESH_COARSENING_VERBOSITY_LEVEL", true))
48 m_verbosity_level = v.value();
49}
50
51/*---------------------------------------------------------------------------*/
52/*---------------------------------------------------------------------------*/
53
55Int64 CartesianMeshCoarsening::
56_getMaxUniqueId(const ItemGroup& group)
57{
58 Int64 max_offset = 0;
59 ENUMERATE_ (Item, iitem, group) {
60 Item item = *iitem;
61 if (max_offset < item.uniqueId())
62 max_offset = item.uniqueId();
63 }
64 return max_offset;
65}
66
67/*---------------------------------------------------------------------------*/
68/*---------------------------------------------------------------------------*/
69
70void CartesianMeshCoarsening::
71createCoarseCells()
72{
73 if (m_is_create_coarse_called)
74 ARCANE_FATAL("This method has already been called");
75 m_is_create_coarse_called = true;
76
77 const bool is_verbose = m_verbosity_level > 0;
78 IMesh* mesh = m_cartesian_mesh->mesh();
79 Integer nb_patch = m_cartesian_mesh->nbPatch();
80 if (nb_patch != 1)
81 ARCANE_FATAL("This method is only valid for 1 patch (nb_patch={0})", nb_patch);
82
83 if (!mesh->isAmrActivated())
84 ARCANE_FATAL("AMR is not activated for this case");
85
86 // TODO: Supprimer les mailles fantômes puis les reconstruire
87 // TODO: Mettre à jour les informations dans CellDirectionMng
88 // de ownNbCell(), globalNbCell(), ...
89
90 Integer nb_dir = mesh->dimension();
91 if (nb_dir != 2)
92 ARCANE_FATAL("This method is only valid for 2D mesh");
93
94 IParallelMng* pm = mesh->parallelMng();
95 const Int32 my_rank = pm->commRank();
96 info() << "CoarseCartesianMesh nb_direction=" << nb_dir;
97
98 for (Integer idir = 0; idir < nb_dir; ++idir) {
99 CellDirectionMng cdm(m_cartesian_mesh->cellDirection(idir));
100 Int32 nb_own_cell = cdm.ownNbCell();
101 info() << "NB_OWN_CELL dir=" << idir << " n=" << nb_own_cell;
102 if ((nb_own_cell % 2) != 0)
103 ARCANE_FATAL("Invalid number of cells ({0}) for direction {1}. Should be a multiple of 2",
105 }
106
107 // Calcule l'offset pour la création des uniqueId().
108 // On prend comme offset le max des uniqueId() des faces et des mailles.
109 // A terme avec la numérotation cartésienne partout, on pourra déterminer
110 // directement cette valeur
111 Int64 max_cell_uid = _getMaxUniqueId(mesh->allCells());
112 Int64 max_face_uid = _getMaxUniqueId(mesh->allFaces());
113 const Int64 coarse_grid_cell_offset = 1 + pm->reduce(Parallel::ReduceMax, math::max(max_cell_uid, max_face_uid));
114 m_first_own_cell_unique_id_offset = coarse_grid_cell_offset;
115
116 CellDirectionMng cdm_x(m_cartesian_mesh->cellDirection(0));
117 CellDirectionMng cdm_y(m_cartesian_mesh->cellDirection(1));
118
119 const Int64 global_nb_cell_x = cdm_x.globalNbCell();
120 const Int64 global_nb_cell_y = cdm_y.globalNbCell();
127
128 // Pour les mailles et faces grossières, les noeuds existent déjà
129 // On ne peut donc pas utiliser la connectivité cartésienne de la grille grossière
130 // pour eux (on pourra le faire lorsque l'AMR par patch avec duplication sera active)
131 // En attendant on utilise la numérotation de la grille raffinée.
132
133 // TODO: Calculer le nombre de faces et de mailles et allouer en conséquence.
136 Int32 nb_coarse_face = 0;
137 Int32 nb_coarse_cell = 0;
140 ENUMERATE_ (Cell, icell, mesh->ownCells()) {
141 Cell cell = *icell;
142 Int64 cell_uid = cell.uniqueId();
143 Int64x3 cell_xy = refined_cell_uid_computer.compute(cell_uid);
144 const Int64 cell_x = cell_xy.x;
145 const Int64 cell_y = cell_xy.y;
146 // Comme on déraffine par 2, ne prend que les mailles dont les coordoonnées
147 // topologiques sont paires
148 if ((cell_x % 2) != 0 || (cell_y % 2) != 0)
149 continue;
150 if (is_verbose)
151 info() << "CELLCoarse uid=" << cell_uid << " x=" << cell_x << " y=" << cell_y;
152 const Int64 coarse_cell_x = cell_x / 2;
153 const Int64 coarse_cell_y = cell_y / 2;
154 std::array<Int64, 4> node_uids_container;
156 node_uids[0] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 0);
157 node_uids[1] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 0);
158 node_uids[2] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 2);
159 node_uids[3] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 2);
160 if (is_verbose)
161 info() << "CELLNodes uid=" << node_uids;
162 std::array<Int64, 4> coarse_face_uids = coarse_face_uid_computer.computeForCell(coarse_cell_x, coarse_cell_y);
163 const ItemTypeInfo* cell_type = cell.typeInfo();
164 // Ajoute les 4 faces
165 for (Int32 z = 0; z < 4; ++z) {
167 faces_infos.add(IT_Line2);
169 faces_infos.add(node_uids[lface.node(0)]);
170 faces_infos.add(node_uids[lface.node(1)]);
172 }
173 // Ajoute la maille
174 {
175 cells_infos.add(IT_Quad4);
177 for (Int32 z = 0; z < 4; ++z)
178 cells_infos.add(node_uids[z]);
181 }
182 }
183
190
191 // Maintenant que les mailles grossières sont créées, il faut indiquer
192 // qu'elles sont parentes.
194
195 // Positionne les propriétaires des nouvelles mailles
196 // et ajoute un flag (ItemFlags::II_UserMark1) pour les marquer.
197 // Cela sera utilisé pour détruire les mailles raffinées par la suite.
198 {
200 Cell cell = *icell;
202 cell.mutableItemBase().addFlags(ItemFlags::II_UserMark1);
203 }
204 cell_family->notifyItemsOwnerChanged();
205 }
206
207 // Il faut donner un propriétaire aux faces.
208 // Comme les nouvelles faces utilisent un noeud déjà existant, on prend comme propriétaire
209 // celui du premier noeud de la face
210 {
213 Face face = *iface;
214 Int32 owner = face.node(0).owner();
215 face.mutableItemBase().setOwner(owner, my_rank);
216 }
217 face_family->notifyItemsOwnerChanged();
218 }
219
220 // Met à jour le maillage
221 mesh->modifier()->endUpdate();
222
223 // Après l'appel à endUpdate() les numéros locaux ne changent plus.
224 // On peut s'en servir pour conserver pour chaque maille grossière la liste des mailles
225 // raffinées
226 m_coarse_cells.resize(nb_coarse_cell);
227 m_refined_cells.resize(nb_coarse_cell, 4);
228
229 {
230 CellInfoListView cells(mesh->cellFamily());
233 Int32 coarse_index = 0;
234 std::array<Int32, 4> sub_cell_lids_container;
236
237 ENUMERATE_ (Cell, icell, mesh->ownCells()) {
239 if (!(coarse_cell.itemBase().flags() & ItemFlags::II_UserMark1))
240 continue;
241 // Supprime le flag
242 coarse_cell.mutableItemBase().removeFlags(ItemFlags::II_UserMark1);
243 m_coarse_cells[coarse_index] = coarse_cell.itemLocalId();
245 // A partir de la première sous-maille, on peut connaître les 3 autres
246 // car elles sont respectivement à droite, en haut à droite et en haut.
247 sub_cell_lids[0] = first_child_cell.localId();
248 sub_cell_lids[1] = cdm_x[first_child_cell].next().localId();
249 sub_cell_lids[2] = cdm_y[CellLocalId(sub_cell_lids[1])].next().localId();
250 sub_cell_lids[3] = cdm_y[first_child_cell].next().localId();
251 if (is_verbose)
252 info() << "AddChildForCoarseCell i=" << coarse_index << " coarse=" << ItemPrinter(coarse_cell)
253 << " children_lid=" << sub_cell_lids;
254 for (Int32 z = 0; z < 4; ++z) {
256 m_refined_cells[coarse_index][z] = sub_local_id;
257 if (is_verbose)
258 info() << " AddParentCellToCell: z=" << z << " child=" << ItemPrinter(cells[sub_local_id]);
259 }
260 ++coarse_index;
261 }
262 }
263
264 if (is_verbose) {
265 ENUMERATE_ (Cell, icell, mesh->allCells()) {
266 Cell cell = *icell;
267 info() << "Final cell=" << ItemPrinter(cell) << " level=" << cell.level();
268 }
269 }
270
271 const bool dump_coarse_mesh = false;
272 if (dump_coarse_mesh) {
273 String filename = String::format("mesh_coarse_{0}.svg", my_rank);
274 std::ofstream ofile(filename.localstr());
276 writer.write(mesh->allCells());
277 }
278}
279
280/*---------------------------------------------------------------------------*/
281/*---------------------------------------------------------------------------*/
282
283void CartesianMeshCoarsening::
284removeRefinedCells()
285{
286 if (!m_is_create_coarse_called)
287 ARCANE_FATAL("You need to call createCoarseCells() before");
288 if (m_is_remove_refined_called)
289 ARCANE_FATAL("This method has already been called");
290 m_is_remove_refined_called = true;
291
292 IMesh* mesh = m_cartesian_mesh->mesh();
294
295 // Supprime toutes les mailles raffinées ainsi que toutes les mailles fantômes
296 {
297 std::unordered_set<Int32> coarse_cells_set;
298 for (Int32 cell_lid : m_coarse_cells)
300
302 ENUMERATE_ (Cell, icell, mesh->ownCells()) {
303 Int32 local_id = icell.itemLocalId();
304 Cell cell = *icell;
305 if (!cell.isOwn() || (coarse_cells_set.find(local_id) != coarse_cells_set.end()))
306 cells_to_remove.add(local_id);
307 }
308 mesh_modifier->removeCells(cells_to_remove);
309 mesh_modifier->endUpdate();
310 }
311
312 // Reconstruit les mailles fantômes
313 mesh_modifier->setDynamic(true);
314 mesh_modifier->updateGhostLayers();
315
316 // Affiche les statistiques du nouveau maillage
317 {
318 MeshStats ms(traceMng(), mesh, mesh->parallelMng());
319 ms.dumpStats();
320 }
321
322 _recomputeMeshGenerationInfo();
323
324 // Il faut recalculer les nouvelles directions
325 m_cartesian_mesh->computeDirections();
326}
327
328/*---------------------------------------------------------------------------*/
329/*---------------------------------------------------------------------------*/
333void CartesianMeshCoarsening::
334_recomputeMeshGenerationInfo()
335{
336 IMesh* mesh = m_cartesian_mesh->mesh();
337 auto* cmgi = ICartesianMeshGenerationInfo::getReference(mesh, false);
338 if (!cmgi)
339 return;
340
341 // Coefficient de dé-raffinement
342 const Int32 cf = 2;
343
344 {
345 ConstArrayView<Int64> v = cmgi->ownCellOffsets();
346 cmgi->setOwnCellOffsets(v[0] / cf, v[1] / cf, v[2] / cf);
347 }
348 {
349 ConstArrayView<Int64> v = cmgi->globalNbCells();
350 cmgi->setGlobalNbCells(v[0] / cf, v[1] / cf, v[2] / cf);
351 }
352 {
353 ConstArrayView<Int32> v = cmgi->ownNbCells();
354 cmgi->setOwnNbCells(v[0] / cf, v[1] / cf, v[2] / cf);
355 }
356 cmgi->setFirstOwnCellUniqueId(m_first_own_cell_unique_id_offset);
357}
358
359/*---------------------------------------------------------------------------*/
360/*---------------------------------------------------------------------------*/
361
362} // End namespace Arcane
363
364/*---------------------------------------------------------------------------*/
365/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ENUMERATE_(type, name, group)
Enumérateur générique d'un groupe d'entité
Classe pour calculer en 2D le uniqueId() d'une maille en fonction de sa position dans la grille.
Classe pour calculer en 2D le uniqueId() d'une face en fonction de sa position dans la grille.
Classe pour calculer en 2D le uniqueId() d'un noeud en fonction de sa position dans la grille.
Informations sur les dimensions d'une grille cartésienne.
Infos sur les mailles d'une direction spécifique X,Y ou Z d'un maillage structuré.
Vue sur les informations des mailles.
Maille d'un maillage.
Definition Item.h:1178
Int32 level() const
Definition Item.h:1328
Face d'une maille.
Definition Item.h:932
Interface d'une famille d'entités.
virtual CellGroup ownCells()=0
Groupe de toutes les mailles propres au domaine.
virtual FaceGroup allFaces()=0
Groupe de toutes les faces.
virtual Integer dimension()=0
Dimension du maillage (1D, 2D ou 3D).
virtual IItemFamily * faceFamily()=0
Retourne la famille des faces.
virtual CellGroup allCells()=0
Groupe de toutes les mailles.
virtual IItemFamily * cellFamily()=0
Retourne la famille des mailles.
Interface de modification du maillage.
virtual IParallelMng * parallelMng()=0
Gestionnaire de parallèlisme.
virtual IMeshModifier * modifier()=0
Interface de modification associée.
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.
Groupe d'entités de maillage.
Definition ItemGroup.h:49
Classe utilitaire pour imprimer les infos sur une entité.
Definition ItemPrinter.h:35
Informations locales sur une face d'une maille.
Infos sur un type d'entité du maillage.
Node node(Int32 i) const
i-ème noeud de l'entité
Definition Item.h:768
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:377
impl::MutableItemBase mutableItemBase() const
Partie interne modifiable de l'entité.
Definition Item.h:365
bool isOwn() const
true si l'entité est appartient au sous-domaine
Definition Item.h:244
Int32 owner() const
Numéro du sous-domaine propriétaire de l'entité
Definition Item.h:229
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
Definition Item.h:216
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
Arguments pour IMeshModifier::addCells().
Arguments pour IMeshModifier::addFaces().
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.
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
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-