Arcane  v4.1.4.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
CartesianPatchGroup.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/* CartesianPatchGroup.cc (C) 2000-2026 */
9/* */
10/* Gestion du groupe de patchs du maillage cartésien. */
11/*---------------------------------------------------------------------------*/
12
13#include "arcane/cartesianmesh/internal/CartesianPatchGroup.h"
14
15#include "arcane/utils/FixedArray.h"
16#include "arcane/utils/Vector3.h"
17#include "arcane/utils/StringBuilder.h"
18#include "arcane/utils/ITraceMng.h"
19
20#include "arcane/core/IMesh.h"
21#include "arcane/core/IParallelMng.h"
22#include "arcane/core/MeshKind.h"
23#include "arcane/core/Properties.h"
24
25#include "arcane/cartesianmesh/ICartesianMesh.h"
26#include "arcane/cartesianmesh/AMRZonePosition.h"
27
28#include "arcane/cartesianmesh/internal/CartesianMeshPatch.h"
29#include "arcane/cartesianmesh/internal/ICartesianMeshInternal.h"
30#include "arcane/cartesianmesh/internal/AMRPatchPositionLevelGroup.h"
31#include "arcane/cartesianmesh/internal/AMRPatchPositionSignature.h"
32#include "arcane/cartesianmesh/internal/AMRPatchPositionSignatureCut.h"
33#include "arcane/cartesianmesh/internal/ICartesianMeshNumberingMngInternal.h"
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
37
38namespace Arcane
39{
40
41/*---------------------------------------------------------------------------*/
42/*---------------------------------------------------------------------------*/
43
44CartesianPatchGroup::
45CartesianPatchGroup(ICartesianMesh* cmesh)
46: TraceAccessor(cmesh->traceMng())
47, m_cmesh(cmesh)
48, m_index_new_patches(1)
49, m_size_of_overlap_layer_top_level(0)
50, m_higher_level(0)
51, m_target_nb_levels(0)
52, m_latest_call_level(-2)
53{}
54
55/*---------------------------------------------------------------------------*/
56/*---------------------------------------------------------------------------*/
57
58void CartesianPatchGroup::
59build()
60{
61 m_properties = makeRef(new Properties(*(m_cmesh->mesh()->properties()), "CartesianPatchGroup"));
62}
63
64/*---------------------------------------------------------------------------*/
65/*---------------------------------------------------------------------------*/
66
67void CartesianPatchGroup::
68saveInfosInProperties()
69{
70 m_properties->set("Version", 1);
71
72 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
73 UniqueArray<String> patch_group_names;
74 for (Integer i = 1; i < m_amr_patches_pointer.size(); ++i) {
75 patch_group_names.add(allCells(i).name());
76 }
77 m_properties->set("PatchGroupNames", patch_group_names);
78 }
79
80 else {
81 // Il est inutile de sauvegarder le patch ground. Il sera recalculé.
82 UniqueArray<String> patch_group_names(m_amr_patches_pointer.size() - 1);
83 UniqueArray<Int32> level(m_amr_patches_pointer.size() - 1);
84 UniqueArray<Int32> overlap(m_amr_patches_pointer.size() - 1);
85 UniqueArray<Int32> index(m_amr_patches_pointer.size() - 1);
86 UniqueArray<CartCoord> min_point((m_amr_patches_pointer.size() - 1) * 3);
87 UniqueArray<CartCoord> max_point((m_amr_patches_pointer.size() - 1) * 3);
88
89 for (Integer patch = 1; patch < m_amr_patches_pointer.size(); ++patch) {
90 const Integer pos_in_array = patch - 1;
91 const AMRPatchPosition& position = m_amr_patches_pointer[patch]->_internalApi()->positionRef();
92 level[pos_in_array] = position.level();
93 overlap[pos_in_array] = position.overlapLayerSize();
94 index[pos_in_array] = m_amr_patches_pointer[patch]->index();
95
96 const Integer pos = pos_in_array * 3;
97 min_point[pos + 0] = position.minPoint().x;
98 min_point[pos + 1] = position.minPoint().y;
99 min_point[pos + 2] = position.minPoint().z;
100 max_point[pos + 0] = position.maxPoint().x;
101 max_point[pos + 1] = position.maxPoint().y;
102 max_point[pos + 2] = position.maxPoint().z;
103
104 patch_group_names[pos_in_array] = allCells(patch).name();
105 }
106 m_properties->set("LevelPatches", level);
107 m_properties->set("OverlapSizePatches", overlap);
108 m_properties->set("IndexPatches", index);
109 m_properties->set("MinPointPatches", min_point);
110 m_properties->set("MaxPointPatches", max_point);
111
112 // TODO : Trouver une autre façon de gérer ça.
113 // Dans le cas d'une protection reprise, le tableau m_available_index
114 // ne peut pas être correctement recalculé à cause des éléments après
115 // le "index max" des "index actif". Ces éléments "en trop" ne
116 // peuvent pas être retrouvés sans plus d'infos.
117 m_properties->set("PatchGroupNamesAvailable", m_available_group_index);
118 m_properties->set("PatchGroupNames", patch_group_names);
119 }
120}
121
122/*---------------------------------------------------------------------------*/
123/*---------------------------------------------------------------------------*/
124
125void CartesianPatchGroup::
126recreateFromDump()
127{
128 Trace::Setter mci(traceMng(), "CartesianPatchGroup");
129
130 // Sauve le numéro de version pour être sur que c'est OK en reprise
131 Int32 v = m_properties->getInt32("Version");
132 if (v != 1) {
133 ARCANE_FATAL("Bad serializer version: trying to read from incompatible checkpoint v={0} expected={1}", v, 1);
134 }
135
136 clear();
137 _createGroundPatch();
138
139 // Récupère les noms des groupes des patchs
140 UniqueArray<String> patch_group_names;
141 m_properties->get("PatchGroupNames", patch_group_names);
142
143 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
144 info(4) << "Found n=" << patch_group_names.size() << " patchs";
145
146 IItemFamily* cell_family = m_cmesh->mesh()->cellFamily();
147 for (const String& x : patch_group_names) {
148 CellGroup group = cell_family->findGroup(x);
149 if (group.null())
150 ARCANE_FATAL("Can not find cell group '{0}'", x);
151 _addPatchAfterRestore(group);
152 }
153 }
154 else {
155 UniqueArray<Int32> level;
156 UniqueArray<Int32> overlap;
157 UniqueArray<Int32> index;
158 UniqueArray<CartCoord> min_point;
159 UniqueArray<CartCoord> max_point;
160
161 m_properties->get("LevelPatches", level);
162 m_properties->get("OverlapSizePatches", overlap);
163 m_properties->get("IndexPatches", index);
164 m_properties->get("MinPointPatches", min_point);
165 m_properties->get("MaxPointPatches", max_point);
166
167 IItemFamily* cell_family = m_cmesh->mesh()->cellFamily();
168
169 // À noter : on a exclut le patch ground de la sauvegarde.
170 for (Integer pos_in_array = 0; pos_in_array < index.size(); ++pos_in_array) {
171 ConstArrayView min(min_point.subConstView(pos_in_array * 3, 3));
172 ConstArrayView max(max_point.subConstView(pos_in_array * 3, 3));
173
174 AMRPatchPosition position(
175 level[pos_in_array],
176 { min[MD_DirX], min[MD_DirY], min[MD_DirZ] },
177 { max[MD_DirX], max[MD_DirY], max[MD_DirZ] },
178 overlap[pos_in_array]);
179
180 const String& x = patch_group_names[pos_in_array];
181 CellGroup cell_group = cell_family->findGroup(x);
182 if (cell_group.null())
183 ARCANE_FATAL("Can not find cell group '{0}'", x);
184
185 auto* cdi = new CartesianMeshPatch(m_cmesh, index[pos_in_array], position);
186 _addPatchInstance(makeRef(cdi));
187 _addCellGroup(cell_group, cdi, true);
188 }
189
190 UniqueArray<Int32> available_index;
191 m_properties->get("PatchGroupNamesAvailable", available_index);
192 rebuildAvailableGroupIndex(available_index);
193 }
194}
195
196/*---------------------------------------------------------------------------*/
197/*---------------------------------------------------------------------------*/
198
199Ref<CartesianMeshPatch> CartesianPatchGroup::
200groundPatch()
201{
202 _createGroundPatch();
203 return patch(0);
204}
205
206/*---------------------------------------------------------------------------*/
207/*---------------------------------------------------------------------------*/
208
209void CartesianPatchGroup::
210addPatch(ConstArrayView<Int32> cells_local_id)
211{
212 if (m_cmesh->mesh()->meshKind().meshAMRKind() == eMeshAMRKind::PatchCartesianMeshOnly) {
213 ARCANE_FATAL("Do not use this method with AMR type 3");
214 }
215
216 Integer index = _nextIndexForNewPatch();
217 String children_group_name = String("CartesianMeshPatchCells") + index;
218 IItemFamily* cell_family = m_cmesh->mesh()->cellFamily();
219 CellGroup children_cells = cell_family->createGroup(children_group_name, cells_local_id, true);
220 _addPatch(children_cells, index);
221}
222
223/*---------------------------------------------------------------------------*/
224/*---------------------------------------------------------------------------*/
225
226// Il faut appeler rebuildAvailableIndex() après les appels à cette méthode.
227Integer CartesianPatchGroup::
228_addPatchAfterRestore(CellGroup cell_group)
229{
230 const String& name = cell_group.name();
231 Integer group_index = -1;
232 if (name.startsWith("CartesianMeshPatchCells")) {
233 String index_str = name.substring(23);
234 group_index = std::stoi(index_str.localstr());
235 }
236 else {
237 ARCANE_FATAL("Invalid group");
238 }
239
240 _addPatch(cell_group, group_index);
241 return group_index;
242}
243
244/*---------------------------------------------------------------------------*/
245/*---------------------------------------------------------------------------*/
246
247void CartesianPatchGroup::
248_addPatch(CellGroup cell_group, Integer group_index)
249{
250 _createGroundPatch();
251 if (group_index == -1) {
252 return;
253 }
254 if (cell_group.null())
255 ARCANE_FATAL("Null cell group");
256
257 AMRPatchPosition position;
258
259 auto* cdi = new CartesianMeshPatch(m_cmesh, group_index, position);
260 _addPatchInstance(makeRef(cdi));
261 _addCellGroup(cell_group, cdi, true);
262}
263
264/*---------------------------------------------------------------------------*/
265/*---------------------------------------------------------------------------*/
266
267void CartesianPatchGroup::
268addPatch(const AMRZonePosition& zone_position)
269{
270 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
271 ARCANE_FATAL("Method available only with AMR PatchCartesianMeshOnly");
272 }
273
274 Trace::Setter mci(traceMng(), "CartesianPatchGroup");
275
276 info() << "addPatch() with zone"
277 << " -- Position : " << zone_position.position()
278 << " -- Length : " << zone_position.length();
279
280 clearRefineRelatedFlags();
281
282 auto amr = m_cmesh->_internalApi()->cartesianMeshAMRPatchMng();
283 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
284
285 // La conversion nous donne le patch intermédiaire (qui entoure les mailles
286 // à raffiner et non les mailles raffinées). Un appel à la méthode
287 // AMRPatchPosition::patchUp() permet de monter le patch d'un niveau afin
288 // qu'il regroupe les mailles raffinées, devenant ainsi un patch "classique".
289 AMRPatchPosition position = zone_position.toAMRPatchPosition(m_cmesh);
290
291 Int32 level = position.level();
292 Int32 level_up = level + 1;
293 Int32 nb_overlap_cells = 0;
294
295 Int32 higher_level = m_higher_level;
296
297 // La méthode patchUp() aura besoin du futur higher_level pour calculer
298 // correctement le nombre de couches de mailles de recouvrement.
299 // Si on a un patch qui sera plus haut que tous les autres.
300 if (level_up >= higher_level) {
301 higher_level = level_up;
302 // Le nombre de couches du niveau le plus haut devra être
303 // m_size_of_overlap_layer_top_level. On est sur un patch intermédiaire,
304 // donc on divise ce nombre par le nombre de mailles enfants qui seront
305 // créées.
306 nb_overlap_cells = m_size_of_overlap_layer_top_level / numbering->pattern();
307 debug() << "Higher level -- Old : " << m_higher_level << " -- New : " << higher_level;
308 }
309
310 else {
311 // Le nombre de couches de mailles de recouvrements.
312 // +1 car le patch créé sera de niveau level + 1.
313 // /pattern car les mailles à raffiner sont sur le niveau level.
314 //
315 // Explication :
316 // level=0,
317 // le futur patch sera de niveau 1, donc le nombre de couches de
318 // recouvrement doit être celui correspondant au niveau 1
319 // (donc level+1),
320 // or, les mailles à raffiner sont de niveau 0, donc on doit diviser le
321 // nombre de couches par le nombre de mailles enfants qui seront créées
322 // (pour une dimension) (donc numbering->pattern()).
323 nb_overlap_cells = overlapLayerSize(level + 1) / numbering->pattern();
324 }
325 position.setOverlapLayerSize(nb_overlap_cells);
326
327 debug() << "Zone to intermediary patch"
328 << " -- minPoint : " << position.minPoint()
329 << " -- maxPoint : " << position.maxPoint()
330 << " -- overlapLayerSize : " << position.overlapLayerSize()
331 << " -- level : " << level;
332
333 // Rappel : on ne peut raffiner que les mailles ayant le flag "II_InPatch".
334 // Cette condition est vérifiée dans la méthode
335 // AMRZonePosition::toAMRPatchPosition() appelée au-dessus.
336 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level)) {
337 if (!icell->hasHChildren()) {
338 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
339 if (position.isInWithOverlap(pos)) {
340 icell->mutableItemBase().addFlags(ItemFlags::II_Refine);
341 }
342 }
343 }
344
345 amr->refine();
346
347 // On passe d'un patch intermédiaire à un patch classique.
348 AMRPatchPosition position_up = position.patchUp(m_cmesh->mesh()->dimension(), higher_level, m_size_of_overlap_layer_top_level);
349
350 info() << "Zone to Patch"
351 << " -- minPoint : " << position_up.minPoint()
352 << " -- maxPoint : " << position_up.maxPoint()
353 << " -- overlapLayerSize : " << position_up.overlapLayerSize()
354 << " -- level : " << position_up.level();
355
356 // On ajoute ce patch dans notre objet.
357 _addPatch(position_up);
358
359 // Si le patch créé est plus haut que les autres, il y a eu création d'un
360 // nouveau niveau de raffinement et on doit mettre à jour le nombre de
361 // couches de mailles de recouvrement des niveaux plus bas.
362 _updateHigherLevel();
363
364#ifdef ARCANE_CHECK
365 _checkPatchesAndMesh();
366#endif
367}
368
369/*---------------------------------------------------------------------------*/
370/*---------------------------------------------------------------------------*/
371
372Integer CartesianPatchGroup::
373nbPatch() const
374{
375 return m_amr_patches.size();
376}
377
378/*---------------------------------------------------------------------------*/
379/*---------------------------------------------------------------------------*/
380
381Ref<CartesianMeshPatch> CartesianPatchGroup::
382patch(const Integer index) const
383{
384 return m_amr_patches[index];
385}
386
387/*---------------------------------------------------------------------------*/
388/*---------------------------------------------------------------------------*/
389
390CartesianMeshPatchListView CartesianPatchGroup::
391patchListView() const
392{
393 return CartesianMeshPatchListView{ m_amr_patches_pointer };
394}
395
396/*---------------------------------------------------------------------------*/
397/*---------------------------------------------------------------------------*/
398
399CellGroup CartesianPatchGroup::
400allCells(const Integer index)
401{
402 return m_amr_patch_cell_groups_all[index];
403}
404
405/*---------------------------------------------------------------------------*/
406/*---------------------------------------------------------------------------*/
407
408CellGroup CartesianPatchGroup::
409inPatchCells(Integer index)
410{
411 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
412 ARCANE_FATAL("Method available only with AMR PatchCartesianMeshOnly");
413 }
414 return m_amr_patch_cell_groups_inpatch[index];
415}
416
417/*---------------------------------------------------------------------------*/
418/*---------------------------------------------------------------------------*/
419
420CellGroup CartesianPatchGroup::
421overlapCells(Integer index)
422{
423 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
424 ARCANE_FATAL("Method available only with AMR PatchCartesianMeshOnly");
425 }
426 return m_amr_patch_cell_groups_overlap[index];
427}
428
429/*---------------------------------------------------------------------------*/
430/*---------------------------------------------------------------------------*/
431
432// Attention : efface aussi le ground patch. Nécessaire de le récupérer après coup.
433// (le m_all_items_direction_info de CartesianMeshImpl)
434void CartesianPatchGroup::
435clear()
436{
437 _removeAllPatches();
438}
439
440/*---------------------------------------------------------------------------*/
441/*---------------------------------------------------------------------------*/
442
443void CartesianPatchGroup::
444removePatch(const Integer index)
445{
446 if (m_patches_to_delete.contains(index)) {
447 return;
448 }
449 if (index == 0) {
450 ARCANE_FATAL("You cannot remove ground patch");
451 }
452 if (index < 1 || index >= m_amr_patches.size()) {
453 ARCANE_FATAL("Invalid index");
454 }
455
456 m_patches_to_delete.add(index);
457}
458
459/*---------------------------------------------------------------------------*/
460/*---------------------------------------------------------------------------*/
461
462void CartesianPatchGroup::
463removeCellsInAllPatches(ConstArrayView<Int32> cells_local_id)
464{
465 if (m_cmesh->mesh()->meshKind().meshAMRKind() == eMeshAMRKind::PatchCartesianMeshOnly) {
466 ARCANE_FATAL("Method available only with AMR Cell");
467 }
468
469 // Dans l'AMR type 1, il n'y a que les groupes "all".
470 for (Integer i = 1; i < m_amr_patch_cell_groups_all.size(); ++i) {
471 allCells(i).removeItems(cells_local_id);
472 }
473 applyPatchEdit(true, false);
474}
475
476/*---------------------------------------------------------------------------*/
477/*---------------------------------------------------------------------------*/
478
479void CartesianPatchGroup::
480_removeCellsInAllPatches(const AMRPatchPosition& zone_to_delete)
481{
482 // Attention si suppression de la suppression en deux étapes : _removePartOfPatch() supprime aussi des patchs.
483 // i = 1 car on ne peut pas déraffjner le patch ground.
484 const Integer nb_patchs = m_amr_patches_pointer.size();
485 for (Integer i = 1; i < nb_patchs; ++i) {
486 ICartesianMeshPatch* patch = m_amr_patches_pointer[i];
487 // info() << "I : " << i
488 // << " -- Compare Patch (min : " << patch->position().minPoint()
489 // << ", max : " << patch->position().maxPoint()
490 // << ", level : " << patch->position().level()
491 // << ") and Zone (min : " << zone_to_delete.minPoint()
492 // << ", max : " << zone_to_delete.maxPoint()
493 // << ", level : " << zone_to_delete.level() << ")";
494
495 if (zone_to_delete.haveIntersection(patch->position())) {
496 _removePartOfPatch(i, zone_to_delete);
497 }
498 }
499}
500
501/*---------------------------------------------------------------------------*/
502/*---------------------------------------------------------------------------*/
503
504void CartesianPatchGroup::
505removeCellsInZone(const AMRZonePosition& zone_to_delete)
506{
507 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
508 ARCANE_FATAL("Method available only with AMR PatchCartesianMeshOnly");
509 }
510 clearRefineRelatedFlags();
511
512 UniqueArray<Int32> cells_local_id;
513
514 AMRPatchPosition patch_position;
515 zone_to_delete.cellsInPatch(m_cmesh, cells_local_id, patch_position);
516
517 _removeCellsInAllPatches(patch_position);
518 applyPatchEdit(false, false);
519 _updatePatchFlagsOfItemsLevel(patch_position.level(), true);
520 _updateHigherLevel();
521 _coarsenUselessCells(true);
522
523#ifdef ARCANE_CHECK
524 _checkPatchesAndMesh();
525#endif
526}
527
528/*---------------------------------------------------------------------------*/
529/*---------------------------------------------------------------------------*/
530
531void CartesianPatchGroup::
532applyPatchEdit(bool remove_empty_patches, bool update_higher_level)
533{
534 // m_cmesh->mesh()->traceMng()->info() << "applyPatchEdit() -- Remove nb patch : " << m_patches_to_delete.size();
535
536 std::stable_sort(m_patches_to_delete.begin(), m_patches_to_delete.end(),
537 [](const Integer a, const Integer b) {
538 return a < b;
539 });
540
541 _removeMultiplePatches(m_patches_to_delete);
542 m_patches_to_delete.clear();
543
544 // Dans l'AMR type 3, il ne peut pas y avoir de patch vide.
545 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly && remove_empty_patches) {
546 UniqueArray<Integer> size_of_patches(m_amr_patch_cell_groups_all.size());
547 for (Integer i = 0; i < m_amr_patch_cell_groups_all.size(); ++i) {
548 size_of_patches[i] = m_amr_patch_cell_groups_all[i].size();
549 }
550 m_cmesh->mesh()->parallelMng()->reduce(MessagePassing::ReduceMax, size_of_patches);
551 for (Integer i = 0; i < size_of_patches.size(); ++i) {
552 if (size_of_patches[i] == 0) {
553 m_patches_to_delete.add(i);
554 }
555 }
556 _removeMultiplePatches(m_patches_to_delete);
557 m_patches_to_delete.clear();
558 }
559
560 // Dans l'AMR type 1, il n'y a pas de notion de niveau de patch.
561 if (m_cmesh->mesh()->meshKind().meshAMRKind() == eMeshAMRKind::PatchCartesianMeshOnly && update_higher_level) {
562 _updateHigherLevel();
563 _coarsenUselessCells(true);
564 }
565}
566
567/*---------------------------------------------------------------------------*/
568/*---------------------------------------------------------------------------*/
569
570void CartesianPatchGroup::
571updateLevelsAndAddGroundPatch()
572{
573 // TODO : Cette méthode devrait appeler createSubLevel(), pas l'inverse.
574 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
575 return;
576 }
577 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
578 auto amr = m_cmesh->_internalApi()->cartesianMeshAMRPatchMng();
579
580 amr->createSubLevel();
581
582 // Attention : on suppose que numbering->updateFirstLevel(); a déjà été appelé !
583
584 for (ICartesianMeshPatch* patch : m_amr_patches_pointer) {
585 const Int32 level = patch->position().level();
586 // Si le niveau est 0, c'est le patch spécial 0 donc on ne modifie que le max, le niveau reste à 0.
587 if (level == 0) {
588 const CartCoord3 max_point = patch->position().maxPoint();
589 if (m_cmesh->mesh()->dimension() == 2) {
590 patch->_internalApi()->positionRef().setMaxPoint({
591 numbering->offsetLevelToLevel(max_point.x, level, level - 1),
592 numbering->offsetLevelToLevel(max_point.y, level, level - 1),
593 1,
594 });
595 }
596 else {
597 patch->_internalApi()->positionRef().setMaxPoint({
598 numbering->offsetLevelToLevel(max_point.x, level, level - 1),
599 numbering->offsetLevelToLevel(max_point.y, level, level - 1),
600 numbering->offsetLevelToLevel(max_point.z, level, level - 1),
601 });
602 }
603 }
604 // Sinon, on "surélève" le niveau des patchs vu qu'il va y avoir le patch "-1"
605 else {
606 patch->_internalApi()->positionRef().setLevel(level + 1);
607 }
608 }
609
610 {
611 AMRPatchPosition old_ground;
612 old_ground.setLevel(1);
613 old_ground.setMinPoint({ 0, 0, 0 });
614 old_ground.setMaxPoint({ numbering->globalNbCellsX(1), numbering->globalNbCellsY(1), numbering->globalNbCellsZ(1) });
615 old_ground.computeOverlapLayerSize(m_higher_level + 1, m_size_of_overlap_layer_top_level);
616 _addPatch(old_ground);
617 }
618 // Calcul des directions du nouveau patch ground.
619 m_cmesh->computeDirectionsPatchV2(0);
620
621 _updatePatchFlagsOfItemsGroundLevel();
622
623 // Les méthodes _increaseOverlapSizeLevel() et _reduceOverlapSizeLevel()
624 // s'occuperont de recalculer les directions des patchs surélevés.
625 // Note : Le recalcul est nécessaire car on ajoute/supprime des mailles de
626 // recouvrement.
627 _updateHigherLevel();
628
629#ifdef ARCANE_CHECK
630 _checkPatchesAndMesh();
631#endif
632}
633
634/*---------------------------------------------------------------------------*/
635/*---------------------------------------------------------------------------*/
636
637Integer CartesianPatchGroup::
638_nextIndexForNewPatch()
639{
640 if (!m_available_group_index.empty()) {
641 const Integer elem = m_available_group_index.back();
642 m_available_group_index.popBack();
643 return elem;
644 }
645 return m_index_new_patches++;
646}
647
648/*---------------------------------------------------------------------------*/
649/*---------------------------------------------------------------------------*/
650
651void CartesianPatchGroup::
652mergePatches()
653{
654 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
655 return;
656 }
657 UniqueArray<Int32> new_merged_patches;
658
659 // info() << "Global fusion";
660 UniqueArray<std::pair<Integer, Int64>> index_n_nb_cells;
661 {
662 Integer index = 0;
663 for (auto patch : m_amr_patches_pointer) {
664 index_n_nb_cells.add({ index++, patch->position().nbCells() });
665 }
666 }
667
668 // Algo de fusion.
669 // D'abord, on trie les patchs du plus petit nb de mailles au plus grand nb de mailles (optionnel).
670 // Ensuite, pour chaque patch, on regarde si l'on peut le fusionner avec un autre.
671 // Si on arrive à faire une fusion, on recommence l'algo jusqu'à ne plus pouvoir fusionner.
672 bool fusion = true;
673 while (fusion) {
674 fusion = false;
675
676 std::stable_sort(index_n_nb_cells.begin(), index_n_nb_cells.end(),
677 [](const std::pair<Integer, Int64>& a, const std::pair<Integer, Int64>& b) {
678 return a.second < b.second;
679 });
680
681 for (Integer p0 = 0; p0 < index_n_nb_cells.size(); ++p0) {
682 auto [index_p0, nb_cells_p0] = index_n_nb_cells[p0];
683
684 AMRPatchPosition& patch_fusion_0 = m_amr_patches_pointer[index_p0]->_internalApi()->positionRef();
685 if (patch_fusion_0.isNull())
686 continue;
687
688 // Si une fusion a déjà eu lieu, on doit alors regarder les patchs avant "p0"
689 // (vu qu'il y en a au moins un qui a été modifié).
690 // (une "optimisation" pourrait être de récupérer la position du premier
691 // patch fusionné mais bon, moins lisible + pas beaucoup de patchs).
692 for (Integer p1 = p0 + 1; p1 < m_amr_patches_pointer.size(); ++p1) {
693 auto [index_p1, nb_cells_p1] = index_n_nb_cells[p1];
694
695 AMRPatchPosition& patch_fusion_1 = m_amr_patches_pointer[index_p1]->_internalApi()->positionRef();
696 if (patch_fusion_1.isNull())
697 continue;
698
699 // info() << "\tCheck fusion"
700 // << " -- 0 Min point : " << patch_fusion_0.minPoint()
701 // << " -- 0 Max point : " << patch_fusion_0.maxPoint()
702 // << " -- 0 Level : " << patch_fusion_0.level()
703 // << " -- 1 Min point : " << patch_fusion_1.minPoint()
704 // << " -- 1 Max point : " << patch_fusion_1.maxPoint()
705 // << " -- 1 Level : " << patch_fusion_1.level();
706
707 if (patch_fusion_0.fusion(patch_fusion_1)) {
708 // info() << "Fusion OK";
709 index_n_nb_cells[p0].second = patch_fusion_0.nbCells();
710
711 // info() << "Remove patch : " << index_p1;
712 removePatch(index_p1);
713
714 if (!new_merged_patches.contains(index_p0)) {
715 new_merged_patches.add(index_p0);
716 }
717
718 auto find_p1 = new_merged_patches.span().findFirst(index_p1);
719 if (find_p1.has_value()) {
720 new_merged_patches.remove(find_p1.value());
721 }
722
723 fusion = true;
724 break;
725 }
726 }
727 if (fusion) {
728 break;
729 }
730 }
731 }
732
733 UniqueArray<Int32> levels_edited;
734 for (Int32 patch_index : new_merged_patches) {
735 _updateCellGroups(patch_index, false);
736
737 Int32 level = patch(patch_index)->_internalApi()->positionRef().level();
738 if (!levels_edited.contains(level)) {
739 levels_edited.add(level);
740 }
741 }
742 applyPatchEdit(false, false);
743
744 for (Int32 level : levels_edited) {
745 _updatePatchFlagsOfItemsLevel(level, true);
746 }
747
748#ifdef ARCANE_CHECK
749 _checkPatchesAndMesh();
750#endif
751}
752
753/*---------------------------------------------------------------------------*/
754/*---------------------------------------------------------------------------*/
755
756void CartesianPatchGroup::
757beginAdaptMesh(Int32 nb_levels, Int32 level_to_refine_first)
758{
759 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
760 ARCANE_FATAL("Method available only with AMR PatchCartesianMeshOnly");
761 }
762 if (m_latest_call_level != -2) {
763 ARCANE_FATAL("Call endAdaptMesh() before restart mesh adaptation");
764 }
765 if (level_to_refine_first > m_higher_level) {
766 ARCANE_FATAL("Cannot begin to refine level higher than the actual higher level -- Level to refine first : {0} -- Higher level : {1}", level_to_refine_first, m_higher_level);
767 }
768
769 Trace::Setter mci(traceMng(), "CartesianPatchGroup");
770 info() << "Begin adapting mesh with higher level = " << (nb_levels - 1);
771
772 // On supprime tous les patchs au-dessus du premier niveau à raffiner.
773 Int32 max_level = 0;
774 for (Integer p = 1; p < m_amr_patches_pointer.size(); ++p) {
775 Int32 level = m_amr_patches_pointer[p]->_internalApi()->positionRef().level();
776 if (level > level_to_refine_first) {
777 removePatch(p);
778 max_level = level;
779 }
780 }
781 applyPatchEdit(false, false);
782
783 // On enlève aussi les flags II_InPatch et II_Overlap des mailles pour que
784 // celles qui ne sont plus utilisées par la suite dans un des nouveaux
785 // patchs soit supprimées dans la méthode finalizeAdaptMesh().
786 for (Integer l = level_to_refine_first + 1; l <= max_level; ++l) {
787 _removePatchFlagsOfItemsLevel(l);
788 }
789 // On doit adapter tous les niveaux sous le niveau à adapter.
790 // Les patchs du niveau "level_to_refine_first" (exclus) et plus seront supprimés.
791 if (nb_levels - 1 != m_higher_level) {
792 debug() << "beginAdaptMesh() -- Change overlap layer size -- Old higher level : " << m_higher_level
793 << " -- Asked higher level : " << (nb_levels - 1)
794 << " -- Adapt level lower than : " << level_to_refine_first;
795
796 for (Int32 level = 1; level <= level_to_refine_first; ++level) {
797 _changeOverlapSizeLevel(level, m_higher_level, nb_levels - 1);
798 }
799 }
800
801 m_target_nb_levels = nb_levels;
802 m_latest_call_level = level_to_refine_first - 1;
803 // m_higher_level conserve son ancienne valeur.
804}
805
806/*---------------------------------------------------------------------------*/
807/*---------------------------------------------------------------------------*/
808
809void CartesianPatchGroup::
810endAdaptMesh()
811{
812 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
813 ARCANE_FATAL("Method available only with AMR PatchCartesianMeshOnly");
814 }
815 if (m_latest_call_level == -2) {
816 ARCANE_FATAL("Call beginAdaptMesh() before");
817 }
818 Trace::Setter mci(traceMng(), "CartesianPatchGroup");
819 info() << "Finalizing adapting mesh with higher level = " << (m_target_nb_levels - 1);
820
821 auto amr = m_cmesh->_internalApi()->cartesianMeshAMRPatchMng();
822
823 // Le plus haut niveau devient le dernier niveau adapté (+1 pour avoir le
824 // niveau raffiné).
825 // On est sûr que c'est le niveau le plus haut étant donné que l'on supprime
826 // systématiquement les patchs au-dessus dans adaptLevel().
827 // beginAdaptMesh() met le premier niveau à raffiner donné par l'utilisateur
828 // dans l'attribut m_latest_call_level et vérifie si le niveau existe. Le
829 // premier m_latest_call_level est donc valide.
830 m_higher_level = m_latest_call_level + 1;
831
832 // Si m_latest_call_level == 0, alors adaptLevel() a créée le niveau 1 donc
833 // il y a 2 niveaux.
834 // Si le niveau le plus haut créé est inférieur au niveau le plus haut donné
835 // par l'utilisateur dans la méthode beginAdaptMesh(), on est obligé de
836 // réadapter le nombre de couche de mailles de recouvrement pour chaque
837 // patch.
838 if (m_higher_level + 1 < m_target_nb_levels) {
839 info() << "Reduce higher level from " << (m_target_nb_levels - 1) << " to " << m_higher_level;
840
841 for (Int32 level = 1; level <= m_higher_level; ++level) {
842 _changeOverlapSizeLevel(level, m_target_nb_levels - 1, m_higher_level);
843 }
844 }
845
846 _coarsenUselessCells(true);
847
848 m_target_nb_levels = 0;
849 m_latest_call_level = -2;
850 clearRefineRelatedFlags();
851
852 info() << "Patch list:";
853
854 for (Integer i = 0; i <= m_higher_level; ++i) {
855 for (auto p : m_amr_patches_pointer) {
856 auto& position = p->_internalApi()->positionRef();
857 if (position.level() == i) {
858 info() << "\tPatch #" << p->index()
859 << " -- Level : " << position.level()
860 << " -- Min point : " << position.minPoint()
861 << " -- Max point : " << position.maxPoint()
862 << " -- Overlap layer size : " << position.overlapLayerSize();
863 }
864 }
865 }
866#ifdef ARCANE_CHECK
867 _checkPatchesAndMesh();
868#endif
869}
870
871/*---------------------------------------------------------------------------*/
872/*---------------------------------------------------------------------------*/
873
874void CartesianPatchGroup::
875adaptLevel(Int32 level_to_adapt, bool do_fatal_if_useless)
876{
877 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
878 ARCANE_FATAL("Method available only with AMR PatchCartesianMeshOnly");
879 }
880 if (m_latest_call_level == -2) {
881 ARCANE_FATAL("Call beginAdaptMesh() before to begin a mesh adaptation");
882 }
883 if (level_to_adapt + 1 >= m_target_nb_levels || level_to_adapt < 0) {
884 ARCANE_FATAL("Bad level to adapt -- Level to adapt : {0} (creating level {1}) -- Max nb levels : {2}", level_to_adapt, level_to_adapt + 1, m_target_nb_levels);
885 }
886
887 Trace::Setter mci(traceMng(), "CartesianPatchGroup");
888
889 if (level_to_adapt > m_latest_call_level + 1) {
890 if (do_fatal_if_useless) {
891 ARCANE_FATAL("You must refine level {0} before.", (m_latest_call_level + 1));
892 }
893 warning() << String::format("Useless call -- You must refine level {0} before.", (m_latest_call_level + 1));
894 return;
895 }
896
897 // On supprime tous les patchs au-dessus du niveau que l'on souhaite adapter.
898 // On le fait aussi ici dans le cas où l'utilisateur appelle cette méthode
899 // avec un niveau inférieur à son précedent appel (ce qui n'est pas
900 // forcément optimal vu qu'on supprime ce qui a été calculé
901 // précédemment...).
902 if (level_to_adapt < m_latest_call_level) {
903 Int32 max_level = 0;
904 for (Integer p = 1; p < m_amr_patches_pointer.size(); ++p) {
905 Int32 level = m_amr_patches_pointer[p]->_internalApi()->positionRef().level();
906 if (level > level_to_adapt) {
907 removePatch(p);
908 max_level = level;
909 }
910 }
911 applyPatchEdit(false, false);
912
913 for (Integer l = level_to_adapt + 1; l <= max_level; ++l) {
914 _removePatchFlagsOfItemsLevel(l);
915 }
916 }
917
918 auto amr = m_cmesh->_internalApi()->cartesianMeshAMRPatchMng();
919 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
920
921 // Le nombre de couches de mailles de recouvrements.
922 // +1 car les patchs créés seront de niveau level_to_adapt + 1.
923 // /pattern car les mailles à raffiner sont sur le niveau level_to_adapt.
924 //
925 // Explication :
926 // level_to_adapt=0,
927 // les futurs patchs seront de niveau 1, donc le nombre de couches de
928 // recouvrement doit être celui correspondant au niveau 1
929 // (donc level_to_adapt+1),
930 // or, les mailles à raffiner sont de niveau 0, donc on doit diviser le
931 // nombre de couches par le nombre de mailles enfants qui seront créées
932 // (pour une dimension) (donc numbering->pattern()).
933 Int32 nb_overlap_cells = overlapLayerSize(level_to_adapt + 1) / numbering->pattern();
934
935 info() << "adaptLevel()"
936 << " -- Level to adapt : " << level_to_adapt
937 << " -- Nb of overlap cells (intermediary patch) : " << nb_overlap_cells;
938
939 // Deux vérifications :
940 // - on ne peut pas raffiner plusieurs niveaux d'un coup,
941 // - on ne peut pas raffiner des mailles qui ne sont pas dans un patch (les
942 // mailles de recouvrements ne sont pas forcément dans un patch).
943 // De plus, on doit savoir s'il y a au moins une maille avec le flag
944 // II_Refine pour savoir si c'est utile de continuer la méthode ou non.
945 bool has_cell_to_refine = false;
946 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allCells()) {
947 if (icell->hasFlags(ItemFlags::II_Refine)) {
948 if (icell->level() != level_to_adapt) {
949 ARCANE_FATAL("Flag II_Refine found on Cell (UID={0} - Level={1}) not in level to refine (={2})", icell->uniqueId(), icell->level(), level_to_adapt);
950 }
951 if (level_to_adapt != 0 && !icell->hasFlags(ItemFlags::II_InPatch)) {
952 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
953 ARCANE_FATAL("Cannot refine cell not in patch -- Pos : {0} -- CellUID : {1} -- CellLevel : {2}", pos, icell->uniqueId(), icell->level());
954 }
955 has_cell_to_refine = true;
956 }
957 }
958 has_cell_to_refine = m_cmesh->mesh()->parallelMng()->reduce(MessagePassing::ReduceMax, has_cell_to_refine);
959
960 if (!has_cell_to_refine) {
961 if (do_fatal_if_useless) {
962 ARCANE_FATAL("There are no cells to refine.");
963 }
964 // On rappelle que, dans endAdaptMesh(), m_higher_level prendra la valeur
965 // de m_latest_call_level +1.
966 //
967 // Il est important de mettre -1 ici dans le cas où (exemple) :
968 // - Initialement, pas de patchs (m_latest_call_level == -1), adaptLevel(0) :
969 // -> On raffine des mailles niveau 0, donc m_latest_call_level = 0 et
970 // donc, m_higher_level sera égal à 1
971 // - On refait une seconde fois adaptLevel(0) :
972 // -> L'utilisateur n'a marqué aucune maille de niveau 0, donc
973 // m_latest_call_level = -1 et donc m_higher_level = 0.
974 // Au-dessus, on supprime les niveaux supérieurs à level_to_adapt même si
975 // l'appel à adaptLevel() ne raffine pas de maille, on doit donc mettre à
976 // jour m_latest_call_level.
977 m_latest_call_level = level_to_adapt - 1;
978 debug() << "adaptLevel() -- End call -- No refine -- Actual patch list:";
979
980 for (Integer i = 0; i <= m_target_nb_levels; ++i) {
981 for (auto p : m_amr_patches_pointer) {
982 auto& position = p->_internalApi()->positionRef();
983 if (position.level() == i) {
984 debug() << "\tPatch #" << p->index()
985 << " -- Level : " << position.level()
986 << " -- Min point : " << position.minPoint()
987 << " -- Max point : " << position.maxPoint()
988 << " -- Overlap layer size : " << position.overlapLayerSize();
989 }
990 }
991 }
992 return;
993 }
994
995 m_latest_call_level = level_to_adapt;
996
997 UniqueArray<AMRPatchPositionSignature> sig_array;
998
999 // On doit donner un ou plusieurs patchs initiaux, pour être réduit et
1000 // découpé.
1001 // Si le niveau à adapter est le niveau 0, on peut créer un patch initial
1002 // qui fait la taille du patch ground.
1003 // On n'a pas besoin de le réduire, AMRPatchPositionSignature::fillSig()
1004 // s'en occupera.
1005 if (level_to_adapt == 0) {
1006 AMRPatchPosition all_level;
1007 all_level.setLevel(level_to_adapt);
1008 all_level.setMinPoint({ 0, 0, 0 });
1009 all_level.setMaxPoint({ numbering->globalNbCellsX(level_to_adapt), numbering->globalNbCellsY(level_to_adapt), numbering->globalNbCellsZ(level_to_adapt) });
1010 // Pour ce setOverlapLayerSize(), voir l'explication au-dessus.
1011 all_level.setOverlapLayerSize(nb_overlap_cells);
1012 AMRPatchPositionSignature sig(all_level, m_cmesh);
1013 sig_array.add(sig);
1014 }
1015
1016 // Pour les autres niveaux, on crée les patchs initiaux en copiant les
1017 // patchs du niveau level_to_adapt.
1018 // On ne peut pas créer un patch qui fait la taille du niveau level_to_adapt
1019 // car il est impératif que le ou les patchs générés par
1020 // AMRPatchPositionSignatureCut (futurs patchs du niveau level_to_adapt+1)
1021 // soit inclus dans le ou les patchs du niveau level_to_adapt ! (sinon on
1022 // aurait des mailles orphelines).
1023 // On peut prendre ces patchs comme patchs initiaux car on sait que les
1024 // seules mailles que l'on aura à raffiner sont dans le ou les patchs du
1025 // niveau level_to_adapt (les mailles ayant le flag II_InPatch).
1026 // On sait aussi que les méthodes de AMRPatchPositionSignatureCut ne peuvent
1027 // pas agrandir les patchs initiaux (uniquement réduire ou couper).
1028 // (et oui, le if(level_to_adapt == 0) n'est pas indispensable, mais comme
1029 // on sait qu'il y a qu'un seul patch de niveau 0, c'est plus rapide).
1030 else {
1031 for (auto patch : m_amr_patches_pointer) {
1032 Integer level = patch->_internalApi()->positionRef().level();
1033 if (level == level_to_adapt) {
1034 auto position = patch->position();
1035 position.setOverlapLayerSize(nb_overlap_cells);
1036 AMRPatchPositionSignature sig(position, m_cmesh);
1037 sig_array.add(sig);
1038 }
1039 }
1040 }
1041
1042 AMRPatchPositionSignatureCut::cut(sig_array);
1043
1044 // Une fois les patchs découpés, on ajoute le flag II_Refine aux mailles de
1045 // ces patchs.
1046 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level_to_adapt)) {
1047 if (!icell->hasHChildren()) {
1048 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
1049 for (const AMRPatchPositionSignature& patch_signature : sig_array) {
1050 if (patch_signature.patch().isInWithOverlap(pos)) {
1051 if (!icell->hasFlags(ItemFlags::II_InPatch) && !icell->hasFlags(ItemFlags::II_Overlap)) {
1052 ARCANE_FATAL("Internal error -- Refine algo error -- Pos : {0}", pos);
1053 }
1054 icell->mutableItemBase().addFlags(ItemFlags::II_Refine);
1055 }
1056 }
1057 }
1058 }
1059
1060 {
1061 // UniqueArray<CartCoord> out(numbering->globalNbCellsY(level_to_adapt) * numbering->globalNbCellsX(level_to_adapt), -1);
1062 // Array2View av_out(out.data(), numbering->globalNbCellsY(level_to_adapt), numbering->globalNbCellsX(level_to_adapt));
1063 // ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level_to_adapt)) {
1064 // CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
1065 // if (icell->hasHChildren()) {
1066 // av_out(pos.y, pos.x) = 0;
1067 // }
1068 // if (icell->hasFlags(ItemFlags::II_Refine)) {
1069 // av_out(pos.y, pos.x) = 1;
1070 // }
1071 // }
1072 //
1073 // StringBuilder str = "";
1074 // for (CartCoord i = 0; i < numbering->globalNbCellsX(level_to_adapt); ++i) {
1075 // str += "\n";
1076 // for (CartCoord j = 0; j < numbering->globalNbCellsY(level_to_adapt); ++j) {
1077 // CartCoord c = av_out(i, j);
1078 // if (c == 1)
1079 // str += "[++]";
1080 // else if (c == 0)
1081 // str += "[XX]";
1082 // else
1083 // str += "[ ]";
1084 // }
1085 // }
1086 // info() << str;
1087 }
1088
1089 // On raffine.
1090 amr->refine();
1091
1092 // TODO : Normalement, il n'y a pas besoin de faire ça, à corriger dans amr->refine().
1093 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level_to_adapt)) {
1094 icell->mutableItemBase().removeFlags(ItemFlags::II_Refine);
1095 }
1096
1097 // Les patchs de sig_array sont des patchs "intermédiaires". Ce sont des
1098 // patchs de niveau level_to_adapt représentant des patchs de niveau
1099 // level_to_adapt+1.
1100 // Il est maintenant nécessaire de les convertir en patch de niveau
1101 // level_to_adapt+1.
1102 UniqueArray<AMRPatchPosition> all_patches;
1103 for (const auto& elem : sig_array) {
1104 all_patches.add(elem.patch().patchUp(m_cmesh->mesh()->dimension(), m_target_nb_levels - 1, m_size_of_overlap_layer_top_level));
1105 }
1106
1107 // On fusionne les patchs qui peuvent l'être avant de les "ajouter" dans le maillage.
1108 AMRPatchPositionLevelGroup::fusionPatches(all_patches, true);
1109
1110 // for (const AMRPatchPosition& patch : all_patches) {
1111 // debug() << "\tPatch AAA"
1112 // << " -- Level : " << patch.level()
1113 // << " -- Min point : " << patch.minPoint()
1114 // << " -- Max point : " << patch.maxPoint()
1115 // << " -- overlapLayerSize : " << patch.overlapLayerSize();
1116 // }
1117
1118 {
1119 // UniqueArray<CartCoord> out(numbering->globalNbCellsY(level_to_adapt + 1) * numbering->globalNbCellsX(level_to_adapt + 1), -1);
1120 // Array2View av_out(out.data(), numbering->globalNbCellsY(level_to_adapt + 1), numbering->globalNbCellsX(level_to_adapt + 1));
1121 // ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level_to_adapt + 1)) {
1122 //
1123 // CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
1124 // Integer patch = -1;
1125 //
1126 // if (icell->hasFlags(ItemFlags::II_Overlap) && icell->hasFlags(ItemFlags::II_InPatch)) {
1127 // patch = -2;
1128 // }
1129 // else if (icell->hasFlags(ItemFlags::II_Overlap)) {
1130 // patch = -3;
1131 // }
1132 // else if (icell->hasFlags(ItemFlags::II_InPatch)) {
1133 // patch = -4;
1134 // }
1135 // else {
1136 // patch = -5;
1137 // }
1138 // av_out(pos.y, pos.x) = patch;
1139 // if (icell->uniqueId() == 3310) {
1140 // info() << "Maille présente ! -- Coord : " << pos << " -- Flags : " << patch;
1141 // }
1142 // }
1143 //
1144 // StringBuilder str = "";
1145 // for (CartCoord i = 0; i < numbering->globalNbCellsX(level_to_adapt + 1); ++i) {
1146 // str += "\n";
1147 // for (CartCoord j = 0; j < numbering->globalNbCellsY(level_to_adapt + 1); ++j) {
1148 // CartCoord c = av_out(i, j);
1149 // if (c >= 0) {
1150 // str += "[";
1151 // if (c < 10)
1152 // str += " ";
1153 // str += c;
1154 // str += "]";
1155 // }
1156 // else if (c == -2) {
1157 // str += "[OI]";
1158 // }
1159 // else if (c == -3) {
1160 // str += "[OO]";
1161 // }
1162 // else if (c == -4) {
1163 // str += "[II]";
1164 // }
1165 // else if (c == -5) {
1166 // str += "[XX]";
1167 // }
1168 // else
1169 // str += "[ ]";
1170 // }
1171 // }
1172 // info() << str;
1173 }
1174
1175 // On ajoute les patchs au maillage (on crée les groupes) et on calcule les
1176 // directions pour chacun d'eux (pour que l'utilisateur puisse les utiliser
1177 // directement).
1178 for (const AMRPatchPosition& patch : all_patches) {
1179 Integer index = _addPatch(patch);
1180 // TODO : Mais alors pas une bonne idée du tout !
1181 m_cmesh->computeDirectionsPatchV2(index);
1182 }
1183
1184 debug() << "adaptLevel() -- End call -- Actual patch list:";
1185
1186 for (Integer i = 0; i <= m_target_nb_levels; ++i) {
1187 for (auto p : m_amr_patches_pointer) {
1188 auto& position = p->_internalApi()->positionRef();
1189 if (position.level() == i) {
1190 debug() << "\tPatch #" << p->index()
1191 << " -- Level : " << position.level()
1192 << " -- Min point : " << position.minPoint()
1193 << " -- Max point : " << position.maxPoint()
1194 << " -- Overlap layer size : " << position.overlapLayerSize();
1195 }
1196 }
1197 }
1198}
1199
1200/*---------------------------------------------------------------------------*/
1201/*---------------------------------------------------------------------------*/
1202
1203void CartesianPatchGroup::
1204_increaseOverlapSizeLevel(Int32 level_to_increate, Int32 new_size)
1205{
1206 if (level_to_increate == 0) {
1207 ARCANE_FATAL("Level 0 has not overlap layer");
1208 }
1209
1210 auto amr = m_cmesh->_internalApi()->cartesianMeshAMRPatchMng();
1211 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
1212
1213 bool has_cell_to_refine = false;
1214
1215 // Trois grandes étapes :
1216 // - d'abord, on agrandit le nombre de couches dans les structures position,
1217 // puis on ajoute le flag II_Refine aux mailles parentes qui n'ont pas
1218 // d'enfant,
1219 // - on raffine les mailles,
1220 // - on ajoute les flags aux nouvelles mailles et on les ajoute aux groupes
1221 // de mailles des patchs.
1222 for (Integer p = 1; p < m_amr_patches_pointer.size(); ++p) {
1223 Int32 level = m_amr_patches_pointer[p]->_internalApi()->positionRef().level();
1224 if (level == level_to_increate) {
1225 AMRPatchPosition& position = m_amr_patches_pointer[p]->_internalApi()->positionRef();
1226
1227 Int32 size_layer = position.overlapLayerSize();
1228 if (size_layer > new_size) {
1229 ARCANE_FATAL("Cannot reduce layer with _increaseOverlapSizeLevel method");
1230 }
1231
1232 // On pourrait vérifier que le nombre de couches de tous les patchs d'un
1233 // niveau est identique.
1234
1235 if (size_layer == new_size) {
1236 continue;
1237 }
1238
1239 has_cell_to_refine = true;
1240 position.setOverlapLayerSize(new_size);
1241
1242 // Les mailles à raffiner sont sur le niveau inférieur.
1243 // Pour chaque maille, pour savoir si l'on doit la raffiner ou non, on
1244 // la monte d'un niveau et on regarde si elle est dans les couches de
1245 // recouvrement.
1246 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level_to_increate - 1)) {
1247 const CartCoord3 pos = numbering->offsetLevelToLevel(numbering->cellUniqueIdToCoord(*icell), level_to_increate - 1, level_to_increate);
1248 if (position.isInWithOverlap(pos) && !icell->hasHChildren()) {
1249 icell->mutableItemBase().addFlags(ItemFlags::II_Refine);
1250 }
1251 }
1252 }
1253 }
1254 has_cell_to_refine = m_cmesh->mesh()->parallelMng()->reduce(MessagePassing::ReduceMax, has_cell_to_refine);
1255 if (!has_cell_to_refine) {
1256 return;
1257 }
1258
1259 // On raffine les mailles.
1260 amr->refine();
1261
1262 // TODO : Normalement, il n'y a pas besoin de faire ça, à corriger dans amr->refine().
1263 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level_to_increate - 1)) {
1264 icell->mutableItemBase().removeFlags(ItemFlags::II_Refine);
1265 }
1266
1267 UniqueArray<Int32> cell_to_add;
1268
1269 // Ajoute les flags et on actualise les groupes de mailles des patchs.
1270 for (Integer p = 1; p < m_amr_patches_pointer.size(); ++p) {
1271 Int32 level = m_amr_patches_pointer[p]->_internalApi()->positionRef().level();
1272 if (level == level_to_increate) {
1273 AMRPatchPosition& position = m_amr_patches_pointer[p]->_internalApi()->positionRef();
1274
1275 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level_to_increate)) {
1276 if (!icell->hasFlags(ItemFlags::II_JustAdded))
1277 continue;
1278
1279 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
1280
1281 if (position.isInWithOverlap(pos)) {
1282 cell_to_add.add(icell.localId());
1283 icell->mutableItemBase().addFlags(ItemFlags::II_Overlap);
1284 for (Face face : icell->faces()) {
1285 face.mutableItemBase().addFlags(ItemFlags::II_Overlap);
1286 }
1287 for (Node node : icell->nodes()) {
1288 node.mutableItemBase().addFlags(ItemFlags::II_Overlap);
1289 }
1290 }
1291 else if (position.isIn(pos)) {
1292 icell->mutableItemBase().addFlags(ItemFlags::II_InPatch);
1293 for (Face face : icell->faces()) {
1294 face.mutableItemBase().addFlags(ItemFlags::II_InPatch);
1295 }
1296 for (Node node : icell->nodes()) {
1297 node.mutableItemBase().addFlags(ItemFlags::II_InPatch);
1298 }
1299 }
1300 }
1301
1302 allCells(p).addItems(cell_to_add, true); //TODO Normalement, mettre check = false
1303 overlapCells(p).addItems(cell_to_add, true);
1304 cell_to_add.clear();
1305
1306 // On calcule les directions pour que le patch soit utilisable.
1307 m_cmesh->computeDirectionsPatchV2(p);
1308 }
1309 }
1310
1311 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level_to_increate)) {
1312 icell->mutableItemBase().removeFlags(ItemFlags::II_JustAdded);
1313 }
1314}
1315
1316/*---------------------------------------------------------------------------*/
1317/*---------------------------------------------------------------------------*/
1318
1319void CartesianPatchGroup::
1320_reduceOverlapSizeLevel(Int32 level_to_reduce, Int32 new_size)
1321{
1322 // Attention : Le reduce est possible car on ne supprime pas de mailles, on
1323 // leur enlève leurs flags InPatch/Overlap pour pouvoir les supprimer
1324 // ensuite.
1325 // On les enlève uniquement des groupes de mailles des patchs.
1326 // Il est donc nécessaire d'avoir une autre méthode après celle-ci pour
1327 // supprimer les mailles sans flags.
1328
1329 if (level_to_reduce == 0) {
1330 ARCANE_FATAL("Level 0 has not overlap layer");
1331 }
1332
1333 auto amr = m_cmesh->_internalApi()->cartesianMeshAMRPatchMng();
1334 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
1335
1336 // Deux étapes :
1337 // - d'abord, on actualise les structures position des patchs puis on
1338 // supprime des groupes de mailles des patchs les mailles qui ne sont plus
1339 // dans les couches de recouvrement,
1340 // - enfin, on recalcule les flags de tout le niveau.
1341 bool has_cell_to_mark = false;
1342 UniqueArray<Int32> cell_to_remove;
1343
1344 for (Integer p = 1; p < m_amr_patches_pointer.size(); ++p) {
1345 Int32 level = m_amr_patches_pointer[p]->_internalApi()->positionRef().level();
1346 if (level == level_to_reduce) {
1347 AMRPatchPosition& position = m_amr_patches_pointer[p]->_internalApi()->positionRef();
1348
1349 Int32 size_layer = position.overlapLayerSize();
1350 if (size_layer < new_size) {
1351 ARCANE_FATAL("Cannot add layer with _reduceOverlapSizeLevel method");
1352 }
1353 if (size_layer == new_size) {
1354 continue;
1355 }
1356
1357 has_cell_to_mark = true;
1358 position.setOverlapLayerSize(new_size);
1359
1360 ENUMERATE_ (Cell, icell, overlapCells(p)) {
1361 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
1362 if (!position.isInWithOverlap(pos)) {
1363 cell_to_remove.add(icell.localId());
1364 }
1365 }
1366
1367 allCells(p).removeItems(cell_to_remove, true); //TODO Normalement, mettre check = false
1368 overlapCells(p).removeItems(cell_to_remove, true);
1369 cell_to_remove.clear();
1370 }
1371 }
1372 has_cell_to_mark = m_cmesh->mesh()->parallelMng()->reduce(MessagePassing::ReduceMax, has_cell_to_mark);
1373 if (!has_cell_to_mark) {
1374 return;
1375 }
1376
1377 // À cause du mélange des deux flags, on doit recalculer les flags.
1378 _updatePatchFlagsOfItemsLevel(level_to_reduce, true);
1379
1380 for (Integer p = 1; p < m_amr_patches_pointer.size(); ++p) {
1381 Int32 level = m_amr_patches_pointer[p]->_internalApi()->positionRef().level();
1382 if (level == level_to_reduce) {
1383 m_cmesh->computeDirectionsPatchV2(p);
1384 }
1385 }
1386}
1387
1388/*---------------------------------------------------------------------------*/
1389/*---------------------------------------------------------------------------*/
1390
1391void CartesianPatchGroup::
1392_updateHigherLevel()
1393{
1394 // On regarde quel est le patch le plus haut.
1395 Int32 higher_level_patch = 0;
1396
1397 for (const auto patch : m_amr_patches_pointer) {
1398 const Int32 level = patch->_internalApi()->positionRef().level();
1399 if (level > higher_level_patch) {
1400 higher_level_patch = level;
1401 }
1402 }
1403
1404 if (higher_level_patch != m_higher_level) {
1405 for (Int32 level = 1; level <= higher_level_patch; ++level) {
1406 _changeOverlapSizeLevel(level, m_higher_level, higher_level_patch);
1407 }
1408
1409 m_higher_level = higher_level_patch;
1410 }
1411}
1412
1413/*---------------------------------------------------------------------------*/
1414/*---------------------------------------------------------------------------*/
1415
1416void CartesianPatchGroup::
1417_changeOverlapSizeLevel(Int32 level, Int32 previous_higher_level, Int32 new_higher_level)
1418{
1419 if (previous_higher_level == new_higher_level) {
1420 return;
1421 }
1422
1423 Int32 old_overlap_size = ((level > previous_higher_level) ? 0 : AMRPatchPosition::computeOverlapLayerSize(level, previous_higher_level, m_size_of_overlap_layer_top_level));
1424 Int32 new_overlap_size = AMRPatchPosition::computeOverlapLayerSize(level, new_higher_level, m_size_of_overlap_layer_top_level);
1425
1426 if (old_overlap_size == new_overlap_size) {
1427 return;
1428 }
1429 if (old_overlap_size < new_overlap_size) {
1430 _increaseOverlapSizeLevel(level, new_overlap_size);
1431 }
1432 else {
1433 _reduceOverlapSizeLevel(level, new_overlap_size);
1434 }
1435}
1436
1437/*---------------------------------------------------------------------------*/
1438/*---------------------------------------------------------------------------*/
1439
1440void CartesianPatchGroup::
1441_coarsenUselessCells(bool use_cells_level)
1442{
1443 Int32 higher_level_patch = m_higher_level;
1444 if (use_cells_level) {
1445 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allCells()) {
1446 if (icell->level() > higher_level_patch) {
1447 higher_level_patch = icell->level();
1448 }
1449 }
1450 higher_level_patch = m_cmesh->mesh()->parallelMng()->reduce(MessagePassing::ReduceMax, higher_level_patch);
1451 }
1452
1453 // On supprime les mailles qui ne sont pas/plus dans un patch.
1454 for (Integer level = higher_level_patch; level > 0; --level) {
1455 _coarsenUselessCellsInLevel(level);
1456 }
1457}
1458
1459/*---------------------------------------------------------------------------*/
1460/*---------------------------------------------------------------------------*/
1461
1462void CartesianPatchGroup::
1463_coarsenUselessCellsInLevel(Int32 level)
1464{
1465 Integer nb_cells_to_coarse = 0;
1466 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level)) {
1467 if (!icell->hasFlags(ItemFlags::II_InPatch) && !icell->hasFlags(ItemFlags::II_Overlap)) {
1468 //debug() << "Coarse CellUID : " << icell->uniqueId();
1469 icell->mutableItemBase().addFlags(ItemFlags::II_Coarsen);
1470 nb_cells_to_coarse++;
1471 }
1472 }
1473 debug() << "Remove " << nb_cells_to_coarse << " refined cells without flag in level " << level;
1474 nb_cells_to_coarse = m_cmesh->mesh()->parallelMng()->reduce(MessagePassing::ReduceMax, nb_cells_to_coarse);
1475
1476 auto amr = m_cmesh->_internalApi()->cartesianMeshAMRPatchMng();
1477 if (nb_cells_to_coarse != 0) {
1478 amr->coarsen(true);
1479 }
1480}
1481
1482/*---------------------------------------------------------------------------*/
1483/*---------------------------------------------------------------------------*/
1484
1485void CartesianPatchGroup::
1486_updatePatchFlagsOfItemsLevel(Int32 level, bool use_cell_groups)
1487{
1488 if (level == 0) {
1489 _updatePatchFlagsOfItemsGroundLevel();
1490 return;
1491 }
1492
1493 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
1494
1495 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level)) {
1496 icell->mutableItemBase().removeFlags(ItemFlags::II_InPatch | ItemFlags::II_Overlap);
1497 }
1498 ENUMERATE_ (Face, iface, m_cmesh->mesh()->allLevelCells(level).faceGroup()) {
1499 iface->mutableItemBase().removeFlags(ItemFlags::II_InPatch | ItemFlags::II_Overlap);
1500 }
1501 ENUMERATE_ (Node, inode, m_cmesh->mesh()->allLevelCells(level).nodeGroup()) {
1502 inode->mutableItemBase().removeFlags(ItemFlags::II_InPatch | ItemFlags::II_Overlap);
1503 }
1504
1505 // En utilisant les cell_groups des patchs, on n'a pas besoin de rechercher,
1506 // pour chaque maille, si elle est dans chaque patch.
1507 // Mais ça nécessite que les cell_groups soit disponibles.
1508 if (use_cell_groups) {
1509 for (Integer p = 1; p < m_amr_patches_pointer.size(); ++p) {
1510 Int32 level_patch = m_amr_patches_pointer[p]->_internalApi()->positionRef().level();
1511 if (level_patch == level) {
1512 ENUMERATE_ (Cell, icell, inPatchCells(p)) {
1513 icell->mutableItemBase().addFlags(ItemFlags::II_InPatch);
1514 }
1515 ENUMERATE_ (Face, iface, inPatchCells(p).faceGroup()) {
1516 iface->mutableItemBase().addFlags(ItemFlags::II_InPatch);
1517 }
1518 ENUMERATE_ (Node, inode, inPatchCells(p).nodeGroup()) {
1519 inode->mutableItemBase().addFlags(ItemFlags::II_InPatch);
1520 }
1521
1522 ENUMERATE_ (Cell, icell, overlapCells(p)) {
1523 icell->mutableItemBase().addFlags(ItemFlags::II_Overlap);
1524 }
1525 ENUMERATE_ (Face, iface, overlapCells(p).faceGroup()) {
1526 iface->mutableItemBase().addFlags(ItemFlags::II_Overlap);
1527 }
1528 ENUMERATE_ (Node, inode, overlapCells(p).nodeGroup()) {
1529 inode->mutableItemBase().addFlags(ItemFlags::II_Overlap);
1530 }
1531 }
1532 }
1533 }
1534
1535 // Sinon, méthode brute qui fonctionne toujours.
1536 else {
1537 // On ajoute les flags sur les mailles des patchs.
1538 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level)) {
1539 bool in_overlap = false;
1540 bool in_patch = false;
1541
1542 // Si une maille est dans un patch, elle prend le flag II_InPatch.
1543 // Si une maille est une maille de recouvrement pour un patch, elle prend
1544 // le flag II_Overlap.
1545 // Comme son nom l'indique, une maille de recouvrement peut recouvrir un
1546 // autre patch. Donc une maille peut être à la fois II_InPatch et
1547 // II_Overlap.
1548 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
1549
1550 for (Integer p = 1; p < m_amr_patches_pointer.size(); ++p) {
1551 auto& patch = m_amr_patches_pointer[p]->_internalApi()->positionRef();
1552 if (patch.level() != level) {
1553 continue;
1554 }
1555
1556 if (patch.isIn(pos)) {
1557 in_patch = true;
1558 }
1559 else if (patch.isInWithOverlap(pos)) {
1560 in_overlap = true;
1561 }
1562 if (in_patch && in_overlap) {
1563 break;
1564 }
1565 }
1566 if (in_patch && in_overlap) {
1567 icell->mutableItemBase().addFlags(ItemFlags::II_InPatch | ItemFlags::II_Overlap);
1568 for (Face face : icell->faces()) {
1569 face.mutableItemBase().addFlags(ItemFlags::II_InPatch | ItemFlags::II_Overlap);
1570 }
1571 for (Node node : icell->nodes()) {
1572 node.mutableItemBase().addFlags(ItemFlags::II_InPatch | ItemFlags::II_Overlap);
1573 }
1574 }
1575 else if (in_overlap) {
1576 icell->mutableItemBase().addFlags(ItemFlags::II_Overlap);
1577 icell->mutableItemBase().removeFlags(ItemFlags::II_InPatch); //Au cas où.
1578 for (Face face : icell->faces()) {
1579 face.mutableItemBase().addFlags(ItemFlags::II_Overlap);
1580 }
1581 for (Node node : icell->nodes()) {
1582 node.mutableItemBase().addFlags(ItemFlags::II_Overlap);
1583 }
1584 }
1585 else if (in_patch) {
1586 icell->mutableItemBase().addFlags(ItemFlags::II_InPatch);
1587 icell->mutableItemBase().removeFlags(ItemFlags::II_Overlap); //Au cas où.
1588 for (Face face : icell->faces()) {
1589 face.mutableItemBase().addFlags(ItemFlags::II_InPatch);
1590 }
1591 for (Node node : icell->nodes()) {
1592 node.mutableItemBase().addFlags(ItemFlags::II_InPatch);
1593 }
1594 }
1595 else {
1596 icell->mutableItemBase().removeFlags(ItemFlags::II_InPatch | ItemFlags::II_Overlap); //Au cas où.
1597 }
1598 }
1599 }
1600}
1601
1602/*---------------------------------------------------------------------------*/
1603/*---------------------------------------------------------------------------*/
1604
1605void CartesianPatchGroup::
1606_updatePatchFlagsOfItemsGroundLevel()
1607{
1608 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(0)) {
1609 icell->mutableItemBase().addFlags(ItemFlags::II_InPatch);
1610 }
1611 ENUMERATE_ (Face, iface, m_cmesh->mesh()->allLevelCells(0).faceGroup()) {
1612 iface->mutableItemBase().addFlags(ItemFlags::II_InPatch);
1613 }
1614 ENUMERATE_ (Node, inode, m_cmesh->mesh()->allLevelCells(0).nodeGroup()) {
1615 inode->mutableItemBase().addFlags(ItemFlags::II_InPatch);
1616 }
1617}
1618
1619/*---------------------------------------------------------------------------*/
1620/*---------------------------------------------------------------------------*/
1621
1622void CartesianPatchGroup::
1623_removePatchFlagsOfItemsLevel(Int32 level)
1624{
1625 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level)) {
1626 icell->mutableItemBase().removeFlags(ItemFlags::II_Overlap | ItemFlags::II_InPatch);
1627 }
1628 ENUMERATE_ (Face, iface, m_cmesh->mesh()->allLevelCells(level).faceGroup()) {
1629 iface->mutableItemBase().removeFlags(ItemFlags::II_Overlap | ItemFlags::II_InPatch);
1630 }
1631 ENUMERATE_ (Node, inode, m_cmesh->mesh()->allLevelCells(level).nodeGroup()) {
1632 inode->mutableItemBase().removeFlags(ItemFlags::II_Overlap | ItemFlags::II_InPatch);
1633 }
1634}
1635
1636/*---------------------------------------------------------------------------*/
1637/*---------------------------------------------------------------------------*/
1638
1639void CartesianPatchGroup::
1640_checkPatchesAndMesh()
1641{
1642 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
1643 {
1644 Int32 higher_level = 0;
1645 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allCells()) {
1646 if (icell->level() > higher_level) {
1647 higher_level = icell->level();
1648 }
1649 }
1650 higher_level = m_cmesh->mesh()->parallelMng()->reduce(MessagePassing::ReduceMax, higher_level);
1651 if (higher_level != m_higher_level) {
1652 ARCANE_FATAL("_checkPatchesAndMesh -- Bad higher level -- m_higher_level : {0} -- Found : {1}", m_higher_level, higher_level);
1653 }
1654 }
1655 {
1656 for (Int32 level = 0; level < m_higher_level; ++level) {
1657 Int32 check_overlap = overlapLayerSize(level);
1658 for (Integer p = 0; p < m_amr_patches_pointer.size(); ++p) {
1659 auto& position = m_amr_patches_pointer[p]->_internalApi()->positionRef();
1660 if (position.level() == level) {
1661 if (check_overlap == -1) {
1662 check_overlap = position.overlapLayerSize();
1663 }
1664 else if (check_overlap != position.overlapLayerSize()) {
1665 ARCANE_FATAL("_checkPatchesAndMesh -- Overlap size incoherence -- Patch pos : {0} -- Previous size : {1} -- Found : {2}", p, check_overlap, position.overlapLayerSize());
1666 }
1667 }
1668 }
1669 }
1670 }
1671 {
1672 // II_UserMark1 = II_Overlap
1673 // II_UserMark2 = II_InPatch
1674 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allCells()) {
1675 Integer level = icell->level();
1676
1677 bool in_overlap = false;
1678 bool in_patch = false;
1679
1680 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
1681
1682 for (auto p : m_amr_patches_pointer) {
1683 auto& patch = p->_internalApi()->positionRef();
1684 if (patch.level() != level) {
1685 continue;
1686 }
1687
1688 if (patch.isIn(pos)) {
1689 in_patch = true;
1690 }
1691 else if (patch.isInWithOverlap(pos)) {
1692 in_overlap = true;
1693 }
1694 if (in_patch && in_overlap) {
1695 break;
1696 }
1697 }
1698 if (in_patch && in_overlap) {
1699 icell->mutableItemBase().addFlags(ItemFlags::II_UserMark1); // II_Overlap
1700 icell->mutableItemBase().addFlags(ItemFlags::II_UserMark2); // II_InPatch
1701 }
1702 else if (in_overlap) {
1703 icell->mutableItemBase().addFlags(ItemFlags::II_UserMark1); // II_Overlap
1704 icell->mutableItemBase().removeFlags(ItemFlags::II_UserMark2); // II_InPatch
1705 }
1706 else if (in_patch) {
1707 icell->mutableItemBase().addFlags(ItemFlags::II_UserMark2); // II_InPatch
1708 icell->mutableItemBase().removeFlags(ItemFlags::II_UserMark1); // II_Overlap
1709 }
1710 else {
1711 icell->mutableItemBase().removeFlags(ItemFlags::II_UserMark2); // II_InPatch
1712 icell->mutableItemBase().removeFlags(ItemFlags::II_UserMark1); // II_Overlap
1713 }
1714 }
1715 ENUMERATE_ (Face, iface, m_cmesh->mesh()->allFaces()) {
1716 Int32 max_level = 0;
1717 for (Cell cell : iface->cells()) {
1718 if (cell.level() > max_level) {
1719 max_level = cell.level();
1720 }
1721 }
1722 for (Cell cell : iface->cells()) {
1723 if (cell.level() != max_level) {
1724 continue;
1725 }
1726 if (cell.hasFlags(ItemFlags::II_UserMark1)) {
1727 iface->mutableItemBase().addFlags(ItemFlags::II_UserMark1); // II_Overlap
1728 }
1729 if (cell.hasFlags(ItemFlags::II_UserMark2)) {
1730 iface->mutableItemBase().addFlags(ItemFlags::II_UserMark2); // II_InPatch
1731 }
1732 }
1733 }
1734 ENUMERATE_ (Node, inode, m_cmesh->mesh()->allNodes()) {
1735 Int32 max_level = 0;
1736 for (Cell cell : inode->cells()) {
1737 if (cell.level() > max_level) {
1738 max_level = cell.level();
1739 }
1740 }
1741 for (Cell cell : inode->cells()) {
1742 if (cell.level() != max_level) {
1743 continue;
1744 }
1745 if (cell.hasFlags(ItemFlags::II_UserMark1)) {
1746 inode->mutableItemBase().addFlags(ItemFlags::II_UserMark1); // II_Overlap
1747 }
1748 if (cell.hasFlags(ItemFlags::II_UserMark2)) {
1749 inode->mutableItemBase().addFlags(ItemFlags::II_UserMark2); // II_InPatch
1750 }
1751 }
1752 }
1753
1754 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allCells()) {
1755 if (icell->hasFlags(ItemFlags::II_UserMark1)) {
1756 if (!icell->hasFlags(ItemFlags::II_Overlap)) {
1757 ARCANE_FATAL("_checkPatchesAndMesh -- II_UserMark1 but not II_Overlap -- CellUID : {0}", icell->uniqueId());
1758 }
1759 }
1760 if (icell->hasFlags(ItemFlags::II_UserMark2)) {
1761 if (!icell->hasFlags(ItemFlags::II_InPatch)) {
1762 ARCANE_FATAL("_checkPatchesAndMesh -- II_UserMark2 but not II_InPatch -- CellUID : {0}", icell->uniqueId());
1763 }
1764 }
1765 if (icell->hasFlags(ItemFlags::II_Overlap)) {
1766 if (!icell->hasFlags(ItemFlags::II_UserMark1)) {
1767 ARCANE_FATAL("_checkPatchesAndMesh -- II_Overlap but not II_UserMark1 -- CellUID : {0}", icell->uniqueId());
1768 }
1769 }
1770 if (icell->hasFlags(ItemFlags::II_InPatch)) {
1771 if (!icell->hasFlags(ItemFlags::II_UserMark2)) {
1772 ARCANE_FATAL("_checkPatchesAndMesh -- II_InPatch but not II_UserMark2 -- CellUID : {0}", icell->uniqueId());
1773 }
1774 }
1775
1776 // Aujourd'hui, on peut avoir des mailles raffinées mais dans aucun patch.
1777
1778 icell->mutableItemBase().removeFlags(ItemFlags::II_UserMark1); // II_Overlap
1779 icell->mutableItemBase().removeFlags(ItemFlags::II_UserMark2); // II_InPatch
1780 }
1781 ENUMERATE_ (Face, iface, m_cmesh->mesh()->allFaces()) {
1782 if (iface->hasFlags(ItemFlags::II_UserMark1)) {
1783 if (!iface->hasFlags(ItemFlags::II_Overlap)) {
1784 ARCANE_FATAL("_checkPatchesAndMesh -- II_UserMark1 but not II_Overlap -- FaceUID : {0}", iface->uniqueId());
1785 }
1786 }
1787 if (iface->hasFlags(ItemFlags::II_UserMark2)) {
1788 if (!iface->hasFlags(ItemFlags::II_InPatch)) {
1789 ARCANE_FATAL("_checkPatchesAndMesh -- II_UserMark2 but not II_InPatch -- FaceUID : {0}", iface->uniqueId());
1790 }
1791 }
1792 if (iface->hasFlags(ItemFlags::II_Overlap)) {
1793 if (!iface->hasFlags(ItemFlags::II_UserMark1)) {
1794 ARCANE_FATAL("_checkPatchesAndMesh -- II_Overlap but not II_UserMark1 -- FaceUID : {0}", iface->uniqueId());
1795 }
1796 }
1797 if (iface->hasFlags(ItemFlags::II_InPatch)) {
1798 if (!iface->hasFlags(ItemFlags::II_UserMark2)) {
1799 ARCANE_FATAL("_checkPatchesAndMesh -- II_InPatch but not II_UserMark2 -- FaceUID : {0}", iface->uniqueId());
1800 }
1801 }
1802
1803 iface->mutableItemBase().removeFlags(ItemFlags::II_UserMark1); // II_Overlap
1804 iface->mutableItemBase().removeFlags(ItemFlags::II_UserMark2); // II_InPatch
1805 }
1806 ENUMERATE_ (Node, inode, m_cmesh->mesh()->allNodes()) {
1807 if (inode->hasFlags(ItemFlags::II_UserMark1)) {
1808 if (!inode->hasFlags(ItemFlags::II_Overlap)) {
1809 ARCANE_FATAL("_checkPatchesAndMesh -- II_UserMark1 but not II_Overlap -- NodeUID : {0}", inode->uniqueId());
1810 }
1811 }
1812 if (inode->hasFlags(ItemFlags::II_UserMark2)) {
1813 if (!inode->hasFlags(ItemFlags::II_InPatch)) {
1814 ARCANE_FATAL("_checkPatchesAndMesh -- II_UserMark2 but not II_InPatch -- NodeUID : {0}", inode->uniqueId());
1815 }
1816 }
1817 if (inode->hasFlags(ItemFlags::II_Overlap)) {
1818 if (!inode->hasFlags(ItemFlags::II_UserMark1)) {
1819 ARCANE_FATAL("_checkPatchesAndMesh -- II_Overlap but not II_UserMark1 -- NodeUID : {0}", inode->uniqueId());
1820 }
1821 }
1822 if (inode->hasFlags(ItemFlags::II_InPatch)) {
1823 if (!inode->hasFlags(ItemFlags::II_UserMark2)) {
1824 ARCANE_FATAL("_checkPatchesAndMesh -- II_InPatch but not II_UserMark2 -- NodeUID : {0}", inode->uniqueId());
1825 }
1826 }
1827
1828 inode->mutableItemBase().removeFlags(ItemFlags::II_UserMark1); // II_Overlap
1829 inode->mutableItemBase().removeFlags(ItemFlags::II_UserMark2); // II_InPatch
1830 }
1831 }
1832}
1833
1834/*---------------------------------------------------------------------------*/
1835/*---------------------------------------------------------------------------*/
1836
1837void CartesianPatchGroup::
1838clearRefineRelatedFlags() const
1839{
1840 constexpr ItemFlags::FlagType flags_to_remove = (ItemFlags::II_Coarsen | ItemFlags::II_Refine |
1841 ItemFlags::II_JustCoarsened | ItemFlags::II_JustRefined |
1842 ItemFlags::II_JustAdded | ItemFlags::II_CoarsenInactive);
1843 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allCells()) {
1844 icell->mutableItemBase().removeFlags(flags_to_remove);
1845 }
1846}
1847
1848/*---------------------------------------------------------------------------*/
1849/*---------------------------------------------------------------------------*/
1850
1851void CartesianPatchGroup::
1852rebuildAvailableGroupIndex(ConstArrayView<Integer> available_group_index)
1853{
1854 m_available_group_index = available_group_index;
1855}
1856
1857/*---------------------------------------------------------------------------*/
1858/*---------------------------------------------------------------------------*/
1859
1860ConstArrayView<Int32> CartesianPatchGroup::
1861availableGroupIndex()
1862{
1863 return m_available_group_index;
1864}
1865
1866/*---------------------------------------------------------------------------*/
1867/*---------------------------------------------------------------------------*/
1868
1869void CartesianPatchGroup::
1870setOverlapLayerSizeTopLevel(Int32 size_of_overlap_layer_top_level)
1871{
1872 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
1873
1874 Int32 new_size_of_overlap_layer_top_level = 0;
1875 // La valeur -1 est une valeur spéciale qui permet de désactiver les mailles
1876 // de recouvrement.
1877 if (size_of_overlap_layer_top_level == -1)
1878 new_size_of_overlap_layer_top_level = -1;
1879 else
1880 // On s'assure que la taille fournie par l'utilisateur est un multiple de
1881 // pattern (2 aujourd'hui).
1882 new_size_of_overlap_layer_top_level = size_of_overlap_layer_top_level + (size_of_overlap_layer_top_level % numbering->pattern());
1883
1884 if (new_size_of_overlap_layer_top_level == m_size_of_overlap_layer_top_level) {
1885 return;
1886 }
1887
1888 // S'il y a changement de la taille de la couche du niveau le plus haut, il
1889 // y aura un changement de taille sur les autres niveaux.
1890 for (Int32 level = 1; level <= m_higher_level; ++level) {
1891 Int32 old_overlap_size = AMRPatchPosition::computeOverlapLayerSize(level, m_higher_level, m_size_of_overlap_layer_top_level);
1892 Int32 new_overlap_size = AMRPatchPosition::computeOverlapLayerSize(level, m_higher_level, new_size_of_overlap_layer_top_level);
1893
1894 if (old_overlap_size == new_overlap_size) {
1895 continue;
1896 }
1897 if (old_overlap_size < new_overlap_size) {
1898 _increaseOverlapSizeLevel(level, new_overlap_size);
1899 }
1900 else {
1901 _reduceOverlapSizeLevel(level, new_overlap_size);
1902 }
1903 }
1904 m_size_of_overlap_layer_top_level = new_size_of_overlap_layer_top_level;
1905}
1906
1907/*---------------------------------------------------------------------------*/
1908/*---------------------------------------------------------------------------*/
1909
1910Int32 CartesianPatchGroup::
1911overlapLayerSize(Int32 level)
1912{
1913 if (level == 0) {
1914 return 0;
1915 }
1916 // Deux cas :
1917 // - on est dans une phase de raffinement (beginAdaptMesh()), on doit donc
1918 // considérer que le niveau le plus haut est m_target_nb_levels-1,
1919 // - sinon, on prend le niveau le plus haut actuel.
1920 Int32 higher_level = m_higher_level;
1921 if (m_target_nb_levels != 0) {
1922 higher_level = m_target_nb_levels - 1;
1923 }
1924 return AMRPatchPosition::computeOverlapLayerSize(level, higher_level, m_size_of_overlap_layer_top_level);
1925}
1926
1927/*---------------------------------------------------------------------------*/
1928/*---------------------------------------------------------------------------*/
1929
1930void CartesianPatchGroup::
1931_addPatchInstance(Ref<CartesianMeshPatch> v)
1932{
1933 m_amr_patches.add(v);
1934 m_amr_patches_pointer.add(v.get());
1935}
1936
1937/*---------------------------------------------------------------------------*/
1938/*---------------------------------------------------------------------------*/
1939
1940void CartesianPatchGroup::
1941_removeOnePatch(Integer index)
1942{
1943 m_available_group_index.add(m_amr_patches[index]->index());
1944 // info() << "_removeOnePatch() -- Save group_index : " << m_available_group_index.back();
1945
1946 m_amr_patch_cell_groups_all[index].clear();
1947 m_amr_patch_cell_groups_all.remove(index);
1948
1949 if (m_cmesh->mesh()->meshKind().meshAMRKind() == eMeshAMRKind::PatchCartesianMeshOnly) {
1950 m_amr_patch_cell_groups_inpatch[index].clear();
1951 m_amr_patch_cell_groups_inpatch.remove(index);
1952 m_amr_patch_cell_groups_overlap[index].clear();
1953 m_amr_patch_cell_groups_overlap.remove(index);
1954 }
1955
1956 m_amr_patches_pointer.remove(index);
1957 m_amr_patches.remove(index);
1958}
1959
1960/*---------------------------------------------------------------------------*/
1961/*---------------------------------------------------------------------------*/
1962
1963// Le tableau doit être trié.
1964void CartesianPatchGroup::
1965_removeMultiplePatches(ConstArrayView<Integer> indexes)
1966{
1967 Integer count = 0;
1968 for (const Integer index : indexes) {
1969 _removeOnePatch(index - count);
1970 count++;
1971 }
1972}
1973
1974/*---------------------------------------------------------------------------*/
1975/*---------------------------------------------------------------------------*/
1976
1977void CartesianPatchGroup::
1978_removeAllPatches()
1979{
1980 for (Integer i = 1; i < m_amr_patch_cell_groups_all.size(); ++i) {
1981 m_amr_patch_cell_groups_all[i].clear();
1982 }
1983 m_amr_patch_cell_groups_all.clear();
1984
1985 if (m_cmesh->mesh()->meshKind().meshAMRKind() == eMeshAMRKind::PatchCartesianMeshOnly) {
1986 for (Integer i = 0; i < m_amr_patch_cell_groups_inpatch.size(); ++i) {
1987 m_amr_patch_cell_groups_inpatch[i].clear();
1988 m_amr_patch_cell_groups_overlap[i].clear();
1989 }
1990 m_amr_patch_cell_groups_inpatch.clear();
1991 m_amr_patch_cell_groups_overlap.clear();
1992 }
1993
1994 m_amr_patches_pointer.clear();
1995 m_amr_patches.clear();
1996 m_available_group_index.clear();
1997 m_patches_to_delete.clear();
1998 m_index_new_patches = 1;
1999
2000 m_higher_level = 0;
2001}
2002
2003/*---------------------------------------------------------------------------*/
2004/*---------------------------------------------------------------------------*/
2005
2006void CartesianPatchGroup::
2007_createGroundPatch()
2008{
2009 if (!m_amr_patches.empty())
2010 return;
2011 auto patch = makeRef(new CartesianMeshPatch(m_cmesh, -1));
2012
2013 if (m_cmesh->mesh()->meshKind().meshAMRKind() == eMeshAMRKind::PatchCartesianMeshOnly) {
2014 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
2015 patch->_internalApi()->positionRef().setMinPoint({ 0, 0, 0 });
2016 patch->_internalApi()->positionRef().setMaxPoint({ numbering->globalNbCellsX(0), numbering->globalNbCellsY(0), numbering->globalNbCellsZ(0) });
2017 patch->_internalApi()->positionRef().setLevel(0);
2018 }
2019
2020 _addPatchInstance(patch);
2021 _addCellGroup(m_cmesh->mesh()->allLevelCells(0), patch.get(), true);
2022}
2023
2024/*---------------------------------------------------------------------------*/
2025/*---------------------------------------------------------------------------*/
2026
2027Integer CartesianPatchGroup::
2028_addCellGroup(CellGroup cell_group, CartesianMeshPatch* patch, bool add_flags)
2029{
2030 m_amr_patch_cell_groups_all.add(cell_group);
2031
2032 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
2033 // Patch non-régulier.
2034 // m_amr_patch_cell_groups_inpatch.add(cell_group);
2035 // m_amr_patch_cell_groups_overlap.add(CellGroup());
2036 return m_amr_patch_cell_groups_all.size() - 1;
2037 }
2038
2039 AMRPatchPosition patch_position = patch->position();
2040 Ref<ICartesianMeshNumberingMngInternal> numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
2041
2042 UniqueArray<Int32> inpatch_items_lid;
2043 UniqueArray<Int32> overlap_items_lid;
2044
2045 ENUMERATE_ (Cell, icell, cell_group) {
2046 Cell cell = *icell;
2047 const CartCoord3 pos = numbering->cellUniqueIdToCoord(cell);
2048
2049 if (patch_position.isIn(pos)) {
2050 inpatch_items_lid.add(cell.localId());
2051 }
2052 else {
2053 overlap_items_lid.add(cell.localId());
2054 }
2055 }
2056
2057 CellGroup own = m_cmesh->mesh()->cellFamily()->createGroup(cell_group.name().clone() + "_InPatch", inpatch_items_lid, true);
2058 m_amr_patch_cell_groups_inpatch.add(own);
2059
2060 CellGroup overlap = m_cmesh->mesh()->cellFamily()->createGroup(cell_group.name().clone() + "_Overlap", overlap_items_lid, true);
2061 m_amr_patch_cell_groups_overlap.add(overlap);
2062
2063 if (add_flags) {
2064 // Si une entité est dans un patch, elle prend le flag II_InPatch.
2065 // Si une entité est une entité de recouvrement pour un patch, elle prend
2066 // le flag II_Overlap.
2067 // Comme son nom l'indique, une entité de recouvrement peut recouvrir un
2068 // autre patch. Donc une entité peut être à la fois II_InPatch et
2069 // II_Overlap.
2070 ENUMERATE_ (Cell, icell, own) {
2071 icell->mutableItemBase().addFlags(ItemFlags::II_InPatch);
2072 }
2073 ENUMERATE_ (Face, iface, own.faceGroup()) {
2074 iface->mutableItemBase().addFlags(ItemFlags::II_InPatch);
2075 }
2076 ENUMERATE_ (Node, inode, own.nodeGroup()) {
2077 inode->mutableItemBase().addFlags(ItemFlags::II_InPatch);
2078 }
2079
2080 ENUMERATE_ (Cell, icell, overlap) {
2081 icell->mutableItemBase().addFlags(ItemFlags::II_Overlap);
2082 }
2083 ENUMERATE_ (Face, iface, overlap.faceGroup()) {
2084 iface->mutableItemBase().addFlags(ItemFlags::II_Overlap);
2085 }
2086 ENUMERATE_ (Node, inode, overlap.nodeGroup()) {
2087 inode->mutableItemBase().addFlags(ItemFlags::II_Overlap);
2088 }
2089 }
2090
2091 return m_amr_patch_cell_groups_all.size() - 1;
2092}
2093
2094/*---------------------------------------------------------------------------*/
2095/*---------------------------------------------------------------------------*/
2096
2097void CartesianPatchGroup::
2098_updateCellGroups(Integer index, bool update_flags)
2099{
2100 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
2101 ARCANE_FATAL("Method available only with AMR PatchCartesianMeshOnly");
2102 }
2103
2104 CellGroup patch_all_cells = allCells(index);
2105 CellGroup patch_inpatch = inPatchCells(index);
2106 CellGroup patch_overlap = overlapCells(index);
2107
2108 patch_all_cells.clear();
2109 patch_inpatch.clear();
2110 patch_overlap.clear();
2111
2112 const auto& position = patch(index)->_internalApi()->positionRef();
2113
2114 Int32 level = position.level();
2115
2116 UniqueArray<Int32> inpatch_items_lid;
2117 UniqueArray<Int32> overlap_items_lid;
2118
2119 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
2120
2121 // On ajoute les flags sur les mailles des patchs.
2122 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level)) {
2123 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
2124
2125 if (position.isIn(pos)) {
2126 inpatch_items_lid.add(icell.localId());
2127 }
2128 else if (position.isInWithOverlap(pos)) {
2129 overlap_items_lid.add(icell.localId());
2130 }
2131 }
2132
2133 patch_all_cells.addItems(inpatch_items_lid, false);
2134 patch_all_cells.addItems(overlap_items_lid, false);
2135
2136 patch_inpatch.addItems(inpatch_items_lid, false);
2137 patch_overlap.addItems(overlap_items_lid, false);
2138
2139 if (update_flags) {
2140 ENUMERATE_ (Cell, icell, patch_inpatch) {
2141 icell->mutableItemBase().addFlags(ItemFlags::II_InPatch);
2142 }
2143 ENUMERATE_ (Face, iface, patch_inpatch.faceGroup()) {
2144 iface->mutableItemBase().addFlags(ItemFlags::II_InPatch);
2145 }
2146 ENUMERATE_ (Node, inode, patch_inpatch.nodeGroup()) {
2147 inode->mutableItemBase().addFlags(ItemFlags::II_InPatch);
2148 }
2149
2150 ENUMERATE_ (Cell, icell, patch_overlap) {
2151 icell->mutableItemBase().addFlags(ItemFlags::II_Overlap);
2152 }
2153 ENUMERATE_ (Face, iface, patch_overlap.faceGroup()) {
2154 iface->mutableItemBase().addFlags(ItemFlags::II_Overlap);
2155 }
2156 ENUMERATE_ (Node, inode, patch_overlap.nodeGroup()) {
2157 inode->mutableItemBase().addFlags(ItemFlags::II_Overlap);
2158 }
2159 }
2160}
2161
2162/*---------------------------------------------------------------------------*/
2163/*---------------------------------------------------------------------------*/
2164
2165/*---------------------------------------------------------------------------*/
2166/*---------------------------------------------------------------------------*/
2167
2168// Il est nécessaire que le patch source et le patch part_to_remove soient
2169// en contact pour que cette méthode fonctionne.
2170void CartesianPatchGroup::
2171_removePartOfPatch(Integer index_patch_to_edit, const AMRPatchPosition& part_to_remove)
2172{
2173 // info() << "Coarse Zone"
2174 // << " -- Min point : " << part_to_remove.minPoint()
2175 // << " -- Max point : " << part_to_remove.maxPoint()
2176 // << " -- Level : " << part_to_remove.level();
2177
2178 // p1 est le bout de patch qu'il faut retirer de p0.
2179 // On a donc uniquement quatre cas à traiter (sachant que p0 et p1 sont
2180 // forcément en contact en x et/ou y et/ou z).
2181 //
2182 // Cas 1 :
2183 // p0 |-----|
2184 // p1 |---------|
2185 // r = {-1, -1}
2186 //
2187 // Cas 2 :
2188 // p0 |-----|
2189 // p1 |-----|
2190 // r = {p1_min, -1}
2191 //
2192 // Cas 3 :
2193 // p0 |-----|
2194 // p1 |-----|
2195 // r = {-1, p1_max}
2196 //
2197 // Cas 4 :
2198 // p0 |-----|
2199 // p1 |---|
2200 // r = {p1_min, p1_max}
2201 auto cut_points_p0 = [](CartCoord p0_min, CartCoord p0_max, CartCoord p1_min, CartCoord p1_max) -> std::pair<CartCoord, CartCoord> {
2202 std::pair to_return{ -1, -1 };
2203 if (p1_min > p0_min && p1_min < p0_max) {
2204 to_return.first = p1_min;
2205 }
2206 if (p1_max > p0_min && p1_max < p0_max) {
2207 to_return.second = p1_max;
2208 }
2209 return to_return;
2210 };
2211
2212 ICartesianMeshPatch* patch = m_amr_patches_pointer[index_patch_to_edit];
2213 AMRPatchPosition patch_position = patch->position();
2214
2215 UniqueArray<AMRPatchPosition> new_patch_out;
2216
2217 CartCoord3 min_point_of_patch_to_exclude(-1, -1, -1);
2218
2219 // Partie découpe du patch autour de la zone à exclure.
2220 {
2221 UniqueArray<AMRPatchPosition> new_patch_in;
2222
2223 // On coupe le patch en x.
2224 {
2225 auto cut_point_x = cut_points_p0(patch_position.minPoint().x, patch_position.maxPoint().x, part_to_remove.minPoint().x, part_to_remove.maxPoint().x);
2226
2227 // p0 |-----|
2228 // p1 |---------|
2229 if (cut_point_x.first == -1 && cut_point_x.second == -1) {
2230 min_point_of_patch_to_exclude.x = patch_position.minPoint().x;
2231 new_patch_out.add(patch_position);
2232 }
2233 // p0 |-----|
2234 // p1 |-----|
2235 else if (cut_point_x.second == -1) {
2236 min_point_of_patch_to_exclude.x = cut_point_x.first;
2237 auto [fst, snd] = patch_position.cut(cut_point_x.first, MD_DirX);
2238 new_patch_out.add(fst);
2239 new_patch_out.add(snd);
2240 }
2241 // p0 |-----|
2242 // p1 |-----|
2243 else if (cut_point_x.first == -1) {
2244 min_point_of_patch_to_exclude.x = patch_position.minPoint().x;
2245 auto [fst, snd] = patch_position.cut(cut_point_x.second, MD_DirX);
2246 new_patch_out.add(fst);
2247 new_patch_out.add(snd);
2248 }
2249 // p0 |-----|
2250 // p1 |---|
2251 else {
2252 min_point_of_patch_to_exclude.x = cut_point_x.first;
2253 auto [fst, snd_thr] = patch_position.cut(cut_point_x.first, MD_DirX);
2254 new_patch_out.add(fst);
2255 auto [snd, thr] = snd_thr.cut(cut_point_x.second, MD_DirX);
2256 new_patch_out.add(snd);
2257 new_patch_out.add(thr);
2258 }
2259 }
2260
2261 // On coupe le patch en y.
2262 {
2263 std::swap(new_patch_out, new_patch_in);
2264
2265 auto cut_point_y = cut_points_p0(patch_position.minPoint().y, patch_position.maxPoint().y, part_to_remove.minPoint().y, part_to_remove.maxPoint().y);
2266
2267 // p0 |-----|
2268 // p1 |---------|
2269 if (cut_point_y.first == -1 && cut_point_y.second == -1) {
2270 for (const AMRPatchPosition& patch_x : new_patch_in) {
2271 min_point_of_patch_to_exclude.y = patch_x.minPoint().y;
2272 new_patch_out.add(patch_x);
2273 }
2274 }
2275 // p0 |-----|
2276 // p1 |-----|
2277 else if (cut_point_y.second == -1) {
2278 min_point_of_patch_to_exclude.y = cut_point_y.first;
2279 for (const AMRPatchPosition& patch_x : new_patch_in) {
2280 auto [fst, snd] = patch_x.cut(cut_point_y.first, MD_DirY);
2281 new_patch_out.add(fst);
2282 new_patch_out.add(snd);
2283 }
2284 }
2285 // p0 |-----|
2286 // p1 |-----|
2287 else if (cut_point_y.first == -1) {
2288 for (const AMRPatchPosition& patch_x : new_patch_in) {
2289 min_point_of_patch_to_exclude.y = patch_x.minPoint().y;
2290 auto [fst, snd] = patch_x.cut(cut_point_y.second, MD_DirY);
2291 new_patch_out.add(fst);
2292 new_patch_out.add(snd);
2293 }
2294 }
2295 // p0 |-----|
2296 // p1 |---|
2297 else {
2298 min_point_of_patch_to_exclude.y = cut_point_y.first;
2299 for (const AMRPatchPosition& patch_x : new_patch_in) {
2300 auto [fst, snd_thr] = patch_x.cut(cut_point_y.first, MD_DirY);
2301 new_patch_out.add(fst);
2302 auto [snd, thr] = snd_thr.cut(cut_point_y.second, MD_DirY);
2303 new_patch_out.add(snd);
2304 new_patch_out.add(thr);
2305 }
2306 }
2307 }
2308
2309 // On coupe le patch en z.
2310 if (m_cmesh->mesh()->dimension() == 3) {
2311 std::swap(new_patch_out, new_patch_in);
2312 new_patch_out.clear();
2313
2314 auto cut_point_z = cut_points_p0(patch_position.minPoint().z, patch_position.maxPoint().z, part_to_remove.minPoint().z, part_to_remove.maxPoint().z);
2315
2316 // p0 |-----|
2317 // p1 |---------|
2318 if (cut_point_z.first == -1 && cut_point_z.second == -1) {
2319 for (const AMRPatchPosition& patch_y : new_patch_in) {
2320 min_point_of_patch_to_exclude.z = patch_y.minPoint().z;
2321 new_patch_out.add(patch_y);
2322 }
2323 }
2324 // p0 |-----|
2325 // p1 |-----|
2326 else if (cut_point_z.second == -1) {
2327 for (const AMRPatchPosition& patch_y : new_patch_in) {
2328 min_point_of_patch_to_exclude.z = cut_point_z.first;
2329 auto [fst, snd] = patch_y.cut(cut_point_z.first, MD_DirZ);
2330 new_patch_out.add(fst);
2331 new_patch_out.add(snd);
2332 }
2333 }
2334 // p0 |-----|
2335 // p1 |-----|
2336 else if (cut_point_z.first == -1) {
2337 for (const AMRPatchPosition& patch_y : new_patch_in) {
2338 min_point_of_patch_to_exclude.z = patch_y.minPoint().z;
2339 auto [fst, snd] = patch_y.cut(cut_point_z.second, MD_DirZ);
2340 new_patch_out.add(fst);
2341 new_patch_out.add(snd);
2342 }
2343 }
2344 // p0 |-----|
2345 // p1 |---|
2346 else {
2347 for (const AMRPatchPosition& patch_y : new_patch_in) {
2348 min_point_of_patch_to_exclude.z = cut_point_z.first;
2349 auto [fst, snd_thr] = patch_y.cut(cut_point_z.first, MD_DirZ);
2350 new_patch_out.add(fst);
2351 auto [snd, thr] = snd_thr.cut(cut_point_z.second, MD_DirZ);
2352 new_patch_out.add(snd);
2353 new_patch_out.add(thr);
2354 }
2355 }
2356 }
2357 }
2358
2359 // Partie fusion et ajout.
2360 {
2361 if (m_cmesh->mesh()->dimension() == 2) {
2362 min_point_of_patch_to_exclude.z = 0;
2363 }
2364 // info() << "Nb of new patch before fusion : " << new_patch_out.size();
2365 // info() << "min_point_of_patch_to_exclude : " << min_point_of_patch_to_exclude;
2366
2367 // On met à null le patch représentant le bout de patch à retirer.
2368 for (AMRPatchPosition& new_patch : new_patch_out) {
2369 if (new_patch.minPoint() == min_point_of_patch_to_exclude) {
2370 new_patch.setLevel(-2); // Devient null.
2371 }
2372 // else {
2373 // info() << "\tPatch before fusion"
2374 // << " -- Min point : " << new_patch.minPoint()
2375 // << " -- Max point : " << new_patch.maxPoint()
2376 // << " -- Level : " << new_patch.level();
2377 // }
2378 }
2379
2380 AMRPatchPositionLevelGroup::fusionPatches(new_patch_out, false);
2381
2382 // On ajoute les nouveaux patchs dans la liste des patchs.
2383 // Integer d_nb_patch_final = 0;
2384 for (const auto& new_patch : new_patch_out) {
2385 if (!new_patch.isNull()) {
2386 // info() << "\tNew cut patch"
2387 // << " -- Min point : " << new_patch.minPoint()
2388 // << " -- Max point : " << new_patch.maxPoint()
2389 // << " -- Level : " << new_patch.level();
2390 _addCutPatch(new_patch, allCells(index_patch_to_edit));
2391 // d_nb_patch_final++;
2392 }
2393 }
2394 // info() << "Nb of new patch after fusion : " << d_nb_patch_final;
2395 }
2396
2397 removePatch(index_patch_to_edit);
2398}
2399
2400/*---------------------------------------------------------------------------*/
2401/*---------------------------------------------------------------------------*/
2402
2403void CartesianPatchGroup::
2404_addCutPatch(const AMRPatchPosition& new_patch_position, CellGroup parent_patch_cell_group)
2405{
2406 // Si cette méthode est utilisé par une autre méthode que _removePartOfPatch(),
2407 // voir si la mise à jour de m_higher_level est nécessaire.
2408 // (jusque-là, ce n'est pas utile vu qu'il y aura appel à applyPatchEdit()).
2409 if (parent_patch_cell_group.null())
2410 ARCANE_FATAL("Null cell group");
2411
2412 IItemFamily* cell_family = m_cmesh->mesh()->cellFamily();
2413 Integer group_index = _nextIndexForNewPatch();
2414 String patch_group_name = String("CartesianMeshPatchCells") + group_index;
2415
2416 auto* cdi = new CartesianMeshPatch(m_cmesh, group_index, new_patch_position);
2417 _addPatchInstance(makeRef(cdi));
2418
2419 UniqueArray<Int32> cells_local_id;
2420
2421 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
2422 ENUMERATE_ (Cell, icell, parent_patch_cell_group) {
2423 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
2424 if (new_patch_position.isIn(pos)) {
2425 cells_local_id.add(icell.localId());
2426 }
2427 }
2428
2429 CellGroup parent_cells = cell_family->createGroup(patch_group_name, cells_local_id, true);
2430 // False car les flags sont mis à jour après.
2431 _addCellGroup(parent_cells, cdi, false);
2432
2433 // info() << "_addCutPatch()"
2434 // << " -- m_amr_patch_cell_groups : " << m_amr_patch_cell_groups_all.size()
2435 // << " -- m_amr_patches : " << m_amr_patches.size()
2436 // << " -- group_index : " << group_index
2437 // << " -- cell_group name : " << m_amr_patch_cell_groups_all.back().name();
2438}
2439
2440/*---------------------------------------------------------------------------*/
2441/*---------------------------------------------------------------------------*/
2442
2443Integer CartesianPatchGroup::
2444_addPatch(const AMRPatchPosition& new_patch_position)
2445{
2446 UniqueArray<Int32> cells_local_id;
2447
2448 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
2449
2450 // On ajoute les flags sur les mailles des patchs.
2451 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(new_patch_position.level())) {
2452 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
2453
2454 if (new_patch_position.isInWithOverlap(pos)) {
2455 cells_local_id.add(icell.localId());
2456 }
2457 }
2458
2459 IItemFamily* cell_family = m_cmesh->mesh()->cellFamily();
2460 Integer group_index = _nextIndexForNewPatch();
2461 String patch_group_name = String("CartesianMeshPatchCells") + group_index;
2462
2463 auto* cdi = new CartesianMeshPatch(m_cmesh, group_index, new_patch_position);
2464
2465 _addPatchInstance(makeRef(cdi));
2466 CellGroup parent_cells = cell_family->createGroup(patch_group_name, cells_local_id, true);
2467 Integer array_index = _addCellGroup(parent_cells, cdi, true);
2468
2469 // TODO : Ces deux index, c'est vraiment pas une bonne idée...
2470 return array_index;
2471}
2472
2473/*---------------------------------------------------------------------------*/
2474/*---------------------------------------------------------------------------*/
2475
2476} // End namespace Arcane
2477
2478/*---------------------------------------------------------------------------*/
2479/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ENUMERATE_(type, name, group)
Enumérateur générique d'un groupe d'entité
Classe permettant de définir la position d'un patch dans le maillage cartésien.
AMRPatchPosition patchUp(Integer dim, Int32 higher_level, Int32 overlap_layer_size_top_level) const
Méthode permettant de créer un AMRPatchPosition pour le niveau supérieur.
bool isInWithOverlap(CartCoord x, CartCoord y, CartCoord z) const
Méthode permettant de savoir si une maille de position x,y,z est incluse dans ce patch avec couche de...
static Int32 computeOverlapLayerSize(Int32 level, Int32 higher_level, Int32 overlap_layer_size_top_level)
Méthode permettant de calculer le nombre de couches de mailles de recouvrement pour un niveau donné.
CartCoord3 minPoint() const
Méthode permettant de récupérer la position min de la boite englobante.
void setMinPoint(CartCoord3 min_point)
Méthode permettant de définir la position min de la boite englobante.
void setLevel(Int32 level)
Méthode permettant de définir le niveau du patch.
CartCoord3 maxPoint() const
Méthode permettant de récupérer la position max de la boite englobante.
bool haveIntersection(const AMRPatchPosition &other) const
Méthode permettant de savoir si notre patch est en contact avec le patch other.
Int32 overlapLayerSize() const
Méthode permettant de récupérer le nombre de couches de mailles de recouvrement du patch.
void setOverlapLayerSize(Int32 layer_size)
Méthode permettant de définir le nombre de couches de mailles de recouvrement du patch.
Int32 level() const
Méthode permettant de récupérer le niveau du patch.
void setMaxPoint(CartCoord3 max_point)
Méthode permettant de définir la position max de la boite englobante.
Classe permettant de définir une zone d'un maillage.
void cellsInPatch(IMesh *mesh, UniqueArray< Int32 > &cells_local_id) const
Méthode permettant de retrouver les mailles incluses dans la zone.
Real3 length() const
Méthode permettant de retrouver la taille de la zone.
Real3 position() const
Méthode permettant de retrouver la position de la zone.
AMRPatchPosition toAMRPatchPosition(ICartesianMesh *mesh) const
Méthode permettant de convertir ce AMRZonePosition en AMRPatchPosition.
Integer size() const
Nombre d'éléments du vecteur.
CellGroup allCells(Integer index)
Méthode permettant de récupérer le groupe de toutes les mailles du patch demandé.
void applyPatchEdit(bool remove_empty_patches, bool update_higher_level)
Méthode permettant de supprimer les patchs en attente de suppression.
Maille d'un maillage.
Definition Item.h:1214
Vue constante d'un tableau de type T.
Interface d'un patch AMR d'un maillage cartésien.
Interface d'un maillage cartésien.
Interface d'une famille d'entités.
Definition IItemFamily.h:84
virtual ItemGroup createGroup(const String &name, Int32ConstArrayView local_ids, bool do_override=false)=0
Créé un groupe d'entités de nom name contenant les entités local_ids.
virtual IMesh * mesh() const =0
Maillage associé
virtual IItemFamily * cellFamily()=0
Retourne la famille des mailles.
@ II_Refine
L'entité est marquée pour raffinement.
Definition ItemFlags.h:77
const String & name() const
Nom du groupe.
Definition ItemGroup.h:76
Integer size() const
Nombre d'éléments du groupe.
Definition ItemGroup.h:88
IMesh * mesh() const
Maillage auquel appartient ce groupe (0 pour le group nul)
Definition ItemGroup.h:126
Référence à une instance.
Chaîne de caractères unicode.
bool startsWith(const String &s) const
Indique si la chaîne commence par les caractères de s.
Definition String.cc:1100
const char * localstr() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:228
String substring(Int64 pos) const
Sous-chaîne commençant à la position pos.
Definition String.cc:1115
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flot pour un message de debug.
TraceMessage info() const
Flot pour un message d'information.
ITraceMng * traceMng() const
Gestionnaire de trace.
Positionne une classe de message.
Vecteur 1D de données avec sémantique par valeur (style STL).
__host__ __device__ Real2 min(Real2 a, Real2 b)
Retourne le minimum de deux Real2.
Definition MathUtils.h:336
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 -*-
Int32 CartCoord
Représente une coordonnée d'un élément dans la grille cartésienne (en X ou en Y ou en Z).
Int32 Integer
Type représentant un entier.
@ MD_DirZ
Direction Z.
@ MD_DirY
Direction Y.
@ MD_DirX
Direction X.
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Créé une référence sur un pointeur.
@ Cell
Le maillage est AMR par maille.
Definition MeshKind.h:52
@ PatchCartesianMeshOnly
Le maillage est AMR par patch cartésien (rectangulaire)
Definition MeshKind.h:56
std::int32_t Int32
Type entier signé sur 32 bits.
Int32x3 CartCoord3
Représente les coordonnées 3D d'un élément dans la grille cartésienne {x, y, z}.