Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
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/* Management of the Cartesian mesh patch group. */
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 // It is unnecessary to save the ground patch. It will be recalculated.
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: Find another way to handle this.
113 // In the case of a resumed protection, the m_available_index
114 // array cannot be correctly recalculated because of elements after
115 // the "max index" of the "active indices". These "extra" elements cannot be found without more information.
116 m_properties->set("PatchGroupNamesAvailable", m_available_group_index);
117 m_properties->set("PatchGroupNames", patch_group_names);
118 }
119}
120
121/*---------------------------------------------------------------------------*/
122/*---------------------------------------------------------------------------*/
123
124void CartesianPatchGroup::
125recreateFromDump()
126{
127 Trace::Setter mci(traceMng(), "CartesianPatchGroup");
128
129 // Save the version number to ensure it is OK upon restart
130 Int32 v = m_properties->getInt32("Version");
131 if (v != 1) {
132 ARCANE_FATAL("Bad serializer version: trying to read from incompatible checkpoint v={0} expected={1}", v, 1);
133 }
134
135 clear();
136 _createGroundPatch();
137
138 // Retrieve the patch group names
139 UniqueArray<String> patch_group_names;
140 m_properties->get("PatchGroupNames", patch_group_names);
141
142 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
143 info(4) << "Found n=" << patch_group_names.size() << " patchs";
144
145 IItemFamily* cell_family = m_cmesh->mesh()->cellFamily();
146 for (const String& x : patch_group_names) {
147 CellGroup group = cell_family->findGroup(x);
148 if (group.null())
149 ARCANE_FATAL("Can not find cell group '{0}'", x);
150 _addPatchAfterRestore(group);
151 }
152 }
153 else {
154 UniqueArray<Int32> level;
155 UniqueArray<Int32> overlap;
156 UniqueArray<Int32> index;
157 UniqueArray<CartCoord> min_point;
158 UniqueArray<CartCoord> max_point;
159
160 m_properties->get("LevelPatches", level);
161 m_properties->get("OverlapSizePatches", overlap);
162 m_properties->get("IndexPatches", index);
163 m_properties->get("MinPointPatches", min_point);
164 m_properties->get("MaxPointPatches", max_point);
165
166 IItemFamily* cell_family = m_cmesh->mesh()->cellFamily();
167
168 // Note: the ground patch was excluded from the save.
169 for (Integer pos_in_array = 0; pos_in_array < index.size(); ++pos_in_array) {
170 ConstArrayView min(min_point.subConstView(pos_in_array * 3, 3));
171 ConstArrayView max(max_point.subConstView(pos_in_array * 3, 3));
172
173 AMRPatchPosition position(
174 level[pos_in_array],
175 { min[MD_DirX], min[MD_DirY], min[MD_DirZ] },
176 { max[MD_DirX], max[MD_DirY], max[MD_DirZ] },
177 overlap[pos_in_array]);
178
179 const String& x = patch_group_names[pos_in_array];
180 CellGroup cell_group = cell_family->findGroup(x);
181 if (cell_group.null())
182 ARCANE_FATAL("Can not find cell group '{0}'", x);
183
184 auto* cdi = new CartesianMeshPatch(m_cmesh, index[pos_in_array], position);
185 _addPatchInstance(makeRef(cdi));
186 _addCellGroup(cell_group, cdi, true);
187 }
188
189 UniqueArray<Int32> available_index;
190 m_properties->get("PatchGroupNamesAvailable", available_index);
191 rebuildAvailableGroupIndex(available_index);
192 }
193}
194
195/*---------------------------------------------------------------------------*/
196/*---------------------------------------------------------------------------*/
197
198Ref<CartesianMeshPatch> CartesianPatchGroup::
199groundPatch()
200{
201 _createGroundPatch();
202 return patch(0);
203}
204
205/*---------------------------------------------------------------------------*/
206/*---------------------------------------------------------------------------*/
207
208void CartesianPatchGroup::
209addPatch(ConstArrayView<Int32> cells_local_id)
210{
211 if (m_cmesh->mesh()->meshKind().meshAMRKind() == eMeshAMRKind::PatchCartesianMeshOnly) {
212 ARCANE_FATAL("Do not use this method with AMR type 3");
213 }
214
215 Integer index = _nextIndexForNewPatch();
216 String children_group_name = String("CartesianMeshPatchCells") + index;
217 IItemFamily* cell_family = m_cmesh->mesh()->cellFamily();
218 CellGroup children_cells = cell_family->createGroup(children_group_name, cells_local_id, true);
219 _addPatch(children_cells, index);
220}
221
222/*---------------------------------------------------------------------------*/
223/*---------------------------------------------------------------------------*/
224
225// rebuildAvailableIndex() must be called after calls to this method.
226Integer CartesianPatchGroup::
227_addPatchAfterRestore(CellGroup cell_group)
228{
229 const String& name = cell_group.name();
230 Integer group_index = -1;
231 if (name.startsWith("CartesianMeshPatchCells")) {
232 String index_str = name.substring(23);
233 group_index = std::stoi(index_str.localstr());
234 }
235 else {
236 ARCANE_FATAL("Invalid group");
237 }
238
239 _addPatch(cell_group, group_index);
240 return group_index;
241}
242
243/*---------------------------------------------------------------------------*/
244/*---------------------------------------------------------------------------*/
245
246void CartesianPatchGroup::
247_addPatch(CellGroup cell_group, Integer group_index)
248{
249 _createGroundPatch();
250 if (group_index == -1) {
251 return;
252 }
253 if (cell_group.null())
254 ARCANE_FATAL("Null cell group");
255
256 AMRPatchPosition position;
257
258 auto* cdi = new CartesianMeshPatch(m_cmesh, group_index, position);
259 _addPatchInstance(makeRef(cdi));
260 _addCellGroup(cell_group, cdi, true);
261}
262
263/*---------------------------------------------------------------------------*/
264/*---------------------------------------------------------------------------*/
265
266void CartesianPatchGroup::
267addPatch(const AMRZonePosition& zone_position)
268{
269 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
270 ARCANE_FATAL("Method available only with AMR PatchCartesianMeshOnly");
271 }
272
273 Trace::Setter mci(traceMng(), "CartesianPatchGroup");
274
275 info() << "addPatch() with zone"
276 << " -- Position : " << zone_position.position()
277 << " -- Length : " << zone_position.length();
278
279 clearRefineRelatedFlags();
280
281 auto amr = m_cmesh->_internalApi()->cartesianMeshAMRPatchMng();
282 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
283
284 // The conversion gives us the intermediate patch (which surrounds the cells
285 // to be refined, not the refined cells). A call to the AMRPatchPosition::patchUp() method
286 // allows the patch to be promoted one level so that it groups the refined cells, thus becoming a "classic" patch.
287 AMRPatchPosition position = zone_position.toAMRPatchPosition(m_cmesh);
288
289 Int32 level = position.level();
290 Int32 level_up = level + 1;
291 Int32 nb_overlap_cells = 0;
292
293 Int32 higher_level = m_higher_level;
294
295 // The patchUp() method will need the future higher_level to correctly calculate
296 // the number of overlap layers.
297 // If we have a patch that will be higher than all others.
298 if (level_up >= higher_level) {
299 higher_level = level_up;
300 // The number of layers for the highest level must be
301 // m_size_of_overlap_layer_top_level. We are on an intermediate patch,
302 // so we divide this number by the number of child cells that will be created.
303 nb_overlap_cells = m_size_of_overlap_layer_top_level / numbering->pattern();
304 debug() << "Higher level -- Old : " << m_higher_level << " -- New : " << higher_level;
305 }
306
307 else {
308 // The number of overlap layers.
309 // +1 because the created patch will be at level level + 1.
310 // /pattern because the cells to be refined are at level level.
311 //
312 // Explanation:
313 // level=0,
314 // the future patch will be at level 1, so the number of overlap layers must be that corresponding to level 1
315 // (i.e., level+1),
316 // but the cells to be refined are at level 0, so we must divide the number of layers by the number of child cells that will be created
317 // (for one dimension) (i.e., numbering->pattern()).
318 nb_overlap_cells = overlapLayerSize(level + 1) / numbering->pattern();
319 }
320 position.setOverlapLayerSize(nb_overlap_cells);
321
322 debug() << "Zone to intermediary patch"
323 << " -- minPoint : " << position.minPoint()
324 << " -- maxPoint : " << position.maxPoint()
325 << " -- overlapLayerSize : " << position.overlapLayerSize()
326 << " -- level : " << level;
327
328 // Reminder: only cells with the "II_InPatch" flag can be refined.
329 // This condition is checked in the method
330 // AMRZonePosition::toAMRPatchPosition() called above.
331 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level)) {
332 if (!icell->hasHChildren()) {
333 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
334 if (position.isInWithOverlap(pos)) {
335 icell->mutableItemBase().addFlags(ItemFlags::II_Refine);
336 }
337 }
338 }
339
340 amr->refine();
341
342 // We transition from an intermediate patch to a classic patch.
343 AMRPatchPosition position_up = position.patchUp(m_cmesh->mesh()->dimension(), higher_level, m_size_of_overlap_layer_top_level);
344
345 info() << "Zone to Patch"
346 << " -- minPoint : " << position_up.minPoint()
347 << " -- maxPoint : " << position_up.maxPoint()
348 << " -- overlapLayerSize : " << position_up.overlapLayerSize()
349 << " -- level : " << position_up.level();
350
351 // We add this patch to our object.
352 _addPatch(position_up);
353
354 // If the created patch is higher than the others, a new refinement level has
355 // been created and we must update the number oF overlap layers for lower levels.
356 _updateHigherLevel();
357
358#ifdef ARCANE_CHECK
359 _checkPatchesAndMesh();
360#endif
361}
362
363/*---------------------------------------------------------------------------*/
364/*---------------------------------------------------------------------------*/
365
366Integer CartesianPatchGroup::
367nbPatch() const
368{
369 return m_amr_patches.size();
370}
371
372/*---------------------------------------------------------------------------*/
373/*---------------------------------------------------------------------------*/
374
375Ref<CartesianMeshPatch> CartesianPatchGroup::
376patch(const Integer index) const
377{
378 return m_amr_patches[index];
379}
380
381/*---------------------------------------------------------------------------*/
382/*---------------------------------------------------------------------------*/
383
384CartesianMeshPatchListView CartesianPatchGroup::
385patchListView() const
386{
387 return CartesianMeshPatchListView{ m_amr_patches_pointer };
388}
389
390/*---------------------------------------------------------------------------*/
391/*---------------------------------------------------------------------------*/
392
393CellGroup CartesianPatchGroup::
394allCells(const Integer index)
395{
396 return m_amr_patch_cell_groups_all[index];
397}
398
399/*---------------------------------------------------------------------------*/
400/*---------------------------------------------------------------------------*/
401
402CellGroup CartesianPatchGroup::
403inPatchCells(Integer index)
404{
405 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
406 ARCANE_FATAL("Method available only with AMR PatchCartesianMeshOnly");
407 }
408 return m_amr_patch_cell_groups_inpatch[index];
409}
410
411/*---------------------------------------------------------------------------*/
412/*---------------------------------------------------------------------------*/
413
414CellGroup CartesianPatchGroup::
415overlapCells(Integer index)
416{
417 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
418 ARCANE_FATAL("Method available only with AMR PatchCartesianMeshOnly");
419 }
420 return m_amr_patch_cell_groups_overlap[index];
421}
422
423/*---------------------------------------------------------------------------*/
424/*---------------------------------------------------------------------------*/
425
426// Warning: also clears the ground patch. It is necessary to retrieve it afterwards.
427// (the m_all_items_direction_info of CartesianMeshImpl)
428void CartesianPatchGroup::
429clear()
430{
431 _removeAllPatches();
432}
433
434/*---------------------------------------------------------------------------*/
435/*---------------------------------------------------------------------------*/
436
437void CartesianPatchGroup::
438removePatch(const Integer index)
439{
440 if (m_patches_to_delete.contains(index)) {
441 return;
442 }
443 if (index == 0) {
444 ARCANE_FATAL("You cannot remove ground patch");
445 }
446 if (index < 1 || index >= m_amr_patches.size()) {
447 ARCANE_FATAL("Invalid index");
448 }
449
450 m_patches_to_delete.add(index);
451}
452
453/*---------------------------------------------------------------------------*/
454/*---------------------------------------------------------------------------*/
455
456void CartesianPatchGroup::
457removeCellsInAllPatches(ConstArrayView<Int32> cells_local_id)
458{
459 if (m_cmesh->mesh()->meshKind().meshAMRKind() == eMeshAMRKind::PatchCartesianMeshOnly) {
460 ARCANE_FATAL("Method available only with AMR Cell");
461 }
462
463 // In AMR type 1, there are only "all" groups.
464 for (Integer i = 1; i < m_amr_patch_cell_groups_all.size(); ++i) {
465 allCells(i).removeItems(cells_local_id);
466 }
467 applyPatchEdit(true, false);
468}
469
470/*---------------------------------------------------------------------------*/
471/*---------------------------------------------------------------------------*/
472
473void CartesianPatchGroup::
474_removeCellsInAllPatches(const AMRPatchPosition& zone_to_delete)
475{
476 // Caution if removing the two-step removal: _removePartOfPatch() also deletes patches.
477 // i = 1 because the ground patch cannot be defined/refined.
478 const Integer nb_patchs = m_amr_patches_pointer.size();
479 for (Integer i = 1; i < nb_patchs; ++i) {
480 ICartesianMeshPatch* patch = m_amr_patches_pointer[i];
481 // info() << "I : " << i
482 // << " -- Compare Patch (min : " << patch->position().minPoint()
483 // << ", max : " << patch->position().maxPoint()
484 // << ", level : " << patch->position().level()
485 // << ") and Zone (min : " << zone_to_delete.minPoint()
486 // << ", max : " << zone_to_delete.maxPoint()
487 // << ", level : " << zone_to_delete.level() << ")";
488
489 if (zone_to_delete.haveIntersection(patch->position())) {
490 _removePartOfPatch(i, zone_to_delete);
491 }
492 }
493}
494
495/*---------------------------------------------------------------------------*/
496/*---------------------------------------------------------------------------*/
497
498void CartesianPatchGroup::
499removeCellsInZone(const AMRZonePosition& zone_to_delete)
500{
501 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
502 ARCANE_FATAL("Method available only with AMR PatchCartesianMeshOnly");
503 }
504 clearRefineRelatedFlags();
505
506 UniqueArray<Int32> cells_local_id;
507
508 AMRPatchPosition patch_position;
509 zone_to_delete.cellsInPatch(m_cmesh, cells_local_id, patch_position);
510
511 _removeCellsInAllPatches(patch_position);
512 applyPatchEdit(false, false);
513 _updatePatchFlagsOfItemsLevel(patch_position.level(), true);
514 _updateHigherLevel();
515 _coarsenUselessCells(true);
516
517#ifdef ARCANE_CHECK
518 _checkPatchesAndMesh();
519#endif
520}
521
522/*---------------------------------------------------------------------------*/
523/*---------------------------------------------------------------------------*/
524
525void CartesianPatchGroup::
526applyPatchEdit(bool remove_empty_patches, bool update_higher_level)
527{
528 // m_cmesh->mesh()->traceMng()->info() << "applyPatchEdit() -- Remove nb patch : " << m_patches_to_delete.size();
529
530 std::stable_sort(m_patches_to_delete.begin(), m_patches_to_delete.end(),
531 [](const Integer a, const Integer b) {
532 return a < b;
533 });
534
535 _removeMultiplePatches(m_patches_to_delete);
536 m_patches_to_delete.clear();
537
538 // In AMR type 3, there cannot be an empty patch.
539 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly && remove_empty_patches) {
540 UniqueArray<Integer> size_of_patches(m_amr_patch_cell_groups_all.size());
541 for (Integer i = 0; i < m_amr_patch_cell_groups_all.size(); ++i) {
542 size_of_patches[i] = m_amr_patch_cell_groups_all[i].size();
543 }
544 m_cmesh->mesh()->parallelMng()->reduce(MessagePassing::ReduceMax, size_of_patches);
545 for (Integer i = 0; i < size_of_patches.size(); ++i) {
546 if (size_of_patches[i] == 0) {
547 m_patches_to_delete.add(i);
548 }
549 }
550 _removeMultiplePatches(m_patches_to_delete);
551 m_patches_to_delete.clear();
552 }
553
554 // In AMR type 1, there is no concept of patch level.
555 if (m_cmesh->mesh()->meshKind().meshAMRKind() == eMeshAMRKind::PatchCartesianMeshOnly && update_higher_level) {
556 _updateHigherLevel();
557 _coarsenUselessCells(true);
558 }
559}
560
561/*---------------------------------------------------------------------------*/
562/*---------------------------------------------------------------------------*/
563
564void CartesianPatchGroup::
565updateLevelsAndAddGroundPatch()
566{
567 // TODO: This method should call createSubLevel(), not the other way around.
568 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
569 return;
570 }
571 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
572 auto amr = m_cmesh->_internalApi()->cartesianMeshAMRPatchMng();
573
574 amr->createSubLevel();
575
576 // Warning: we assume that numbering->updateFirstLevel(); has already been called!
577
578 for (ICartesianMeshPatch* patch : m_amr_patches_pointer) {
579 const Int32 level = patch->position().level();
580 // If the level is 0, it is the special patch 0, so we only modify the max, the level remains 0.
581 if (level == 0) {
582 const CartCoord3 max_point = patch->position().maxPoint();
583 if (m_cmesh->mesh()->dimension() == 2) {
584 patch->_internalApi()->positionRef().setMaxPoint({
585 numbering->offsetLevelToLevel(max_point.x, level, level - 1),
586 numbering->offsetLevelToLevel(max_point.y, level, level - 1),
587 1,
588 });
589 }
590 else {
591 patch->_internalApi()->positionRef().setMaxPoint({
592 numbering->offsetLevelToLevel(max_point.x, level, level - 1),
593 numbering->offsetLevelToLevel(max_point.y, level, level - 1),
594 numbering->offsetLevelToLevel(max_point.z, level, level - 1),
595 });
596 }
597 }
598 // Otherwise, we "elevate" the level of the patches since there will be the "-1" patch
599 else {
600 patch->_internalApi()->positionRef().setLevel(level + 1);
601 }
602 }
603
604 {
605 AMRPatchPosition old_ground;
606 old_ground.setLevel(1);
607 old_ground.setMinPoint({ 0, 0, 0 });
608 old_ground.setMaxPoint({ numbering->globalNbCellsX(1), numbering->globalNbCellsY(1), numbering->globalNbCellsZ(1) });
609 old_ground.computeOverlapLayerSize(m_higher_level + 1, m_size_of_overlap_layer_top_level);
610 _addPatch(old_ground);
611 }
612 // Calculate the directions of the new ground patch.
613 m_cmesh->computeDirectionsPatchV2(0);
614
615 _updatePatchFlagsOfItemsGroundLevel();
616
617 // The methods _increaseOverlapSizeLevel() and _reduceOverlapSizeLevel()
618 // will handle recalculating the directions of the elevated patches.
619 // Note: Recalculation is necessary because we add/delete overlap cells.
620 _updateHigherLevel();
621
622#ifdef ARCANE_CHECK
623 _checkPatchesAndMesh();
624#endif
625}
626
627/*---------------------------------------------------------------------------*/
628/*---------------------------------------------------------------------------*/
629
630Integer CartesianPatchGroup::
631_nextIndexForNewPatch()
632{
633 if (!m_available_group_index.empty()) {
634 const Integer elem = m_available_group_index.back();
635 m_available_group_index.popBack();
636 return elem;
637 }
638 return m_index_new_patches++;
639}
640
641/*---------------------------------------------------------------------------*/
642/*---------------------------------------------------------------------------*/
643
644void CartesianPatchGroup::
645mergePatches()
646{
647 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
648 return;
649 }
650 UniqueArray<Int32> new_merged_patches;
651
652 // info() << "Global fusion";
653 UniqueArray<std::pair<Integer, Int64>> index_n_nb_cells;
654 {
655 Integer index = 0;
656 for (auto patch : m_amr_patches_pointer) {
657 index_n_nb_cells.add({ index++, patch->position().nbCells() });
658 }
659 }
660
661 // Merge algorithm.
662 // First, we sort the patches from the smallest number of cells to the largest number of cells (optional).
663 // Then, for each patch, we check if it can be merged with another.
664 // If a merge is made, we restart the algorithm until no more merges can be made.
665 bool fusion = true;
666 while (fusion) {
667 fusion = false;
668
669 std::stable_sort(index_n_nb_cells.begin(), index_n_nb_cells.end(),
670 [](const std::pair<Integer, Int64>& a, const std::pair<Integer, Int64>& b) {
671 return a.second < b.second;
672 });
673
674 for (Integer p0 = 0; p0 < index_n_nb_cells.size(); ++p0) {
675 auto [index_p0, nb_cells_p0] = index_n_nb_cells[p0];
676
677 AMRPatchPosition& patch_fusion_0 = m_amr_patches_pointer[index_p0]->_internalApi()->positionRef();
678 if (patch_fusion_0.isNull())
679 continue;
680
681 // If a merge has already occurred, we must then look at the patches before "p0"
682 // (since at least one has been modified).
683 // (an "optimization" could be to retrieve the position of the first
684 // merged patch but well, less readable + not many patches).
685 for (Integer p1 = p0 + 1; p1 < m_amr_patches_pointer.size(); ++p1) {
686 auto [index_p1, nb_cells_p1] = index_n_nb_cells[p1];
687
688 AMRPatchPosition& patch_fusion_1 = m_amr_patches_pointer[index_p1]->_internalApi()->positionRef();
689 if (patch_fusion_1.isNull())
690 continue;
691
692 // info() << "\tCheck fusion"
693 // << " -- 0 Min point : " << patch_fusion_0.minPoint()
694 // << " -- 0 Max point : " << patch_fusion_0.maxPoint()
695 // << " -- 0 Level : " << patch_fusion_0.level()
696 // << " -- 1 Min point : " << patch_fusion_1.minPoint()
697 // << " -- 1 Max point : " << patch_fusion_1.maxPoint()
698 // << " -- 1 Level : " << patch_fusion_1.level();
699
700 if (patch_fusion_0.fusion(patch_fusion_1)) {
701 // info() << "Fusion OK";
702 index_n_nb_cells[p0].second = patch_fusion_0.nbCells();
703
704 // info() << "Remove patch : " << index_p1;
705 removePatch(index_p1);
706
707 if (!new_merged_patches.contains(index_p0)) {
708 new_merged_patches.add(index_p0);
709 }
710
711 auto find_p1 = new_merged_patches.span().findFirst(index_p1);
712 if (find_p1.has_value()) {
713 new_merged_patches.remove(find_p1.value());
714 }
715
716 fusion = true;
717 break;
718 }
719 }
720 if (fusion) {
721 break;
722 }
723 }
724 }
725
726 UniqueArray<Int32> levels_edited;
727 for (Int32 patch_index : new_merged_patches) {
728 _updateCellGroups(patch_index, false);
729
730 Int32 level = patch(patch_index)->_internalApi()->positionRef().level();
731 if (!levels_edited.contains(level)) {
732 levels_edited.add(level);
733 }
734 }
735 applyPatchEdit(false, false);
736
737 for (Int32 level : levels_edited) {
738 _updatePatchFlagsOfItemsLevel(level, true);
739 }
740
741#ifdef ARCANE_CHECK
742 _checkPatchesAndMesh();
743#endif
744}
745
746/*---------------------------------------------------------------------------*/
747/*---------------------------------------------------------------------------*/
748
749void CartesianPatchGroup::
750beginAdaptMesh(Int32 nb_levels, Int32 level_to_refine_first)
751{
752 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
753 ARCANE_FATAL("Method available only with AMR PatchCartesianMeshOnly");
754 }
755 if (m_latest_call_level != -2) {
756 ARCANE_FATAL("Call endAdaptMesh() before restart mesh adaptation");
757 }
758 if (level_to_refine_first > m_higher_level) {
759 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);
760 }
761
762 Trace::Setter mci(traceMng(), "CartesianPatchGroup");
763 info() << "Begin adapting mesh with higher level = " << (nb_levels - 1);
764
765 // We delete all patches above the first level to refine.
766 Int32 max_level = 0;
767 for (Integer p = 1; p < m_amr_patches_pointer.size(); ++p) {
768 Int32 level = m_amr_patches_pointer[p]->_internalApi()->positionRef().level();
769 if (level > level_to_refine_first) {
770 removePatch(p);
771 max_level = level;
772 }
773 }
774 applyPatchEdit(false, false);
775
776 // We also remove the II_InPatch and II_Overlap flags from the cells so that
777 // those that are no longer used in any of the new patches are deleted in the finalizeAdaptMesh() method.
778 for (Integer l = level_to_refine_first + 1; l <= max_level; ++l) {
779 _removePatchFlagsOfItemsLevel(l);
780 }
781 // We must adapt all levels below the level to adapt.
782 // Patches of level "level_to_refine_first" (exclusive) and higher will be deleted.
783 if (nb_levels - 1 != m_higher_level) {
784 debug() << "beginAdaptMesh() -- Change overlap layer size -- Old higher level : " << m_higher_level
785 << " -- Asked higher level : " << (nb_levels - 1)
786 << " -- Adapt level lower than : " << level_to_refine_first;
787
788 for (Int32 level = 1; level <= level_to_refine_first; ++level) {
789 _changeOverlapSizeLevel(level, m_higher_level, nb_levels - 1);
790 }
791 }
792
793 m_target_nb_levels = nb_levels;
794 m_latest_call_level = level_to_refine_first - 1;
795 // m_higher_level keeps its old value.
796}
797
798/*---------------------------------------------------------------------------*/
799/*---------------------------------------------------------------------------*/
800
801void CartesianPatchGroup::
802endAdaptMesh()
803{
804 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
805 ARCANE_FATAL("Method available only with AMR PatchCartesianMeshOnly");
806 }
807 if (m_latest_call_level == -2) {
808 ARCANE_FATAL("Call beginAdaptMesh() before");
809 }
810 Trace::Setter mci(traceMng(), "CartesianPatchGroup");
811 info() << "Finalizing adapting mesh with higher level = " << (m_target_nb_levels - 1);
812
813 auto amr = m_cmesh->_internalApi()->cartesianMeshAMRPatchMng();
814
815 // The highest level becomes the last adapted level (+1 to have the refined level).
816 // We are sure this is the highest level given that we systematically delete
817 // patches above it in adaptLevel().
818 // beginAdaptMesh() sets the first level to refine given by the user
819 // in the m_latest_call_level attribute and checks if the level exists. The
820 // first m_latest_call_level is therefore valid.
821 m_higher_level = m_latest_call_level + 1;
822
823 // If m_latest_call_level == 0, then adaptLevel() created level 1, so
824 // there are 2 levels.
825 // If the highest created level is lower than the highest level given
826 // by the user in the beginAdaptMesh() method, we are forced to
827 // re-adapt the number of overlap cell layers for each patch.
828 if (m_higher_level + 1 < m_target_nb_levels) {
829 info() << "Reduce higher level from " << (m_target_nb_levels - 1) << " to " << m_higher_level;
830
831 for (Int32 level = 1; level <= m_higher_level; ++level) {
832 _changeOverlapSizeLevel(level, m_target_nb_levels - 1, m_higher_level);
833 }
834 }
835
836 _coarsenUselessCells(true);
837
838 m_target_nb_levels = 0;
839 m_latest_call_level = -2;
840 clearRefineRelatedFlags();
841
842 info() << "Patch list:";
843
844 for (Integer i = 0; i <= m_higher_level; ++i) {
845 for (auto p : m_amr_patches_pointer) {
846 auto& position = p->_internalApi()->positionRef();
847 if (position.level() == i) {
848 info() << "\tPatch #" << p->index()
849 << " -- Level : " << position.level()
850 << " -- Min point : " << position.minPoint()
851 << " -- Max point : " << position.maxPoint()
852 << " -- Overlap layer size : " << position.overlapLayerSize();
853 }
854 }
855 }
856#ifdef ARCANE_CHECK
857 _checkPatchesAndMesh();
858#endif
859}
860
861/*---------------------------------------------------------------------------*/
862/*---------------------------------------------------------------------------*/
863
864void CartesianPatchGroup::
865adaptLevel(Int32 level_to_adapt, bool do_fatal_if_useless)
866{
867 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
868 ARCANE_FATAL("Method available only with AMR PatchCartesianMeshOnly");
869 }
870 if (m_latest_call_level == -2) {
871 ARCANE_FATAL("Call beginAdaptMesh() before to begin a mesh adaptation");
872 }
873 if (level_to_adapt + 1 >= m_target_nb_levels || level_to_adapt < 0) {
874 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);
875 }
876
877 Trace::Setter mci(traceMng(), "CartesianPatchGroup");
878
879 if (level_to_adapt > m_latest_call_level + 1) {
880 if (do_fatal_if_useless) {
881 ARCANE_FATAL("You must refine level {0} before.", (m_latest_call_level + 1));
882 }
883 warning() << String::format("Useless call -- You must refine level {0} before.", (m_latest_call_level + 1));
884 return;
885 }
886
887 // We delete all patches above the level we want to adapt.
888 // We also do this here in the case where the user calls this method
889 // with a level lower than their previous call (which is not
890 // necessarily optimal since we delete what was calculated
891 // previously...).
892 if (level_to_adapt < m_latest_call_level) {
893 Int32 max_level = 0;
894 for (Integer p = 1; p < m_amr_patches_pointer.size(); ++p) {
895 Int32 level = m_amr_patches_pointer[p]->_internalApi()->positionRef().level();
896 if (level > level_to_adapt) {
897 removePatch(p);
898 max_level = level;
899 }
900 }
901 applyPatchEdit(false, false);
902
903 for (Integer l = level_to_adapt + 1; l <= max_level; ++l) {
904 _removePatchFlagsOfItemsLevel(l);
905 }
906 }
907
908 auto amr = m_cmesh->_internalApi()->cartesianMeshAMRPatchMng();
909 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
910
911 // The number of overlap cell layers.
912 // +1 because the created patches will be at level level_to_adapt + 1.
913 // /pattern because the cells to refine are at level level_to_adapt.
914 //
915 // Explanation:
916 // level_to_adapt=0,
917 // future patches will be at level 1, so the number of overlap layers
918 // must be that corresponding to level 1
919 // (thus level_to_adapt+1),
920 // or, the cells to refine are at level 0, so we must divide the
921 // number of layers by the number of child cells that will be created
922 // (for one dimension) (thus numbering->pattern()).
923 Int32 nb_overlap_cells = overlapLayerSize(level_to_adapt + 1) / numbering->pattern();
924
925 info() << "adaptLevel()"
926 << " -- Level to adapt : " << level_to_adapt
927 << " -- Nb of overlap cells (intermediary patch) : " << nb_overlap_cells;
928
929 // Two checks:
930 // - we cannot refine multiple levels at once,
931 // - we cannot refine cells that are not in a patch (overlap cells are not necessarily in a patch).
932 // In addition, we must know if there is at least one cell with the
933 // II_Refine flag to know if it is useful to continue the method or not.
934 bool has_cell_to_refine = false;
935 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allCells()) {
936 if (icell->hasFlags(ItemFlags::II_Refine)) {
937 if (icell->level() != level_to_adapt) {
938 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);
939 }
940 if (level_to_adapt != 0 && !icell->hasFlags(ItemFlags::II_InPatch)) {
941 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
942 ARCANE_FATAL("Cannot refine cell not in patch -- Pos : {0} -- CellUID : {1} -- CellLevel : {2}", pos, icell->uniqueId(), icell->level());
943 }
944 has_cell_to_refine = true;
945 }
946 }
947 has_cell_to_refine = m_cmesh->mesh()->parallelMng()->reduce(MessagePassing::ReduceMax, has_cell_to_refine);
948
949 if (!has_cell_to_refine) {
950 if (do_fatal_if_useless) {
951 ARCANE_FATAL("There are no cells to refine.");
952 }
953 // We recall that, in endAdaptMesh(), m_higher_level will take the value
954 // of m_latest_call_level + 1.
955 //
956 // It is important to set -1 here in the case where (for example):
957 // - Initially, there are no patches (m_latest_call_level == -1), adaptLevel(0):
958 // -> We refine level 0 cells, so m_latest_call_level = 0 and
959 // thus, m_higher_level will be equal to 1
960 // - We call adaptLevel(0) a second time:
961 // -> The user has not marked any level 0 cells, so
962 // m_latest_call_level = -1 and thus m_higher_level = 0.
963 // Above, we delete levels higher than level_to_adapt even if
964 // the call to adaptLevel() does not refine any cells, so we must update
965 // m_latest_call_level.
966 m_latest_call_level = level_to_adapt - 1;
967 debug() << "adaptLevel() -- End call -- No refine -- Actual patch list:";
968
969 for (Integer i = 0; i <= m_target_nb_levels; ++i) {
970 for (auto p : m_amr_patches_pointer) {
971 auto& position = p->_internalApi()->positionRef();
972 if (position.level() == i) {
973 debug() << "\tPatch #" << p->index()
974 << " -- Level : " << position.level()
975 << " -- Min point : " << position.minPoint()
976 << " -- Max point : " << position.maxPoint()
977 << " -- Overlap layer size : " << position.overlapLayerSize();
978 }
979 }
980 }
981 return;
982 }
983
984 m_latest_call_level = level_to_adapt;
985
986 UniqueArray<AMRPatchPositionSignature> sig_array;
987
988 // We must provide one or more initial patches to be reduced and
989 // cut.
990 // If the level to adapt is level 0, we can create an initial patch
991 // that is the size of the ground patch.
992 // We don't need to reduce it; AMRPatchPositionSignature::fillSig()
993 // will take care of it.
994 if (level_to_adapt == 0) {
995 AMRPatchPosition all_level;
996 all_level.setLevel(level_to_adapt);
997 all_level.setMinPoint({ 0, 0, 0 });
998 all_level.setMaxPoint({ numbering->globalNbCellsX(level_to_adapt), numbering->globalNbCellsY(level_to_adapt), numbering->globalNbCellsZ(level_to_adapt) });
999 // For this setOverlapLayerSize(), see the explanation above.
1000 all_level.setOverlapLayerSize(nb_overlap_cells);
1001 AMRPatchPositionSignature sig(all_level, m_cmesh);
1002 sig_array.add(sig);
1003 }
1004
1005 // For other levels, we create the initial patches by copying the
1006 // patches from level_to_adapt.
1007 // We cannot create a patch that is the size of level_to_adapt
1008 // because it is imperative that the patch(es) generated by
1009 // AMRPatchPositionSignatureCut (future patches of level_to_adapt+1)
1010 // be included in the patch(es) of level_to_adapt! (otherwise we would have orphaned cells).
1011 // We can take these patches as initial patches because we know that the
1012 // only cells we will refine are in the patch(es) of level_to_adapt (cells having the II_InPatch flag).
1013 // We also know that the methods of AMRPatchPositionSignatureCut cannot enlarge the initial patches (only reduce or cut).
1014 // (and yes, the if(level_to_adapt == 0) is not essential, but since we know there is only one level 0 patch, it is faster).
1015 else {
1016 for (auto patch : m_amr_patches_pointer) {
1017 Integer level = patch->_internalApi()->positionRef().level();
1018 if (level == level_to_adapt) {
1019 auto position = patch->position();
1020 position.setOverlapLayerSize(nb_overlap_cells);
1021 AMRPatchPositionSignature sig(position, m_cmesh);
1022 sig_array.add(sig);
1023 }
1024 }
1025 }
1026
1027 AMRPatchPositionSignatureCut::cut(sig_array);
1028
1029 // Once the patches are cut, we add the II_Refine flag to the cells of
1030 // these patches.
1031 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level_to_adapt)) {
1032 if (!icell->hasHChildren()) {
1033 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
1034 for (const AMRPatchPositionSignature& patch_signature : sig_array) {
1035 if (patch_signature.patch().isInWithOverlap(pos)) {
1036 if (!icell->hasFlags(ItemFlags::II_InPatch) && !icell->hasFlags(ItemFlags::II_Overlap)) {
1037 ARCANE_FATAL("Internal error -- Refine algo error -- Pos : {0}", pos);
1038 }
1039 icell->mutableItemBase().addFlags(ItemFlags::II_Refine);
1040 }
1041 }
1042 }
1043 }
1044
1045 {
1046 // UniqueArray<CartCoord> out(numbering->globalNbCellsY(level_to_adapt) * numbering->globalNbCellsX(level_to_adapt), -1);
1047 // Array2View av_out(out.data(), numbering->globalNbCellsY(level_to_adapt), numbering->globalNbCellsX(level_to_adapt));
1048 // ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level_to_adapt)) {
1049 // CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
1050 // if (icell->hasHChildren()) {
1051 // av_out(pos.y, pos.x) = 0;
1052 // }
1053 // if (icell->hasFlags(ItemFlags::II_Refine)) {
1054 // av_out(pos.y, pos.x) = 1;
1055 // }
1056 // }
1057 //
1058 // StringBuilder str = "";
1059 // for (CartCoord i = 0; i < numbering->globalNbCellsX(level_to_adapt); ++i) {
1060 // str += "\n";
1061 // for (CartCoord j = 0; j < numbering->globalNbCellsY(level_to_adapt); ++j) {
1062 // CartCoord c = av_out(i, j);
1063 // if (c == 1)
1064 // str += "[++]";
1065 // else if (c == 0)
1066 // str += "[XX]";
1067 // else
1068 // str += "[ ]";
1069 // }
1070 // }
1071 // info() << str;
1072 }
1073
1074 // We refine.
1075 amr->refine();
1076
1077 // TODO: Normally, this is not necessary, should be corrected in amr->refine().
1078 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level_to_adapt)) {
1079 icell->mutableItemBase().removeFlags(ItemFlags::II_Refine);
1080 }
1081
1082 // The patches in sig_array are "intermediate" patches. They are patches of level_to_adapt representing patches of level_to_adapt+1.
1083 // It is now necessary to convert them into level_to_adapt+1 patches.
1084 UniqueArray<AMRPatchPosition> all_patches;
1085 for (const auto& elem : sig_array) {
1086 all_patches.add(elem.patch().patchUp(m_cmesh->mesh()->dimension(), m_target_nb_levels - 1, m_size_of_overlap_layer_top_level));
1087 }
1088
1089 // We merge the patches that can be merged before "adding" them to the mesh.
1090 AMRPatchPositionLevelGroup::fusionPatches(all_patches, true);
1091
1092 // for (const AMRPatchPosition& patch : all_patches) {
1093 // debug() << "\tPatch AAA"
1094 // << " -- Level : " << patch.level()
1095 // << " -- Min point : " << patch.minPoint()
1096 // << " -- Max point : " << patch.maxPoint()
1097 // << " -- overlapLayerSize : " << patch.overlapLayerSize();
1098 // }
1099
1100 {
1101 // UniqueArray<CartCoord> out(numbering->globalNbCellsY(level_to_adapt + 1) * numbering->globalNbCellsX(level_to_adapt + 1), -1);
1102 // Array2View av_out(out.data(), numbering->globalNbCellsY(level_to_adapt + 1), numbering->globalNbCellsX(level_to_adapt + 1));
1103 // ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level_to_adapt + 1)) {
1104 //
1105 // CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
1106 // Integer patch = -1;
1107 //
1108 // if (icell->hasFlags(ItemFlags::II_Overlap) && icell->hasFlags(ItemFlags::II_InPatch)) {
1109 // patch = -2;
1110 // }
1111 // else if (icell->hasFlags(ItemFlags::II_Overlap)) {
1112 // patch = -3;
1113 // }
1114 // else if (icell->hasFlags(ItemFlags::II_InPatch)) {
1115 // patch = -4;
1116 // }
1117 // else {
1118 // patch = -5;
1119 // }
1120 // av_out(pos.y, pos.x) = patch;
1121 // if (icell->uniqueId() == 3310) {
1122 // info() << "Maille présente ! -- Coord : " << pos << " -- Flags : " << patch;
1123 // }
1124 // }
1125 //
1126 // StringBuilder str = "";
1127 // for (CartCoord i = 0; i < numbering->globalNbCellsX(level_to_adapt + 1); ++i) {
1128 // str += "\n";
1129 // for (CartCoord j = 0; j < numbering->globalNbCellsY(level_to_adapt + 1); ++j) {
1130 // CartCoord c = av_out(i, j);
1131 // if (c >= 0) {
1132 // str += "[";
1133 // if (c < 10)
1134 // str += " ";
1135 // str += c;
1136 // str += "]";
1137 // }
1138 // else if (c == -2) {
1139 // str += "[OI]";
1140 // }
1141 // else if (c == -3) {
1142 // str += "[OO]";
1143 // }
1144 // else if (c == -4) {
1145 // str += "[II]";
1146 // }
1147 // else if (c == -5) {
1148 // str += "[XX]";
1149 // }
1150 // else
1151 // str += "[ ]";
1152 // }
1153 // }
1154 // info() << str;
1155 }
1156
1157 // We add the patches to the mesh (we create the groups) and calculate the
1158 // directions for each of them (so that the user can use them directly).
1159 for (const AMRPatchPosition& patch : all_patches) {
1160 Integer index = _addPatch(patch);
1161 // TODO: But that is not a good idea at all!
1162 m_cmesh->computeDirectionsPatchV2(index);
1163 }
1164
1165 debug() << "adaptLevel() -- End call -- Actual patch list:";
1166
1167 for (Integer i = 0; i <= m_target_nb_levels; ++i) {
1168 for (auto p : m_amr_patches_pointer) {
1169 auto& position = p->_internalApi()->positionRef();
1170 if (position.level() == i) {
1171 debug() << "\tPatch #" << p->index()
1172 << " -- Level : " << position.level()
1173 << " -- Min point : " << position.minPoint()
1174 << " -- Max point : " << position.maxPoint()
1175 << " -- Overlap layer size : " << position.overlapLayerSize();
1176 }
1177 }
1178 }
1179}
1180
1181/*---------------------------------------------------------------------------*/
1182/*---------------------------------------------------------------------------*/
1183
1184void CartesianPatchGroup::
1185_increaseOverlapSizeLevel(Int32 level_to_increate, Int32 new_size)
1186{
1187 if (level_to_increate == 0) {
1188 ARCANE_FATAL("Level 0 has not overlap layer");
1189 }
1190
1191 auto amr = m_cmesh->_internalApi()->cartesianMeshAMRPatchMng();
1192 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
1193
1194 bool has_cell_to_refine = false;
1195
1196 // Three main steps:
1197 // - first, we increase the number of layers in the position structures,
1198 // then we add the II_Refine flag to parent cells that have no children,
1199 // - we refine the cells,
1200 // - we add the flags to the new cells and add them to the cell groups
1201 // of the patches.
1202 for (Integer p = 1; p < m_amr_patches_pointer.size(); ++p) {
1203 Int32 level = m_amr_patches_pointer[p]->_internalApi()->positionRef().level();
1204 if (level == level_to_increate) {
1205 AMRPatchPosition& position = m_amr_patches_pointer[p]->_internalApi()->positionRef();
1206
1207 Int32 size_layer = position.overlapLayerSize();
1208 if (size_layer > new_size) {
1209 ARCANE_FATAL("Cannot reduce layer with _increaseOverlapSizeLevel method");
1210 }
1211
1212 // We could check that the number of layers of all patches of a level is identical.
1213
1214 if (size_layer == new_size) {
1215 continue;
1216 }
1217
1218 has_cell_to_refine = true;
1219 position.setOverlapLayerSize(new_size);
1220
1221 // The cells to refine are on the lower level.
1222 // For each cell, to know whether we should refine it or not, we
1223 // move it up one level and check if it is in the overlap layers.
1224 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level_to_increate - 1)) {
1225 const CartCoord3 pos = numbering->offsetLevelToLevel(numbering->cellUniqueIdToCoord(*icell), level_to_increate - 1, level_to_increate);
1226 if (position.isInWithOverlap(pos) && !icell->hasHChildren()) {
1227 icell->mutableItemBase().addFlags(ItemFlags::II_Refine);
1228 }
1229 }
1230 }
1231 }
1232 has_cell_to_refine = m_cmesh->mesh()->parallelMng()->reduce(MessagePassing::ReduceMax, has_cell_to_refine);
1233 if (!has_cell_to_refine) {
1234 return;
1235 }
1236
1237 // We refine the cells.
1238 amr->refine();
1239
1240 // TODO: Normally, this is not necessary, should be corrected in amr->refine().
1241 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level_to_increate - 1)) {
1242 icell->mutableItemBase().removeFlags(ItemFlags::II_Refine);
1243 }
1244
1245 UniqueArray<Int32> cell_to_add;
1246
1247 // Add the flags and update the cell groups of the patches.
1248 for (Integer p = 1; p < m_amr_patches_pointer.size(); ++p) {
1249 Int32 level = m_amr_patches_pointer[p]->_internalApi()->positionRef().level();
1250 if (level == level_to_increate) {
1251 AMRPatchPosition& position = m_amr_patches_pointer[p]->_internalApi()->positionRef();
1252
1253 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level_to_increate)) {
1254 if (!icell->hasFlags(ItemFlags::II_JustAdded))
1255 continue;
1256
1257 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
1258
1259 if (position.isInWithOverlap(pos)) {
1260 cell_to_add.add(icell.localId());
1261 icell->mutableItemBase().addFlags(ItemFlags::II_Overlap);
1262 for (Face face : icell->faces()) {
1263 face.mutableItemBase().addFlags(ItemFlags::II_Overlap);
1264 }
1265 for (Node node : icell->nodes()) {
1266 node.mutableItemBase().addFlags(ItemFlags::II_Overlap);
1267 }
1268 }
1269 else if (position.isIn(pos)) {
1270 icell->mutableItemBase().addFlags(ItemFlags::II_InPatch);
1271 for (Face face : icell->faces()) {
1272 face.mutableItemBase().addFlags(ItemFlags::II_InPatch);
1273 }
1274 for (Node node : icell->nodes()) {
1275 node.mutableItemBase().addFlags(ItemFlags::II_InPatch);
1276 }
1277 }
1278 }
1279
1280 allCells(p).addItems(cell_to_add, true); //TODO Normally, set check = false
1281 overlapCells(p).addItems(cell_to_add, true);
1282 cell_to_add.clear();
1283
1284 // We calculate the directions so that the patch can be used.
1285 m_cmesh->computeDirectionsPatchV2(p);
1286 }
1287 }
1288
1289 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level_to_increate)) {
1290 icell->mutableItemBase().removeFlags(ItemFlags::II_JustAdded);
1291 }
1292}
1293
1294/*---------------------------------------------------------------------------*/
1295/*---------------------------------------------------------------------------*/
1296
1297void CartesianPatchGroup::
1298_reduceOverlapSizeLevel(Int32 level_to_reduce, Int32 new_size)
1299{
1300 // Warning: The reduction is possible because we are not deleting cells, we are removing their InPatch/Overlap flags so that they can be deleted later.
1301 // We only remove them from the cell groups of the patches.
1302 // It is therefore necessary to have another method after this one to delete cells without flags.
1303
1304 if (level_to_reduce == 0) {
1305 ARCANE_FATAL("Level 0 has not overlap layer");
1306 }
1307
1308 auto amr = m_cmesh->_internalApi()->cartesianMeshAMRPatchMng();
1309 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
1310
1311 // Two steps:
1312 // - first, we update the position structures of the patches, then we
1313 // remove from the cell groups of the patches the cells that are no longer
1314 // in the overlap layers,
1315 // - finally, we recalculate the flags for the entire level.
1316 bool has_cell_to_mark = false;
1317 UniqueArray<Int32> cell_to_remove;
1318
1319 for (Integer p = 1; p < m_amr_patches_pointer.size(); ++p) {
1320 Int32 level = m_amr_patches_pointer[p]->_internalApi()->positionRef().level();
1321 if (level == level_to_reduce) {
1322 AMRPatchPosition& position = m_amr_patches_pointer[p]->_internalApi()->positionRef();
1323
1324 Int32 size_layer = position.overlapLayerSize();
1325 if (size_layer < new_size) {
1326 ARCANE_FATAL("Cannot add layer with _reduceOverlapSizeLevel method");
1327 }
1328 if (size_layer == new_size) {
1329 continue;
1330 }
1331
1332 has_cell_to_mark = true;
1333 position.setOverlapLayerSize(new_size);
1334
1335 ENUMERATE_ (Cell, icell, overlapCells(p)) {
1336 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
1337 if (!position.isInWithOverlap(pos)) {
1338 cell_to_remove.add(icell.localId());
1339 }
1340 }
1341
1342 allCells(p).removeItems(cell_to_remove, true); //TODO Normally, set check = false
1343 overlapCells(p).removeItems(cell_to_remove, true);
1344 cell_to_remove.clear();
1345 }
1346 }
1347 has_cell_to_mark = m_cmesh->mesh()->parallelMng()->reduce(MessagePassing::ReduceMax, has_cell_to_mark);
1348 if (!has_cell_to_mark) {
1349 return;
1350 }
1351
1352 // Because of the mixing of the two flags, we must recalculate the flags.
1353 _updatePatchFlagsOfItemsLevel(level_to_reduce, true);
1354
1355 for (Integer p = 1; p < m_amr_patches_pointer.size(); ++p) {
1356 Int32 level = m_amr_patches_pointer[p]->_internalApi()->positionRef().level();
1357 if (level == level_to_reduce) {
1358 m_cmesh->computeDirectionsPatchV2(p);
1359 }
1360 }
1361}
1362
1363/*---------------------------------------------------------------------------*/
1364/*---------------------------------------------------------------------------*/
1365
1366void CartesianPatchGroup::
1367_updateHigherLevel()
1368{
1369 // We check which is the highest patch.
1370 Int32 higher_level_patch = 0;
1371
1372 for (const auto patch : m_amr_patches_pointer) {
1373 const Int32 level = patch->_internalApi()->positionRef().level();
1374 if (level > higher_level_patch) {
1375 higher_level_patch = level;
1376 }
1377 }
1378
1379 if (higher_level_patch != m_higher_level) {
1380 for (Int32 level = 1; level <= higher_level_patch; ++level) {
1381 _changeOverlapSizeLevel(level, m_higher_level, higher_level_patch);
1382 }
1383
1384 m_higher_level = higher_level_patch;
1385 }
1386}
1387
1388/*---------------------------------------------------------------------------*/
1389/*---------------------------------------------------------------------------*/
1390
1391void CartesianPatchGroup::
1392_changeOverlapSizeLevel(Int32 level, Int32 previous_higher_level, Int32 new_higher_level)
1393{
1394 if (previous_higher_level == new_higher_level) {
1395 return;
1396 }
1397
1398 Int32 old_overlap_size = ((level > previous_higher_level) ? 0 : AMRPatchPosition::computeOverlapLayerSize(level, previous_higher_level, m_size_of_overlap_layer_top_level));
1399 Int32 new_overlap_size = AMRPatchPosition::computeOverlapLayerSize(level, new_higher_level, m_size_of_overlap_layer_top_level);
1400
1401 if (old_overlap_size == new_overlap_size) {
1402 return;
1403 }
1404 if (old_overlap_size < new_overlap_size) {
1405 _increaseOverlapSizeLevel(level, new_overlap_size);
1406 }
1407 else {
1408 _reduceOverlapSizeLevel(level, new_overlap_size);
1409 }
1410}
1411
1412/*---------------------------------------------------------------------------*/
1413/*---------------------------------------------------------------------------*/
1414
1415void CartesianPatchGroup::
1416_coarsenUselessCells(bool use_cells_level)
1417{
1418 Int32 higher_level_patch = m_higher_level;
1419 if (use_cells_level) {
1420 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allCells()) {
1421 if (icell->level() > higher_level_patch) {
1422 higher_level_patch = icell->level();
1423 }
1424 }
1425 higher_level_patch = m_cmesh->mesh()->parallelMng()->reduce(MessagePassing::ReduceMax, higher_level_patch);
1426 }
1427
1428 // We delete the cells that are not/no longer in a patch.
1429 for (Integer level = higher_level_patch; level > 0; --level) {
1430 _coarsenUselessCellsInLevel(level);
1431 }
1432}
1433
1434/*---------------------------------------------------------------------------*/
1435/*---------------------------------------------------------------------------*/
1436
1437void CartesianPatchGroup::
1438_coarsenUselessCellsInLevel(Int32 level)
1439{
1440 Integer nb_cells_to_coarse = 0;
1441 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level)) {
1442 if (!icell->hasFlags(ItemFlags::II_InPatch) && !icell->hasFlags(ItemFlags::II_Overlap)) {
1443 //debug() << "Coarse CellUID : " << icell->uniqueId();
1444 icell->mutableItemBase().addFlags(ItemFlags::II_Coarsen);
1445 nb_cells_to_coarse++;
1446 }
1447 }
1448 debug() << "Remove " << nb_cells_to_coarse << " refined cells without flag in level " << level;
1449 nb_cells_to_coarse = m_cmesh->mesh()->parallelMng()->reduce(MessagePassing::ReduceMax, nb_cells_to_coarse);
1450
1451 auto amr = m_cmesh->_internalApi()->cartesianMeshAMRPatchMng();
1452 if (nb_cells_to_coarse != 0) {
1453 amr->coarsen(true);
1454 }
1455}
1456
1457/*---------------------------------------------------------------------------*/
1458/*---------------------------------------------------------------------------*/
1459
1460void CartesianPatchGroup::
1461_updatePatchFlagsOfItemsLevel(Int32 level, bool use_cell_groups)
1462{
1463 if (level == 0) {
1464 _updatePatchFlagsOfItemsGroundLevel();
1465 return;
1466 }
1467
1468 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
1469
1470 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level)) {
1471 icell->mutableItemBase().removeFlags(ItemFlags::II_InPatch | ItemFlags::II_Overlap);
1472 }
1473 ENUMERATE_ (Face, iface, m_cmesh->mesh()->allLevelCells(level).faceGroup()) {
1474 iface->mutableItemBase().removeFlags(ItemFlags::II_InPatch | ItemFlags::II_Overlap);
1475 }
1476 ENUMERATE_ (Node, inode, m_cmesh->mesh()->allLevelCells(level).nodeGroup()) {
1477 inode->mutableItemBase().removeFlags(ItemFlags::II_InPatch | ItemFlags::II_Overlap);
1478 }
1479
1480 // By using the patch cell_groups, we don't need to search,
1481 // for each mesh, whether it is in each patch.
1482 // But this requires that the cell_groups are available.
1483 if (use_cell_groups) {
1484 for (Integer p = 1; p < m_amr_patches_pointer.size(); ++p) {
1485 Int32 level_patch = m_amr_patches_pointer[p]->_internalApi()->positionRef().level();
1486 if (level_patch == level) {
1487 ENUMERATE_ (Cell, icell, inPatchCells(p)) {
1488 icell->mutableItemBase().addFlags(ItemFlags::II_InPatch);
1489 }
1490 ENUMERATE_ (Face, iface, inPatchCells(p).faceGroup()) {
1491 iface->mutableItemBase().addFlags(ItemFlags::II_InPatch);
1492 }
1493 ENUMERATE_ (Node, inode, inPatchCells(p).nodeGroup()) {
1494 inode->mutableItemBase().addFlags(ItemFlags::II_InPatch);
1495 }
1496
1497 ENUMERATE_ (Cell, icell, overlapCells(p)) {
1498 icell->mutableItemBase().addFlags(ItemFlags::II_Overlap);
1499 }
1500 ENUMERATE_ (Face, iface, overlapCells(p).faceGroup()) {
1501 iface->mutableItemBase().addFlags(ItemFlags::II_Overlap);
1502 }
1503 ENUMERATE_ (Node, inode, overlapCells(p).nodeGroup()) {
1504 inode->mutableItemBase().addFlags(ItemFlags::II_Overlap);
1505 }
1506 }
1507 }
1508 }
1509
1510 // Otherwise, a brute force method that always works.
1511 else {
1512 // We add the flags to the patch cells.
1513 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level)) {
1514 bool in_overlap = false;
1515 bool in_patch = false;
1516
1517 // If a mesh is in a patch, it gets the II_InPatch flag.
1518 // If a mesh is an overlap mesh for a patch, it gets
1519 // the II_Overlap flag.
1520 // As its name suggests, an overlap mesh can overlap another
1521 // patch. So a mesh can be both II_InPatch and
1522 // II_Overlap.
1523 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
1524
1525 for (Integer p = 1; p < m_amr_patches_pointer.size(); ++p) {
1526 auto& patch = m_amr_patches_pointer[p]->_internalApi()->positionRef();
1527 if (patch.level() != level) {
1528 continue;
1529 }
1530
1531 if (patch.isIn(pos)) {
1532 in_patch = true;
1533 }
1534 else if (patch.isInWithOverlap(pos)) {
1535 in_overlap = true;
1536 }
1537 if (in_patch && in_overlap) {
1538 break;
1539 }
1540 }
1541 if (in_patch && in_overlap) {
1542 icell->mutableItemBase().addFlags(ItemFlags::II_InPatch | ItemFlags::II_Overlap);
1543 for (Face face : icell->faces()) {
1544 face.mutableItemBase().addFlags(ItemFlags::II_InPatch | ItemFlags::II_Overlap);
1545 }
1546 for (Node node : icell->nodes()) {
1547 node.mutableItemBase().addFlags(ItemFlags::II_InPatch | ItemFlags::II_Overlap);
1548 }
1549 }
1550 else if (in_overlap) {
1551 icell->mutableItemBase().addFlags(ItemFlags::II_Overlap);
1552 icell->mutableItemBase().removeFlags(ItemFlags::II_InPatch); //Just in case.
1553 for (Face face : icell->faces()) {
1554 face.mutableItemBase().addFlags(ItemFlags::II_Overlap);
1555 }
1556 for (Node node : icell->nodes()) {
1557 node.mutableItemBase().addFlags(ItemFlags::II_Overlap);
1558 }
1559 }
1560 else if (in_patch) {
1561 icell->mutableItemBase().addFlags(ItemFlags::II_InPatch);
1562 icell->mutableItemBase().removeFlags(ItemFlags::II_Overlap); //Just in case.
1563 for (Face face : icell->faces()) {
1564 face.mutableItemBase().addFlags(ItemFlags::II_InPatch);
1565 }
1566 for (Node node : icell->nodes()) {
1567 node.mutableItemBase().addFlags(ItemFlags::II_InPatch);
1568 }
1569 }
1570 else {
1571 icell->mutableItemBase().removeFlags(ItemFlags::II_InPatch | ItemFlags::II_Overlap); //Just in case.
1572 }
1573 }
1574 }
1575}
1576
1577/*---------------------------------------------------------------------------*/
1578/*---------------------------------------------------------------------------*/
1579
1580void CartesianPatchGroup::
1581_updatePatchFlagsOfItemsGroundLevel()
1582{
1583 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(0)) {
1584 icell->mutableItemBase().addFlags(ItemFlags::II_InPatch);
1585 }
1586 ENUMERATE_ (Face, iface, m_cmesh->mesh()->allLevelCells(0).faceGroup()) {
1587 iface->mutableItemBase().addFlags(ItemFlags::II_InPatch);
1588 }
1589 ENUMERATE_ (Node, inode, m_cmesh->mesh()->allLevelCells(0).nodeGroup()) {
1590 inode->mutableItemBase().addFlags(ItemFlags::II_InPatch);
1591 }
1592}
1593
1594/*---------------------------------------------------------------------------*/
1595/*---------------------------------------------------------------------------*/
1596
1597void CartesianPatchGroup::
1598_removePatchFlagsOfItemsLevel(Int32 level)
1599{
1600 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level)) {
1601 icell->mutableItemBase().removeFlags(ItemFlags::II_Overlap | ItemFlags::II_InPatch);
1602 }
1603 ENUMERATE_ (Face, iface, m_cmesh->mesh()->allLevelCells(level).faceGroup()) {
1604 iface->mutableItemBase().removeFlags(ItemFlags::II_Overlap | ItemFlags::II_InPatch);
1605 }
1606 ENUMERATE_ (Node, inode, m_cmesh->mesh()->allLevelCells(level).nodeGroup()) {
1607 inode->mutableItemBase().removeFlags(ItemFlags::II_Overlap | ItemFlags::II_InPatch);
1608 }
1609}
1610
1611/*---------------------------------------------------------------------------*/
1612/*---------------------------------------------------------------------------*/
1613
1614void CartesianPatchGroup::
1615_checkPatchesAndMesh()
1616{
1617 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
1618 {
1619 Int32 higher_level = 0;
1620 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allCells()) {
1621 if (icell->level() > higher_level) {
1622 higher_level = icell->level();
1623 }
1624 }
1625 higher_level = m_cmesh->mesh()->parallelMng()->reduce(MessagePassing::ReduceMax, higher_level);
1626 if (higher_level != m_higher_level) {
1627 ARCANE_FATAL("_checkPatchesAndMesh -- Bad higher level -- m_higher_level : {0} -- Found : {1}", m_higher_level, higher_level);
1628 }
1629 }
1630 {
1631 for (Int32 level = 0; level < m_higher_level; ++level) {
1632 Int32 check_overlap = overlapLayerSize(level);
1633 for (Integer p = 0; p < m_amr_patches_pointer.size(); ++p) {
1634 auto& position = m_amr_patches_pointer[p]->_internalApi()->positionRef();
1635 if (position.level() == level) {
1636 if (check_overlap == -1) {
1637 check_overlap = position.overlapLayerSize();
1638 }
1639 else if (check_overlap != position.overlapLayerSize()) {
1640 ARCANE_FATAL("_checkPatchesAndMesh -- Overlap size incoherence -- Patch pos : {0} -- Previous size : {1} -- Found : {2}", p, check_overlap, position.overlapLayerSize());
1641 }
1642 }
1643 }
1644 }
1645 }
1646 {
1647 // II_UserMark1 = II_Overlap
1648 // II_UserMark2 = II_InPatch
1649 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allCells()) {
1650 Integer level = icell->level();
1651
1652 bool in_overlap = false;
1653 bool in_patch = false;
1654
1655 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
1656
1657 for (auto p : m_amr_patches_pointer) {
1658 auto& patch = p->_internalApi()->positionRef();
1659 if (patch.level() != level) {
1660 continue;
1661 }
1662
1663 if (patch.isIn(pos)) {
1664 in_patch = true;
1665 }
1666 else if (patch.isInWithOverlap(pos)) {
1667 in_overlap = true;
1668 }
1669 if (in_patch && in_overlap) {
1670 break;
1671 }
1672 }
1673 if (in_patch && in_overlap) {
1674 icell->mutableItemBase().addFlags(ItemFlags::II_UserMark1); // II_Overlap
1675 icell->mutableItemBase().addFlags(ItemFlags::II_UserMark2); // II_InPatch
1676 }
1677 else if (in_overlap) {
1678 icell->mutableItemBase().addFlags(ItemFlags::II_UserMark1); // II_Overlap
1679 icell->mutableItemBase().removeFlags(ItemFlags::II_UserMark2); // II_InPatch
1680 }
1681 else if (in_patch) {
1682 icell->mutableItemBase().addFlags(ItemFlags::II_UserMark2); // II_InPatch
1683 icell->mutableItemBase().removeFlags(ItemFlags::II_UserMark1); // II_Overlap
1684 }
1685 else {
1686 icell->mutableItemBase().removeFlags(ItemFlags::II_UserMark2); // II_InPatch
1687 icell->mutableItemBase().removeFlags(ItemFlags::II_UserMark1); // II_Overlap
1688 }
1689 }
1690 ENUMERATE_ (Face, iface, m_cmesh->mesh()->allFaces()) {
1691 Int32 max_level = 0;
1692 for (Cell cell : iface->cells()) {
1693 if (cell.level() > max_level) {
1694 max_level = cell.level();
1695 }
1696 }
1697 for (Cell cell : iface->cells()) {
1698 if (cell.level() != max_level) {
1699 continue;
1700 }
1701 if (cell.hasFlags(ItemFlags::II_UserMark1)) {
1702 iface->mutableItemBase().addFlags(ItemFlags::II_UserMark1); // II_Overlap
1703 }
1704 if (cell.hasFlags(ItemFlags::II_UserMark2)) {
1705 iface->mutableItemBase().addFlags(ItemFlags::II_UserMark2); // II_InPatch
1706 }
1707 }
1708 }
1709 ENUMERATE_ (Node, inode, m_cmesh->mesh()->allNodes()) {
1710 Int32 max_level = 0;
1711 for (Cell cell : inode->cells()) {
1712 if (cell.level() > max_level) {
1713 max_level = cell.level();
1714 }
1715 }
1716 for (Cell cell : inode->cells()) {
1717 if (cell.level() != max_level) {
1718 continue;
1719 }
1720 if (cell.hasFlags(ItemFlags::II_UserMark1)) {
1721 inode->mutableItemBase().addFlags(ItemFlags::II_UserMark1); // II_Overlap
1722 }
1723 if (cell.hasFlags(ItemFlags::II_UserMark2)) {
1724 inode->mutableItemBase().addFlags(ItemFlags::II_UserMark2); // II_InPatch
1725 }
1726 }
1727 }
1728
1729 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allCells()) {
1730 if (icell->hasFlags(ItemFlags::II_UserMark1)) {
1731 if (!icell->hasFlags(ItemFlags::II_Overlap)) {
1732 ARCANE_FATAL("_checkPatchesAndMesh -- II_UserMark1 but not II_Overlap -- CellUID : {0}", icell->uniqueId());
1733 }
1734 }
1735 if (icell->hasFlags(ItemFlags::II_UserMark2)) {
1736 if (!icell->hasFlags(ItemFlags::II_InPatch)) {
1737 ARCANE_FATAL("_checkPatchesAndMesh -- II_UserMark2 but not II_InPatch -- CellUID : {0}", icell->uniqueId());
1738 }
1739 }
1740 if (icell->hasFlags(ItemFlags::II_Overlap)) {
1741 if (!icell->hasFlags(ItemFlags::II_UserMark1)) {
1742 ARCANE_FATAL("_checkPatchesAndMesh -- II_Overlap but not II_UserMark1 -- CellUID : {0}", icell->uniqueId());
1743 }
1744 }
1745 if (icell->hasFlags(ItemFlags::II_InPatch)) {
1746 if (!icell->hasFlags(ItemFlags::II_UserMark2)) {
1747 ARCANE_FATAL("_checkPatchesAndMesh -- II_InPatch but not II_UserMark2 -- CellUID : {0}", icell->uniqueId());
1748 }
1749 }
1750
1751 // Today, we can have refined cells but in no patch.
1752
1753 icell->mutableItemBase().removeFlags(ItemFlags::II_UserMark1); // II_Overlap
1754 icell->mutableItemBase().removeFlags(ItemFlags::II_UserMark2); // II_InPatch
1755 }
1756 ENUMERATE_ (Face, iface, m_cmesh->mesh()->allFaces()) {
1757 if (iface->hasFlags(ItemFlags::II_UserMark1)) {
1758 if (!iface->hasFlags(ItemFlags::II_Overlap)) {
1759 ARCANE_FATAL("_checkPatchesAndMesh -- II_UserMark1 but not II_Overlap -- FaceUID : {0}", iface->uniqueId());
1760 }
1761 }
1762 if (iface->hasFlags(ItemFlags::II_UserMark2)) {
1763 if (!iface->hasFlags(ItemFlags::II_InPatch)) {
1764 ARCANE_FATAL("_checkPatchesAndMesh -- II_UserMark2 but not II_InPatch -- FaceUID : {0}", iface->uniqueId());
1765 }
1766 }
1767 if (iface->hasFlags(ItemFlags::II_Overlap)) {
1768 if (!iface->hasFlags(ItemFlags::II_UserMark1)) {
1769 ARCANE_FATAL("_checkPatchesAndMesh -- II_Overlap but not II_UserMark1 -- FaceUID : {0}", iface->uniqueId());
1770 }
1771 }
1772 if (iface->hasFlags(ItemFlags::II_InPatch)) {
1773 if (!iface->hasFlags(ItemFlags::II_UserMark2)) {
1774 ARCANE_FATAL("_checkPatchesAndMesh -- II_InPatch but not II_UserMark2 -- FaceUID : {0}", iface->uniqueId());
1775 }
1776 }
1777
1778 iface->mutableItemBase().removeFlags(ItemFlags::II_UserMark1); // II_Overlap
1779 iface->mutableItemBase().removeFlags(ItemFlags::II_UserMark2); // II_InPatch
1780 }
1781 ENUMERATE_ (Node, inode, m_cmesh->mesh()->allNodes()) {
1782 if (inode->hasFlags(ItemFlags::II_UserMark1)) {
1783 if (!inode->hasFlags(ItemFlags::II_Overlap)) {
1784 ARCANE_FATAL("_checkPatchesAndMesh -- II_UserMark1 but not II_Overlap -- NodeUID : {0}", inode->uniqueId());
1785 }
1786 }
1787 if (inode->hasFlags(ItemFlags::II_UserMark2)) {
1788 if (!inode->hasFlags(ItemFlags::II_InPatch)) {
1789 ARCANE_FATAL("_checkPatchesAndMesh -- II_UserMark2 but not II_InPatch -- NodeUID : {0}", inode->uniqueId());
1790 }
1791 }
1792 if (inode->hasFlags(ItemFlags::II_Overlap)) {
1793 if (!inode->hasFlags(ItemFlags::II_UserMark1)) {
1794 ARCANE_FATAL("_checkPatchesAndMesh -- II_Overlap but not II_UserMark1 -- NodeUID : {0}", inode->uniqueId());
1795 }
1796 }
1797 if (inode->hasFlags(ItemFlags::II_InPatch)) {
1798 if (!inode->hasFlags(ItemFlags::II_UserMark2)) {
1799 ARCANE_FATAL("_checkPatchesAndMesh -- II_InPatch but not II_UserMark2 -- NodeUID : {0}", inode->uniqueId());
1800 }
1801 }
1802
1803 inode->mutableItemBase().removeFlags(ItemFlags::II_UserMark1); // II_Overlap
1804 inode->mutableItemBase().removeFlags(ItemFlags::II_UserMark2); // II_InPatch
1805 }
1806 }
1807}
1808
1809/*---------------------------------------------------------------------------*/
1810/*---------------------------------------------------------------------------*/
1811
1812void CartesianPatchGroup::
1813clearRefineRelatedFlags() const
1814{
1815 constexpr ItemFlags::FlagType flags_to_remove = (ItemFlags::II_Coarsen | ItemFlags::II_Refine |
1816 ItemFlags::II_JustCoarsened | ItemFlags::II_JustRefined |
1817 ItemFlags::II_JustAdded | ItemFlags::II_CoarsenInactive);
1818 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allCells()) {
1819 icell->mutableItemBase().removeFlags(flags_to_remove);
1820 }
1821}
1822
1823/*---------------------------------------------------------------------------*/
1824/*---------------------------------------------------------------------------*/
1825
1826void CartesianPatchGroup::
1827rebuildAvailableGroupIndex(ConstArrayView<Integer> available_group_index)
1828{
1829 m_available_group_index = available_group_index;
1830}
1831
1832/*---------------------------------------------------------------------------*/
1833/*---------------------------------------------------------------------------*/
1834
1835ConstArrayView<Int32> CartesianPatchGroup::
1836availableGroupIndex()
1837{
1838 return m_available_group_index;
1839}
1840
1841/*---------------------------------------------------------------------------*/
1842/*---------------------------------------------------------------------------*/
1843
1844void CartesianPatchGroup::
1845setOverlapLayerSizeTopLevel(Int32 size_of_overlap_layer_top_level)
1846{
1847 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
1848
1849 Int32 new_size_of_overlap_layer_top_level = 0;
1850 // The value -1 is a special value that allows disabling overlap cells.
1851 if (size_of_overlap_layer_top_level == -1)
1852 new_size_of_overlap_layer_top_level = -1;
1853 else
1854 // We ensure that the size provided by the user is a multiple of
1855 // pattern (2 today).
1856 new_size_of_overlap_layer_top_level = size_of_overlap_layer_top_level + (size_of_overlap_layer_top_level % numbering->pattern());
1857
1858 if (new_size_of_overlap_layer_top_level == m_size_of_overlap_layer_top_level) {
1859 return;
1860 }
1861
1862 // If there is a change in the size of the top level layer, there
1863 // will be a size change on other levels.
1864 for (Int32 level = 1; level <= m_higher_level; ++level) {
1865 Int32 old_overlap_size = AMRPatchPosition::computeOverlapLayerSize(level, m_higher_level, m_size_of_overlap_layer_top_level);
1866 Int32 new_overlap_size = AMRPatchPosition::computeOverlapLayerSize(level, m_higher_level, new_size_of_overlap_layer_top_level);
1867
1868 if (old_overlap_size == new_overlap_size) {
1869 continue;
1870 }
1871 if (old_overlap_size < new_overlap_size) {
1872 _increaseOverlapSizeLevel(level, new_overlap_size);
1873 }
1874 else {
1875 _reduceOverlapSizeLevel(level, new_overlap_size);
1876 }
1877 }
1878 m_size_of_overlap_layer_top_level = new_size_of_overlap_layer_top_level;
1879}
1880
1881/*---------------------------------------------------------------------------*/
1882/*---------------------------------------------------------------------------*/
1883
1884Int32 CartesianPatchGroup::
1885overlapLayerSize(Int32 level)
1886{
1887 if (level == 0) {
1888 return 0;
1889 }
1890 // Two cases:
1891 // - we are in a refinement phase (beginAdaptMesh()), so we must
1892 // consider that the highest level is m_target_nb_levels-1,
1893 // - otherwise, we take the current highest level.
1894 Int32 higher_level = m_higher_level;
1895 if (m_target_nb_levels != 0) {
1896 higher_level = m_target_nb_levels - 1;
1897 }
1898 return AMRPatchPosition::computeOverlapLayerSize(level, higher_level, m_size_of_overlap_layer_top_level);
1899}
1900
1901/*---------------------------------------------------------------------------*/
1902/*---------------------------------------------------------------------------*/
1903
1904void CartesianPatchGroup::
1905_addPatchInstance(Ref<CartesianMeshPatch> v)
1906{
1907 m_amr_patches.add(v);
1908 m_amr_patches_pointer.add(v.get());
1909}
1910
1911/*---------------------------------------------------------------------------*/
1912/*---------------------------------------------------------------------------*/
1913
1914void CartesianPatchGroup::
1915_removeOnePatch(Integer index)
1916{
1917 m_available_group_index.add(m_amr_patches[index]->index());
1918 // info() << "_removeOnePatch() -- Save group_index : " << m_available_group_index.back();
1919
1920 m_amr_patch_cell_groups_all[index].clear();
1921 m_amr_patch_cell_groups_all.remove(index);
1922
1923 if (m_cmesh->mesh()->meshKind().meshAMRKind() == eMeshAMRKind::PatchCartesianMeshOnly) {
1924 m_amr_patch_cell_groups_inpatch[index].clear();
1925 m_amr_patch_cell_groups_inpatch.remove(index);
1926 m_amr_patch_cell_groups_overlap[index].clear();
1927 m_amr_patch_cell_groups_overlap.remove(index);
1928 }
1929
1930 m_amr_patches_pointer.remove(index);
1931 m_amr_patches.remove(index);
1932}
1933
1934/*---------------------------------------------------------------------------*/
1935/*---------------------------------------------------------------------------*/
1936
1937// The array must be sorted.
1938void CartesianPatchGroup::
1939_removeMultiplePatches(ConstArrayView<Integer> indexes)
1940{
1941 Integer count = 0;
1942 for (const Integer index : indexes) {
1943 _removeOnePatch(index - count);
1944 count++;
1945 }
1946}
1947
1948/*---------------------------------------------------------------------------*/
1949/*---------------------------------------------------------------------------*/
1950
1951void CartesianPatchGroup::
1952_removeAllPatches()
1953{
1954 for (Integer i = 1; i < m_amr_patch_cell_groups_all.size(); ++i) {
1955 m_amr_patch_cell_groups_all[i].clear();
1956 }
1957 m_amr_patch_cell_groups_all.clear();
1958
1959 if (m_cmesh->mesh()->meshKind().meshAMRKind() == eMeshAMRKind::PatchCartesianMeshOnly) {
1960 for (Integer i = 0; i < m_amr_patch_cell_groups_inpatch.size(); ++i) {
1961 m_amr_patch_cell_groups_inpatch[i].clear();
1962 m_amr_patch_cell_groups_overlap[i].clear();
1963 }
1964 m_amr_patch_cell_groups_inpatch.clear();
1965 m_amr_patch_cell_groups_overlap.clear();
1966 }
1967
1968 m_amr_patches_pointer.clear();
1969 m_amr_patches.clear();
1970 m_available_group_index.clear();
1971 m_patches_to_delete.clear();
1972 m_index_new_patches = 1;
1973
1974 m_higher_level = 0;
1975}
1976
1977/*---------------------------------------------------------------------------*/
1978/*---------------------------------------------------------------------------*/
1979
1980void CartesianPatchGroup::
1981_createGroundPatch()
1982{
1983 if (!m_amr_patches.empty())
1984 return;
1985 auto patch = makeRef(new CartesianMeshPatch(m_cmesh, -1));
1986
1987 if (m_cmesh->mesh()->meshKind().meshAMRKind() == eMeshAMRKind::PatchCartesianMeshOnly) {
1988 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
1989 patch->_internalApi()->positionRef().setMinPoint({ 0, 0, 0 });
1990 patch->_internalApi()->positionRef().setMaxPoint({ numbering->globalNbCellsX(0), numbering->globalNbCellsY(0), numbering->globalNbCellsZ(0) });
1991 patch->_internalApi()->positionRef().setLevel(0);
1992 }
1993
1994 _addPatchInstance(patch);
1995 _addCellGroup(m_cmesh->mesh()->allLevelCells(0), patch.get(), true);
1996}
1997
1998/*---------------------------------------------------------------------------*/
1999/*---------------------------------------------------------------------------*/
2000
2001Integer CartesianPatchGroup::
2002_addCellGroup(CellGroup cell_group, CartesianMeshPatch* patch, bool add_flags)
2003{
2004 m_amr_patch_cell_groups_all.add(cell_group);
2005
2006 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
2007 // Irregular patch.
2008 // m_amr_patch_cell_groups_inpatch.add(cell_group);
2009 // m_amr_patch_cell_groups_overlap.add(CellGroup());
2010 return m_amr_patch_cell_groups_all.size() - 1;
2011 }
2012
2013 AMRPatchPosition patch_position = patch->position();
2014 Ref<ICartesianMeshNumberingMngInternal> numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
2015
2016 UniqueArray<Int32> inpatch_items_lid;
2017 UniqueArray<Int32> overlap_items_lid;
2018
2019 ENUMERATE_ (Cell, icell, cell_group) {
2020 Cell cell = *icell;
2021 const CartCoord3 pos = numbering->cellUniqueIdToCoord(cell);
2022
2023 if (patch_position.isIn(pos)) {
2024 inpatch_items_lid.add(cell.localId());
2025 }
2026 else {
2027 overlap_items_lid.add(cell.localId());
2028 }
2029 }
2030
2031 CellGroup own = m_cmesh->mesh()->cellFamily()->createGroup(cell_group.name().clone() + "_InPatch", inpatch_items_lid, true);
2032 m_amr_patch_cell_groups_inpatch.add(own);
2033
2034 CellGroup overlap = m_cmesh->mesh()->cellFamily()->createGroup(cell_group.name().clone() + "_Overlap", overlap_items_lid, true);
2035 m_amr_patch_cell_groups_overlap.add(overlap);
2036
2037 if (add_flags) {
2038 // If an entity is in a patch, it gets the II_InPatch flag.
2039 // If an entity is an overlap entity for a patch, it gets the II_Overlap flag.
2040 // As its name suggests, an overlap entity can overlap another patch. Therefore, an entity can be both II_InPatch and II_Overlap.
2041 ENUMERATE_ (Cell, icell, own) {
2042 icell->mutableItemBase().addFlags(ItemFlags::II_InPatch);
2043 }
2044 ENUMERATE_ (Face, iface, own.faceGroup()) {
2045 iface->mutableItemBase().addFlags(ItemFlags::II_InPatch);
2046 }
2047 ENUMERATE_ (Node, inode, own.nodeGroup()) {
2048 inode->mutableItemBase().addFlags(ItemFlags::II_InPatch);
2049 }
2050
2051 ENUMERATE_ (Cell, icell, overlap) {
2052 icell->mutableItemBase().addFlags(ItemFlags::II_Overlap);
2053 }
2054 ENUMERATE_ (Face, iface, overlap.faceGroup()) {
2055 iface->mutableItemBase().addFlags(ItemFlags::II_Overlap);
2056 }
2057 ENUMERATE_ (Node, inode, overlap.nodeGroup()) {
2058 inode->mutableItemBase().addFlags(ItemFlags::II_Overlap);
2059 }
2060 }
2061
2062 return m_amr_patch_cell_groups_all.size() - 1;
2063}
2064
2065/*---------------------------------------------------------------------------*/
2066/*---------------------------------------------------------------------------*/
2067
2068void CartesianPatchGroup::
2069_updateCellGroups(Integer index, bool update_flags)
2070{
2071 if (m_cmesh->mesh()->meshKind().meshAMRKind() != eMeshAMRKind::PatchCartesianMeshOnly) {
2072 ARCANE_FATAL("Method available only with AMR PatchCartesianMeshOnly");
2073 }
2074
2075 CellGroup patch_all_cells = allCells(index);
2076 CellGroup patch_inpatch = inPatchCells(index);
2077 CellGroup patch_overlap = overlapCells(index);
2078
2079 patch_all_cells.clear();
2080 patch_inpatch.clear();
2081 patch_overlap.clear();
2082
2083 const auto& position = patch(index)->_internalApi()->positionRef();
2084
2085 Int32 level = position.level();
2086
2087 UniqueArray<Int32> inpatch_items_lid;
2088 UniqueArray<Int32> overlap_items_lid;
2089
2090 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
2091
2092 // We add the flags to the patch cells.
2093 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(level)) {
2094 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
2095
2096 if (position.isIn(pos)) {
2097 inpatch_items_lid.add(icell.localId());
2098 }
2099 else if (position.isInWithOverlap(pos)) {
2100 overlap_items_lid.add(icell.localId());
2101 }
2102 }
2103
2104 patch_all_cells.addItems(inpatch_items_lid, false);
2105 patch_all_cells.addItems(overlap_items_lid, false);
2106
2107 patch_inpatch.addItems(inpatch_items_lid, false);
2108 patch_overlap.addItems(overlap_items_lid, false);
2109
2110 if (update_flags) {
2111 ENUMERATE_ (Cell, icell, patch_inpatch) {
2112 icell->mutableItemBase().addFlags(ItemFlags::II_InPatch);
2113 }
2114 ENUMERATE_ (Face, iface, patch_inpatch.faceGroup()) {
2115 iface->mutableItemBase().addFlags(ItemFlags::II_InPatch);
2116 }
2117 ENUMERATE_ (Node, inode, patch_inpatch.nodeGroup()) {
2118 inode->mutableItemBase().addFlags(ItemFlags::II_InPatch);
2119 }
2120
2121 ENUMERATE_ (Cell, icell, patch_overlap) {
2122 icell->mutableItemBase().addFlags(ItemFlags::II_Overlap);
2123 }
2124 ENUMERATE_ (Face, iface, patch_overlap.faceGroup()) {
2125 iface->mutableItemBase().addFlags(ItemFlags::II_Overlap);
2126 }
2127 ENUMERATE_ (Node, inode, patch_overlap.nodeGroup()) {
2128 inode->mutableItemBase().addFlags(ItemFlags::II_Overlap);
2129 }
2130 }
2131}
2132
2133/*---------------------------------------------------------------------------*/
2134/*---------------------------------------------------------------------------*/
2135
2136/*---------------------------------------------------------------------------*/
2137/*---------------------------------------------------------------------------*/
2138
2139// It is necessary that the source patch and the part_to_remove patch are in contact for this method to work.
2140void CartesianPatchGroup::
2141_removePartOfPatch(Integer index_patch_to_edit, const AMRPatchPosition& part_to_remove)
2142{
2143 // info() << "Coarse Zone"
2144 // << " -- Min point : " << part_to_remove.minPoint()
2145 // << " -- Max point : " << part_to_remove.maxPoint()
2146 // << " -- Level : " << part_to_remove.level();
2147
2148 // p1 is the patch part that must be removed from p0.
2149 // We therefore only have four cases to handle (knowing that p0 and p1 must be in contact in x and/or y and/or z).
2150 //
2151 // Case 1:
2152 // p0 |-----|
2153 // p1 |---------|
2154 // r = {-1, -1}
2155 //
2156 // Case 2:
2157 // p0 |-----|
2158 // p1 |-----|
2159 // r = {p1_min, -1}
2160 //
2161 // Case 3:
2162 // p0 |-----|
2163 // p1 |-----|
2164 // r = {-1, p1_max}
2165 //
2166 // Case 4:
2167 // p0 |-----|
2168 // p1 |---|
2169 // r = {p1_min, p1_max}
2170 auto cut_points_p0 = [](CartCoord p0_min, CartCoord p0_max, CartCoord p1_min, CartCoord p1_max) -> std::pair<CartCoord, CartCoord> {
2171 std::pair to_return{ -1, -1 };
2172 if (p1_min > p0_min && p1_min < p0_max) {
2173 to_return.first = p1_min;
2174 }
2175 if (p1_max > p0_min && p1_max < p0_max) {
2176 to_return.second = p1_max;
2177 }
2178 return to_return;
2179 };
2180
2181 ICartesianMeshPatch* patch = m_amr_patches_pointer[index_patch_to_edit];
2182 AMRPatchPosition patch_position = patch->position();
2183
2184 UniqueArray<AMRPatchPosition> new_patch_out;
2185
2186 CartCoord3 min_point_of_patch_to_exclude(-1, -1, -1);
2187
2188 // Patch cutting around the area to exclude.
2189 {
2190 UniqueArray<AMRPatchPosition> new_patch_in;
2191
2192 // We cut the patch in x.
2193 {
2194 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);
2195
2196 // p0 |-----|
2197 // p1 |---------|
2198 if (cut_point_x.first == -1 && cut_point_x.second == -1) {
2199 min_point_of_patch_to_exclude.x = patch_position.minPoint().x;
2200 new_patch_out.add(patch_position);
2201 }
2202 // p0 |-----|
2203 // p1 |-----|
2204 else if (cut_point_x.second == -1) {
2205 min_point_of_patch_to_exclude.x = cut_point_x.first;
2206 auto [fst, snd] = patch_position.cut(cut_point_x.first, MD_DirX);
2207 new_patch_out.add(fst);
2208 new_patch_out.add(snd);
2209 }
2210 // p0 |-----|
2211 // p1 |-----|
2212 else if (cut_point_x.first == -1) {
2213 min_point_of_patch_to_exclude.x = patch_position.minPoint().x;
2214 auto [fst, snd] = patch_position.cut(cut_point_x.second, MD_DirX);
2215 new_patch_out.add(fst);
2216 new_patch_out.add(snd);
2217 }
2218 // p0 |-----|
2219 // p1 |---|
2220 else {
2221 min_point_of_patch_to_exclude.x = cut_point_x.first;
2222 auto [fst, snd_thr] = patch_position.cut(cut_point_x.first, MD_DirX);
2223 new_patch_out.add(fst);
2224 auto [snd, thr] = snd_thr.cut(cut_point_x.second, MD_DirX);
2225 new_patch_out.add(snd);
2226 new_patch_out.add(thr);
2227 }
2228 }
2229
2230 // We cut the patch in y.
2231 {
2232 std::swap(new_patch_out, new_patch_in);
2233
2234 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);
2235
2236 // p0 |-----|
2237 // p1 |---------|
2238 if (cut_point_y.first == -1 && cut_point_y.second == -1) {
2239 for (const AMRPatchPosition& patch_x : new_patch_in) {
2240 min_point_of_patch_to_exclude.y = patch_x.minPoint().y;
2241 new_patch_out.add(patch_x);
2242 }
2243 }
2244 // p0 |-----|
2245 // p1 |-----|
2246 else if (cut_point_y.second == -1) {
2247 min_point_of_patch_to_exclude.y = cut_point_y.first;
2248 for (const AMRPatchPosition& patch_x : new_patch_in) {
2249 auto [fst, snd] = patch_x.cut(cut_point_y.first, MD_DirY);
2250 new_patch_out.add(fst);
2251 new_patch_out.add(snd);
2252 }
2253 }
2254 // p0 |-----|
2255 // p1 |-----|
2256 else if (cut_point_y.first == -1) {
2257 for (const AMRPatchPosition& patch_x : new_patch_in) {
2258 min_point_of_patch_to_exclude.y = patch_x.minPoint().y;
2259 auto [fst, snd] = patch_x.cut(cut_point_y.second, MD_DirY);
2260 new_patch_out.add(fst);
2261 new_patch_out.add(snd);
2262 }
2263 }
2264 // p0 |-----|
2265 // p1 |---|
2266 else {
2267 min_point_of_patch_to_exclude.y = cut_point_y.first;
2268 for (const AMRPatchPosition& patch_x : new_patch_in) {
2269 auto [fst, snd_thr] = patch_x.cut(cut_point_y.first, MD_DirY);
2270 new_patch_out.add(fst);
2271 auto [snd, thr] = snd_thr.cut(cut_point_y.second, MD_DirY);
2272 new_patch_out.add(snd);
2273 new_patch_out.add(thr);
2274 }
2275 }
2276 }
2277
2278 // We cut the patch in z.
2279 if (m_cmesh->mesh()->dimension() == 3) {
2280 std::swap(new_patch_out, new_patch_in);
2281 new_patch_out.clear();
2282
2283 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);
2284
2285 // p0 |-----|
2286 // p1 |---------|
2287 if (cut_point_z.first == -1 && cut_point_z.second == -1) {
2288 for (const AMRPatchPosition& patch_y : new_patch_in) {
2289 min_point_of_patch_to_exclude.z = patch_y.minPoint().z;
2290 new_patch_out.add(patch_y);
2291 }
2292 }
2293 // p0 |-----|
2294 // p1 |-----|
2295 else if (cut_point_z.second == -1) {
2296 for (const AMRPatchPosition& patch_y : new_patch_in) {
2297 min_point_of_patch_to_exclude.z = cut_point_z.first;
2298 auto [fst, snd] = patch_y.cut(cut_point_z.first, MD_DirZ);
2299 new_patch_out.add(fst);
2300 new_patch_out.add(snd);
2301 }
2302 }
2303 // p0 |-----|
2304 // p1 |-----|
2305 else if (cut_point_z.first == -1) {
2306 for (const AMRPatchPosition& patch_y : new_patch_in) {
2307 min_point_of_patch_to_exclude.z = patch_y.minPoint().z;
2308 auto [fst, snd] = patch_y.cut(cut_point_z.second, MD_DirZ);
2309 new_patch_out.add(fst);
2310 new_patch_out.add(snd);
2311 }
2312 }
2313 // p0 |-----|
2314 // p1 |---|
2315 else {
2316 for (const AMRPatchPosition& patch_y : new_patch_in) {
2317 min_point_of_patch_to_exclude.z = cut_point_z.first;
2318 auto [fst, snd_thr] = patch_y.cut(cut_point_z.first, MD_DirZ);
2319 new_patch_out.add(fst);
2320 auto [snd, thr] = snd_thr.cut(cut_point_z.second, MD_DirZ);
2321 new_patch_out.add(snd);
2322 new_patch_out.add(thr);
2323 }
2324 }
2325 }
2326 }
2327
2328 // Fusion and addition part.
2329 {
2330 if (m_cmesh->mesh()->dimension() == 2) {
2331 min_point_of_patch_to_exclude.z = 0;
2332 }
2333 // info() << "Nb of new patch before fusion : " << new_patch_out.size();
2334 // info() << "min_point_of_patch_to_exclude : " << min_point_of_patch_to_exclude;
2335
2336 // We set to null the patch representing the patch part to be removed.
2337 for (AMRPatchPosition& new_patch : new_patch_out) {
2338 if (new_patch.minPoint() == min_point_of_patch_to_exclude) {
2339 new_patch.setLevel(-2); // Devient null.
2340 }
2341 // else {
2342 // info() << "\tPatch before fusion"
2343 // << " -- Min point : " << new_patch.minPoint()
2344 // << " -- Max point : " << new_patch.maxPoint()
2345 // << " -- Level : " << new_patch.level();
2346 // }
2347 }
2348
2349 AMRPatchPositionLevelGroup::fusionPatches(new_patch_out, false);
2350
2351 // We add the new patches to the list of patches.
2352 // Integer d_nb_patch_final = 0;
2353 for (const auto& new_patch : new_patch_out) {
2354 if (!new_patch.isNull()) {
2355 // info() << "\tNew cut patch"
2356 // << " -- Min point : " << new_patch.minPoint()
2357 // << " -- Max point : " << new_patch.maxPoint()
2358 // << " -- Level : " << new_patch.level();
2359 _addCutPatch(new_patch, allCells(index_patch_to_edit));
2360 // d_nb_patch_final++;
2361 }
2362 }
2363 // info() << "Nb of new patch after fusion : " << d_nb_patch_final;
2364 }
2365
2366 removePatch(index_patch_to_edit);
2367}
2368
2369/*---------------------------------------------------------------------------*/
2370/*---------------------------------------------------------------------------*/
2371
2372void CartesianPatchGroup::
2373_addCutPatch(const AMRPatchPosition& new_patch_position, CellGroup parent_patch_cell_group)
2374{
2375 // If this method is used by another method than _removePartOfPatch(),
2376 // check if m_higher_level update is necessary.
2377 // (up until now, this is not useful since there will be a call to applyPatchEdit()).
2378 if (parent_patch_cell_group.null())
2379 ARCANE_FATAL("Null cell group");
2380
2381 IItemFamily* cell_family = m_cmesh->mesh()->cellFamily();
2382 Integer group_index = _nextIndexForNewPatch();
2383 String patch_group_name = String("CartesianMeshPatchCells") + group_index;
2384
2385 auto* cdi = new CartesianMeshPatch(m_cmesh, group_index, new_patch_position);
2386 _addPatchInstance(makeRef(cdi));
2387
2388 UniqueArray<Int32> cells_local_id;
2389
2390 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
2391 ENUMERATE_ (Cell, icell, parent_patch_cell_group) {
2392 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
2393 if (new_patch_position.isIn(pos)) {
2394 cells_local_id.add(icell.localId());
2395 }
2396 }
2397
2398 CellGroup parent_cells = cell_family->createGroup(patch_group_name, cells_local_id, true);
2399 // False car les flags sont mis à jour après.
2400 _addCellGroup(parent_cells, cdi, false);
2401
2402 // info() << "_addCutPatch()"
2403 // << " -- m_amr_patch_cell_groups : " << m_amr_patch_cell_groups_all.size()
2404 // << " -- m_amr_patches : " << m_amr_patches.size()
2405 // << " -- group_index : " << group_index
2406 // << " -- cell_group name : " << m_amr_patch_cell_groups_all.back().name();
2407}
2408
2409/*---------------------------------------------------------------------------*/
2410/*---------------------------------------------------------------------------*/
2411
2412Integer CartesianPatchGroup::
2413_addPatch(const AMRPatchPosition& new_patch_position)
2414{
2415 UniqueArray<Int32> cells_local_id;
2416
2417 auto numbering = m_cmesh->_internalApi()->cartesianMeshNumberingMngInternal();
2418
2419 // We add the flags to the patch cells.
2420 ENUMERATE_ (Cell, icell, m_cmesh->mesh()->allLevelCells(new_patch_position.level())) {
2421 const CartCoord3 pos = numbering->cellUniqueIdToCoord(*icell);
2422
2423 if (new_patch_position.isInWithOverlap(pos)) {
2424 cells_local_id.add(icell.localId());
2425 }
2426 }
2427
2428 IItemFamily* cell_family = m_cmesh->mesh()->cellFamily();
2429 Integer group_index = _nextIndexForNewPatch();
2430 String patch_group_name = String("CartesianMeshPatchCells") + group_index;
2431
2432 auto* cdi = new CartesianMeshPatch(m_cmesh, group_index, new_patch_position);
2433
2434 _addPatchInstance(makeRef(cdi));
2435 CellGroup parent_cells = cell_family->createGroup(patch_group_name, cells_local_id, true);
2436 Integer array_index = _addCellGroup(parent_cells, cdi, true);
2437
2438 // TODO: These two indices are really not a good idea...
2439 return array_index;
2440}
2441
2442/*---------------------------------------------------------------------------*/
2443/*---------------------------------------------------------------------------*/
2444
2445} // End namespace Arcane
2446
2447/*---------------------------------------------------------------------------*/
2448/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
#define ENUMERATE_(type, name, group)
Generic enumerator for an entity group.
Class allowing the definition of a patch position in the Cartesian mesh.
AMRPatchPosition patchUp(Integer dim, Int32 higher_level, Int32 overlap_layer_size_top_level) const
Method to create an AMRPatchPosition for the higher level.
bool isInWithOverlap(CartCoord x, CartCoord y, CartCoord z) const
Method to know if a cell at position x,y,z is included in this patch with overlap layer.
static Int32 computeOverlapLayerSize(Int32 level, Int32 higher_level, Int32 overlap_layer_size_top_level)
Method to calculate the number of overlap cell layers for a given level.
CartCoord3 minPoint() const
Method to retrieve the min position of the enclosing box.
void setMinPoint(CartCoord3 min_point)
Method to set the min position of the enclosing box.
void setLevel(Int32 level)
Method to set the patch level.
CartCoord3 maxPoint() const
Method to retrieve the max position of the enclosing box.
bool haveIntersection(const AMRPatchPosition &other) const
Method to know if our patch is in contact with other.
Int32 overlapLayerSize() const
Method to retrieve the number of overlap cell layers of the patch.
void setOverlapLayerSize(Int32 layer_size)
Method to set the number of overlap cell layers of the patch.
Int32 level() const
Method to retrieve the patch level.
void setMaxPoint(CartCoord3 max_point)
Method to set the max position of the enclosing box.
Class allowing the definition of a mesh zone.
void cellsInPatch(IMesh *mesh, UniqueArray< Int32 > &cells_local_id) const
Method allowing retrieval of the cells included in the zone.
Real3 length() const
Method allowing retrieval of the zone's size.
Real3 position() const
Method allowing retrieval of the zone's position.
AMRPatchPosition toAMRPatchPosition(ICartesianMesh *mesh) const
Method allowing conversion of this AMRZonePosition into AMRPatchPosition.
Integer size() const
Number of elements in the vector.
CellGroup allCells(Integer index)
Method to retrieve the group of all cells in the requested patch.
void applyPatchEdit(bool remove_empty_patches, bool update_higher_level)
Method to delete patches pending deletion.
Cell of a mesh.
Definition Item.h:1300
Constant view of an array of type T.
Interface of an AMR patch of a Cartesian mesh.
Interface of an entity family.
Definition IItemFamily.h:83
virtual ItemGroup createGroup(const String &name, Int32ConstArrayView local_ids, bool do_override=false)=0
Creates an entity group named name containing the entities local_ids.
virtual IMesh * mesh() const =0
Associated mesh.
virtual IItemFamily * cellFamily()=0
Returns the cell family.
@ II_Refine
The entity is marked for refinement.
Definition ItemFlags.h:77
const String & name() const
Group name.
Definition ItemGroup.h:81
Integer size() const
Number of elements in the group.
Definition ItemGroup.h:93
IMesh * mesh() const
Mesh to which this group belongs (0 for the null group).
Definition ItemGroup.h:131
Reference to an instance.
bool startsWith(const String &s) const
Indicates if the string starts with the characters of s.
Definition String.cc:1111
const char * localstr() const
Returns the conversion of the instance into UTF-8 encoding.
Definition String.cc:229
String substring(Int64 pos) const
Substring starting at position pos.
Definition String.cc:1126
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flow for a debug message.
TraceMessage info() const
Flow for an information message.
ITraceMng * traceMng() const
Trace manager.
1D data vector with value semantics (STL style).
__host__ __device__ Real2 min(Real2 a, Real2 b)
Returns the minimum of two Real2.
Definition MathUtils.h:346
T max(const T &a, const T &b, const T &c)
Returns the maximum of three elements.
Definition MathUtils.h:407
ItemGroupT< Cell > CellGroup
Group of cells.
Definition ItemTypes.h:184
@ ReduceMax
Maximum of values.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Int32 CartCoord
Represents a coordinate of an element in the Cartesian grid (in X or Y or Z).
Int32 Integer
Type representing an integer.
@ MD_DirZ
Z Direction.
@ MD_DirY
Y Direction.
@ MD_DirX
X Direction.
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Creates a reference on a pointer.
@ Cell
The mesh is AMR by cell.
Definition MeshKind.h:53
@ PatchCartesianMeshOnly
The mesh is AMR by Cartesian patch (rectangular).
Definition MeshKind.h:57
std::int32_t Int32
Signed integer type of 32 bits.
Int32x3 CartCoord3
Represents the 3D coordinates of an element in the Cartesian grid {x, y, z}.