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