Arcane  v3.14.10.0
Documentation utilisateur
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
54//! Retourne le max des uniqueId() des entités de \a group
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",
104 nb_own_cell, idir);
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();
121 CartesianGridDimension refined_grid_dim(global_nb_cell_x, global_nb_cell_y);
122 CartesianGridDimension coarse_grid_dim(global_nb_cell_x / 2, global_nb_cell_y / 2);
123 CartesianGridDimension::CellUniqueIdComputer2D refined_cell_uid_computer(refined_grid_dim.getCellComputer2D(0));
124 CartesianGridDimension::NodeUniqueIdComputer2D refined_node_uid_computer(refined_grid_dim.getNodeComputer2D(0));
125 CartesianGridDimension::CellUniqueIdComputer2D coarse_cell_uid_computer(coarse_grid_dim.getCellComputer2D(coarse_grid_cell_offset));
126 CartesianGridDimension::FaceUniqueIdComputer2D coarse_face_uid_computer(coarse_grid_dim.getFaceComputer2D(coarse_grid_cell_offset));
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.
134 UniqueArray<Int64> faces_infos;
135 UniqueArray<Int64> cells_infos;
136 Int32 nb_coarse_face = 0;
137 Int32 nb_coarse_cell = 0;
138 //! Liste de la première fille de chaque maille grossière
139 UniqueArray<Int64> first_child_cell_unique_ids;
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;
155 ArrayView<Int64> node_uids(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) {
166 ItemTypeInfo::LocalFace lface = cell_type->localFace(z);
167 faces_infos.add(IT_Line2);
168 faces_infos.add(coarse_face_uids[z]);
169 faces_infos.add(node_uids[lface.node(0)]);
170 faces_infos.add(node_uids[lface.node(1)]);
171 ++nb_coarse_face;
172 }
173 // Ajoute la maille
174 {
175 cells_infos.add(IT_Quad4);
176 cells_infos.add(coarse_cell_uid_computer.compute(coarse_cell_x, coarse_cell_y));
177 for (Int32 z = 0; z < 4; ++z)
178 cells_infos.add(node_uids[z]);
179 ++nb_coarse_cell;
180 first_child_cell_unique_ids.add(cell.uniqueId());
181 }
182 }
183
184 UniqueArray<Int32> cells_local_ids;
185 UniqueArray<Int32> faces_local_ids;
186 cells_local_ids.resize(nb_coarse_cell);
187 faces_local_ids.resize(nb_coarse_face);
188 mesh->modifier()->addFaces(MeshModifierAddFacesArgs(nb_coarse_face, faces_infos, faces_local_ids));
189 mesh->modifier()->addCells(MeshModifierAddCellsArgs(nb_coarse_cell, cells_infos, cells_local_ids));
190
191 // Maintenant que les mailles grossières sont créées, il faut indiquer
192 // qu'elles sont parentes.
193 IItemFamily* cell_family = mesh->cellFamily();
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 {
199 ENUMERATE_ (Cell, icell, cell_family->view(cells_local_ids)) {
200 Cell cell = *icell;
201 cell.mutableItemBase().setOwner(my_rank, my_rank);
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 {
211 IItemFamily* face_family = mesh->faceFamily();
212 ENUMERATE_ (Face, iface, face_family->view(faces_local_ids)) {
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());
231 UniqueArray<Int32> first_child_cell_local_ids(nb_coarse_cell);
232 cell_family->itemsUniqueIdToLocalId(first_child_cell_local_ids, first_child_cell_unique_ids);
233 Int32 coarse_index = 0;
234 std::array<Int32, 4> sub_cell_lids_container;
235 ArrayView<Int32> sub_cell_lids(sub_cell_lids_container);
236
237 ENUMERATE_ (Cell, icell, mesh->ownCells()) {
238 Cell coarse_cell = *icell;
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();
244 Cell first_child_cell = cells[first_child_cell_local_ids[coarse_index]];
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) {
255 CellLocalId sub_local_id = CellLocalId(sub_cell_lids[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());
275 SimpleSVGMeshExporter writer(ofile);
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();
293 IMeshModifier* mesh_modifier = mesh->modifier();
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)
299 coarse_cells_set.insert(cell_lid);
300
301 UniqueArray<Int32> cells_to_remove;
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/*---------------------------------------------------------------------------*/
330/*!
331 * \brief Recalcule les informations sur le nombre de mailles par direction.
332 */
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é
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é.
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:1178
CellLocalId itemLocalId() const
Identifiant local de l'entité dans le sous-domaine du processeur.
Definition Item.h:1249
Int32 level() const
Definition Item.h:1328
Face d'une maille.
Definition Item.h:932
Interface d'une famille d'entités.
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.
virtual void itemsUniqueIdToLocalId(Int32ArrayView local_ids, Int64ConstArrayView unique_ids, bool do_fatal=true) const =0
Converti un tableau de numéros uniques en numéros locaux.
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 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 addFaces(Integer nb_face, Int64ConstArrayView face_infos, Int32ArrayView face_lids=Int32ArrayView())=0
Ajoute des faces.
virtual void addCells(Integer nb_cell, Int64ConstArrayView cell_infos, Int32ArrayView cells_lid=Int32ArrayView())=0
Ajoute des mailles.
virtual void endUpdate()=0
Notifie l'instance de la fin de la 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.
Int32 flags() const
Flags de l'entité
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.
Node node(Int32 i) const
i-ème noeud de l'entité
Definition Item.h:768
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
constexpr Int32 localId() const
Identifiant local de l'entité dans le sous-domaine du processeur.
Definition Item.h:210
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
impl::ItemBase itemBase() const
Partie interne de l'entité.
Definition Item.h:354
Arguments pour IMeshModifier::addCells().
Arguments pour IMeshModifier::addFaces().
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é
void removeFlags(Int32 removed_flags)
Supprime les flags \added_flags de ceux de l'entité
Exportation d'un maillage au format SVG.
void write(const CellGroup &cells)
Exporte les entités du groupe cells.
Vue modifiable d'un tableau d'un type T.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
Vue constante d'un tableau de type T.
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
Vecteur 1D de données avec sémantique par valeur (style STL).
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-