Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
AMRPatchPositionSignatureCut.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/* AMRPatchPositionSignatureCut.cc (C) 2000-2026 */
9/* */
10/* Patch cutting methods based on their signatures. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/cartesianmesh/internal/AMRPatchPositionSignatureCut.h"
15
16#include "arcane/utils/FatalErrorException.h"
17#include "arcane/utils/Math.h"
18
19#include "arcane/core/IMesh.h"
20
21#include "arcane/cartesianmesh/ICartesianMesh.h"
22
23#include "arcane/cartesianmesh/internal/AMRPatchPositionSignature.h"
24
25/*---------------------------------------------------------------------------*/
26/*---------------------------------------------------------------------------*/
27
28namespace Arcane
29{
30
31namespace
32{
33 constexpr Integer MIN_SIZE = 1;
34} // namespace
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38
39AMRPatchPositionSignatureCut::
40AMRPatchPositionSignatureCut() = default;
41
42/*---------------------------------------------------------------------------*/
43/*---------------------------------------------------------------------------*/
44
45AMRPatchPositionSignatureCut::
46~AMRPatchPositionSignatureCut() = default;
47
48/*---------------------------------------------------------------------------*/
49/*---------------------------------------------------------------------------*/
50
53{
54 // If the cut produces patches that are too small, we return -1.
55 if (sig.size() < MIN_SIZE * 2) {
56 return -1;
57 }
58
59 CartCoord cut_point = -1;
60 CartCoord mid = sig.size() / 2;
61
62 // Hole part.
63 // We search for a hole in the signature.
64 // The signature must have been compressed beforehand
65 // (AMRPatchPositionSignature::compress()).
66 {
67 for (CartCoord i = 0; i < sig.size(); ++i) {
68 if (sig[i] == 0) {
69 cut_point = i;
70 break;
71 }
72 }
73
74 if (cut_point == 0) {
75 ARCANE_FATAL("Call AMRPatchPositionSignature::compress() before");
76 }
77 if (cut_point != -1 && cut_point >= MIN_SIZE && sig.size() - cut_point >= MIN_SIZE) {
78 return cut_point;
79 }
80 }
81
82#if 0
83 // Second derivative part.
84 // Does not necessarily produce better results compared to the middle cut part.
85 {
86 UniqueArray<CartCoord> dsec_sig(sig.size(), 0);
87
88 CartCoord max = -1;
89 for (CartCoord i = 1; i < dsec_sig.size() - 1; ++i) {
90 dsec_sig[i] = sig[i + 1] - 2 * sig[i] + sig[i - 1];
91 CartCoord dif = math::abs(dsec_sig[i - 1] - dsec_sig[i]);
92 if (dif > max) {
93 cut_point = i;
94 max = dif;
95 }
96 else if (dif == max && math::abs(cut_point - mid) > math::abs(i - mid)) {
97 cut_point = i;
98 }
99 }
100
101 if (cut_point != -1 && cut_point >= MIN_SIZE && sig.size() - cut_point >= MIN_SIZE) {
102 return cut_point;
103 }
104 }
105#endif
106
107 // Middle cut part.
108 {
109 cut_point = mid;
110
111 if (cut_point != -1 && cut_point >= MIN_SIZE && sig.size() - cut_point >= MIN_SIZE) {
112 return cut_point;
113 }
114 }
115
116 return -1;
117}
118
119/*---------------------------------------------------------------------------*/
120/*---------------------------------------------------------------------------*/
121
122std::pair<AMRPatchPositionSignature, AMRPatchPositionSignature> AMRPatchPositionSignatureCut::
124{
125 // We cut along the three dimensions.
126 CartCoord cut_point_x = _cutDim(sig.sigX());
127 CartCoord cut_point_y = _cutDim(sig.sigY());
128 CartCoord cut_point_z = (sig.mesh()->mesh()->dimension() == 2 ? -1 : _cutDim(sig.sigZ()));
129
130 // If it is impossible to cut along one of the dimensions.
131 if (cut_point_x == -1 && cut_point_y == -1 && cut_point_z == -1) {
132 return {};
133 }
134
135 // We adjust the cut points to pass them to the AMRPatchPositionSignature::cut() method.
136 if (cut_point_x != -1) {
137 cut_point_x += sig.patch().minPoint().x;
138 }
139 if (cut_point_y != -1) {
140 cut_point_y += sig.patch().minPoint().y;
141 }
142 if (cut_point_z != -1) {
143 cut_point_z += sig.patch().minPoint().z;
144 }
145
146 // We must choose the best cut point among the three.
147 if (cut_point_x != -1 && cut_point_y != -1 && cut_point_z != -1) {
148
149 // To choose, we cut, calculate the efficiency of the resulting
150 // patches, and choose the most efficient cut.
151 // TODO: Since the compute() methods are collective methods performing
152 // several small reductions, this part should be optimized by combining
153 // the reductions.
154 Real x_efficacity = 0;
155 auto [fst_x, snd_x] = sig.cut(MD_DirX, cut_point_x);
156 {
157 // sig.mesh()->traceMng()->info() << "Cut() -- Compute X -- Cut Point : " << cut_point_x;
158
159 fst_x.compute();
160 snd_x.compute();
161 if (fst_x.isValid() && snd_x.isValid()) {
162
163 // sig.mesh()->traceMng()->info() << "Cut() -- X.fst_x"
164 // << " -- min = " << fst_x.patch().minPoint()
165 // << " -- max = " << fst_x.patch().maxPoint()
166 // << " -- efficacity : " << fst_x.efficacity();
167 // sig.mesh()->traceMng()->info() << "Cut() -- X.snd_x"
168 // << " -- min = " << snd_x.patch().minPoint()
169 // << " -- max = " << snd_x.patch().maxPoint()
170 // << " -- efficacity : " << snd_x.efficacity();
171
172 x_efficacity = (fst_x.efficacity() + snd_x.efficacity()) / 2;
173 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity X : " << x_efficacity;
174 }
175 // else {
176 // sig.mesh()->traceMng()->info() << "Cut() -- Compute X invalid (too small) -- fst_x.length() : " << fst_x.patch().length() << " -- snd_x.length() : " << snd_x.patch().length();
177 // }
178 }
179
180 Real y_efficacity = 0;
181 auto [fst_y, snd_y] = sig.cut(MD_DirY, cut_point_y);
182 {
183 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Y -- Cut Point : " << cut_point_y;
184
185 fst_y.compute();
186 snd_y.compute();
187 if (fst_y.isValid() && snd_y.isValid()) {
188
189 // sig.mesh()->traceMng()->info() << "Cut() -- Y.fst_y"
190 // << " -- min = " << fst_y.patch().minPoint()
191 // << " -- max = " << fst_y.patch().maxPoint()
192 // << " -- efficacity : " << fst_y.efficacity();
193 // sig.mesh()->traceMng()->info() << "Cut() -- Y.snd_y"
194 // << " -- min = " << snd_y.patch().minPoint()
195 // << " -- max = " << snd_y.patch().maxPoint()
196 // << " -- efficacity : " << snd_y.efficacity();
197
198 y_efficacity = (fst_y.efficacity() + snd_y.efficacity()) / 2;
199 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity Y : " << y_efficacity;
200 }
201 // else {
202 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Y invalid (too small) -- fst_y.length() : " << fst_y.patch().length() << " -- snd_y.length() : " << snd_y.patch().length();
203 // }
204 }
205
206 Real z_efficacity = 0;
207 auto [fst_z, snd_z] = sig.cut(MD_DirZ, cut_point_z);
208 {
209 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Z -- Cut Point : " << cut_point_z;
210
211 fst_z.compute();
212 snd_z.compute();
213 if (fst_z.isValid() && snd_z.isValid()) {
214
215 // sig.mesh()->traceMng()->info() << "Cut() -- Z.fst_z"
216 // << " -- min = " << fst_z.patch().minPoint()
217 // << " -- max = " << fst_z.patch().maxPoint()
218 // << " -- efficacity : " << fst_z.efficacity();
219 // sig.mesh()->traceMng()->info() << "Cut() -- Z.snd_z"
220 // << " -- min = " << snd_z.patch().minPoint()
221 // << " -- max = " << snd_z.patch().maxPoint()
222 // << " -- efficacity : " << snd_z.efficacity();
223
224 z_efficacity = (fst_z.efficacity() + snd_z.efficacity()) / 2;
225 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity Z : " << z_efficacity;
226 }
227 // else {
228 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Z invalid (too small) -- fst_z.length() : " << fst_z.patch().length() << " -- snd_z.length() : " << snd_z.patch().length();
229 // }
230 }
231
232 // If the cut does not improve the efficiency, we return.
233 {
234 Real sig_efficacity = sig.efficacity();
235 if (sig_efficacity > x_efficacity && sig_efficacity > y_efficacity && sig_efficacity > z_efficacity) {
236 return {};
237 }
238 }
239
240 // We return the best efficiency.
241 if (x_efficacity >= y_efficacity && x_efficacity >= z_efficacity && x_efficacity != 0) {
242 return { fst_x, snd_x };
243 }
244 if (y_efficacity >= x_efficacity && y_efficacity >= z_efficacity && y_efficacity != 0) {
245 return { fst_y, snd_y };
246 }
247 if (z_efficacity == 0) {
248 ARCANE_FATAL("Invalid cut");
249 }
250 return { fst_z, snd_z };
251 }
252
253 // Same principle as above.
254 if (cut_point_x != -1 && cut_point_y != -1) {
255 Real x_efficacity = 0;
256 auto [fst_x, snd_x] = sig.cut(MD_DirX, cut_point_x);
257 {
258 // sig.mesh()->traceMng()->info() << "Cut() -- Compute X -- Cut Point : " << cut_point_x;
259
260 fst_x.compute();
261 snd_x.compute();
262 if (fst_x.isValid() && snd_x.isValid()) {
263
264 // sig.mesh()->traceMng()->info() << "Cut() -- X.fst_x"
265 // << " -- min = " << fst_x.patch().minPoint()
266 // << " -- max = " << fst_x.patch().maxPoint()
267 // << " -- efficacity : " << fst_x.efficacity();
268 // sig.mesh()->traceMng()->info() << "Cut() -- X.snd_x"
269 // << " -- min = " << snd_x.patch().minPoint()
270 // << " -- max = " << snd_x.patch().maxPoint()
271 // << " -- efficacity : " << snd_x.efficacity();
272
273 x_efficacity = (fst_x.efficacity() + snd_x.efficacity()) / 2;
274 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity X : " << x_efficacity;
275 }
276 // else {
277 // sig.mesh()->traceMng()->info() << "Cut() -- Compute X invalid (too small) -- fst_x.length() : " << fst_x.patch().length() << " -- snd_x.length() : " << snd_x.patch().length();
278 // }
279 }
280
281 Real y_efficacity = 0;
282 auto [fst_y, snd_y] = sig.cut(MD_DirY, cut_point_y);
283 {
284 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Y -- Cut Point : " << cut_point_y;
285
286 fst_y.compute();
287 snd_y.compute();
288 if (fst_y.isValid() && snd_y.isValid()) {
289
290 // sig.mesh()->traceMng()->info() << "Cut() -- Y.fst_y"
291 // << " -- min = " << fst_y.patch().minPoint()
292 // << " -- max = " << fst_y.patch().maxPoint()
293 // << " -- efficacity : " << fst_y.efficacity();
294 // sig.mesh()->traceMng()->info() << "Cut() -- Y.snd_y"
295 // << " -- min = " << snd_y.patch().minPoint()
296 // << " -- max = " << snd_y.patch().maxPoint()
297 // << " -- efficacity : " << snd_y.efficacity();
298
299 y_efficacity = (fst_y.efficacity() + snd_y.efficacity()) / 2;
300 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity Y : " << y_efficacity;
301 }
302 // else {
303 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Y invalid (too small) -- fst_y.length() : " << fst_y.patch().length() << " -- snd_y.length() : " << snd_y.patch().length();
304 // }
305 }
306 {
307 Real sig_efficacity = sig.efficacity();
308 if (sig_efficacity > x_efficacity && sig_efficacity > y_efficacity) {
309 return {};
310 }
311 }
312
313 if (x_efficacity >= y_efficacity && x_efficacity != 0) {
314 return { fst_x, snd_x };
315 }
316 if (y_efficacity == 0) {
317 ARCANE_FATAL("Invalid cut");
318 }
319 return { fst_y, snd_y };
320 }
321
322 if (cut_point_x != -1) {
323 Real x_efficacity = 0;
324 auto [fst_x, snd_x] = sig.cut(MD_DirX, cut_point_x);
325
326 // sig.mesh()->traceMng()->info() << "Cut() -- Compute X -- Cut Point : " << cut_point_x;
327
328 fst_x.compute();
329 snd_x.compute();
330 if (fst_x.isValid() && snd_x.isValid()) {
331
332 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity X.fst_x : " << fst_x.efficacity();
333 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity X.snd_x : " << snd_x.efficacity();
334 x_efficacity = (fst_x.efficacity() + snd_x.efficacity()) / 2;
335 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity X : " << x_efficacity;
336 }
337 // else {
338 // sig.mesh()->traceMng()->info() << "Cut() -- Compute X invalid (too small) -- fst_x.length() : " << fst_x.patch().length() << " -- snd_x.length() : " << snd_x.patch().length();
339 // }
340 if (sig.efficacity() > x_efficacity) {
341 return {};
342 }
343 return { fst_x, snd_x };
344 }
345
346 if (cut_point_y != -1) {
347 Real y_efficacity = 0;
348 auto [fst_y, snd_y] = sig.cut(MD_DirY, cut_point_y);
349
350 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Y -- Cut Point : " << cut_point_y;
351
352 fst_y.compute();
353 snd_y.compute();
354 if (fst_y.isValid() && snd_y.isValid()) {
355
356 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity Y.fst_y : " << fst_y.efficacity();
357 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity Y.snd_y : " << snd_y.efficacity();
358 y_efficacity = (fst_y.efficacity() + snd_y.efficacity()) / 2;
359 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity Y : " << y_efficacity;
360 }
361 // else {
362 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Y invalid (too small) -- fst_y.length() : " << fst_y.patch().length() << " -- snd_y.length() : " << snd_y.patch().length();
363 // }
364 if (sig.efficacity() > y_efficacity) {
365 return {};
366 }
367 return { fst_y, snd_y };
368 }
369 if (cut_point_z != -1) {
370 Real z_efficacity = 0;
371 auto [fst_z, snd_z] = sig.cut(MD_DirZ, cut_point_z);
372
373 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Z -- Cut Point : " << cut_point_z;
374
375 fst_z.compute();
376 snd_z.compute();
377 if (fst_z.isValid() && snd_z.isValid()) {
378
379 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity Z.fst_z : " << fst_z.efficacity();
380 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity Z.snd_z : " << snd_z.efficacity();
381 z_efficacity = (fst_z.efficacity() + snd_z.efficacity()) / 2;
382 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity Z : " << z_efficacity;
383 }
384 // else {
385 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Z invalid (too small) -- fst_z.length() : " << fst_z.patch().length() << " -- snd_z.length() : " << snd_z.patch().length();
386 // }
387 if (sig.efficacity() > z_efficacity) {
388 return {};
389 }
390 return { fst_z, snd_z };
391 }
392 return {};
393}
394
397{
398 // We swap in and out at each iteration.
400 bool a_a_b_b = false;
401
402 // As long as the cut is possible.
403 bool need_cut = true;
404 while (need_cut) {
405 need_cut = false;
406 a_a_b_b = !a_a_b_b;
407
408 UniqueArray<AMRPatchPositionSignature>& array_in = a_a_b_b ? sig_array_a : sig_array_b;
409 UniqueArray<AMRPatchPositionSignature>& array_out = a_a_b_b ? sig_array_b : sig_array_a;
410
411 for (auto& sig : array_in) {
412 // sig.mesh()->traceMng()->info() << "Cut() -- i : " << i;
413
414 // If the cut is still possible.
415 if (!sig.stopCut()) {
416 if (!sig.isComputed()) {
417 sig.compute();
418 }
419 if (sig.canBeCut()) {
420 auto [fst, snd] = cut(sig);
421
422 // If the cut is valid, we add the two new patches to the out array.
423 if (fst.isValid()) {
424 need_cut = true;
425 array_out.add(fst);
426 array_out.add(snd);
427 // sig.mesh()->traceMng()->info() << "First Signature :";
428 // sig.mesh()->traceMng()->info() << "\tmin = " << fst.patch().minPoint() << " -- max = " << fst.patch().maxPoint() << " -- length = " << fst.patch().length();
429 // sig.mesh()->traceMng()->info() << "Second Signature :";
430 // sig.mesh()->traceMng()->info() << "\tmin = " << snd.patch().minPoint() << " -- max = " << snd.patch().maxPoint() << " -- length = " << snd.patch().length();
431 continue;
432 }
433 // If the cut does not produce a valid patch, we stop cutting for this patch.
434 sig.setStopCut(true);
435 // sig.mesh()->traceMng()->info() << "Invalid Signature";
436 }
437 // If the patch can no longer be cut, we stop cutting this patch.
438 else {
439 sig.setStopCut(true);
440 }
441 }
442 // sig.mesh()->traceMng()->info() << "No Update";
443 // sig.mesh()->traceMng()->info() << "\tmin = " << sig.patch().minPoint() << " -- max = " << sig.patch().maxPoint();
444 // If the patch could not be cut, we keep it in the out array.
445 // TODO: Meh
446 if (sig.isValid()) {
447 array_out.add(sig);
448 }
449 }
450 array_in.clear();
451 }
452
453 if (a_a_b_b) {
454 sig_array_a.clear();
455 sig_array_a = sig_array_b;
456 }
457}
458
459/*---------------------------------------------------------------------------*/
460/*---------------------------------------------------------------------------*/
461
462} // End namespace Arcane
463
464/*---------------------------------------------------------------------------*/
465/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
static CartCoord _cutDim(ConstArrayView< CartCoord > sig)
Method allowing searching for the best point to perform a cut.
static std::pair< AMRPatchPositionSignature, AMRPatchPositionSignature > cut(const AMRPatchPositionSignature &sig)
Method allowing a patch to be cut into two.
Class for managing patch signatures.
ConstArrayView< CartCoord > sigX() const
Method for retrieving the X signature.
ConstArrayView< CartCoord > sigZ() const
Method for retrieving the Z signature.
Real efficacity() const
Method to determine the patch's efficiency.
std::pair< AMRPatchPositionSignature, AMRPatchPositionSignature > cut(Integer dim, CartCoord cut_point) const
Method for cutting the patch. The patch is not modified.
AMRPatchPosition patch() const
Method for retrieving a copy of the patch.
ConstArrayView< CartCoord > sigY() const
Method for retrieving the Y signature.
CartCoord3 minPoint() const
Method to retrieve the min position of the enclosing box.
Integer size() const
Number of elements in the vector.
void clear()
Removes the elements from the array.
void add(ConstReferenceType val)
Adds element val to the end of the array.
Constant view of an array of type T.
constexpr Integer size() const noexcept
Number of elements in the array.
1D data vector with value semantics (STL style).
-- 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.
double Real
Type representing a real number.