Arcane  v4.1.3.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
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/* Méthodes de découpages de patchs selon leurs 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()
41= default;
42
43/*---------------------------------------------------------------------------*/
44/*---------------------------------------------------------------------------*/
45
46AMRPatchPositionSignatureCut::
47~AMRPatchPositionSignatureCut() = default;
48
49/*---------------------------------------------------------------------------*/
50/*---------------------------------------------------------------------------*/
51
54{
55 // Si le découpage produira des patchs trop petits, on retourne -1.
56 if (sig.size() < MIN_SIZE * 2) {
57 return -1;
58 }
59
60 CartCoord cut_point = -1;
61 CartCoord mid = sig.size() / 2;
62
63 // Partie trou.
64 // On recherche un trou dans la signature.
65 // La signature doit avoir été compressée avant
66 // (AMRPatchPositionSignature::compress()).
67 {
68 for (CartCoord i = 0; i < sig.size(); ++i) {
69 if (sig[i] == 0) {
70 cut_point = i;
71 break;
72 }
73 }
74
75 if (cut_point == 0) {
76 ARCANE_FATAL("Call AMRPatchPositionSignature::compress() before");
77 }
78 if (cut_point != -1 && cut_point >= MIN_SIZE && sig.size() - cut_point >= MIN_SIZE) {
79 return cut_point;
80 }
81 }
82
83#if 0
84 // Partie dérivée seconde.
85 // Ne produis pas forcément de meilleurs résultats par rapport à la partie
86 // découpe au milieu.
87 {
88 UniqueArray<CartCoord> dsec_sig(sig.size(), 0);
89
90 CartCoord max = -1;
91 for (CartCoord i = 1; i < dsec_sig.size() - 1; ++i) {
92 dsec_sig[i] = sig[i + 1] - 2 * sig[i] + sig[i - 1];
93 CartCoord dif = math::abs(dsec_sig[i - 1] - dsec_sig[i]);
94 if (dif > max) {
95 cut_point = i;
96 max = dif;
97 }
98 else if (dif == max && math::abs(cut_point - mid) > math::abs(i - mid)) {
99 cut_point = i;
100 }
101 }
102
103 if (cut_point != -1 && cut_point >= MIN_SIZE && sig.size() - cut_point >= MIN_SIZE) {
104 return cut_point;
105 }
106 }
107#endif
108
109 // Partie découpe au milieu.
110 {
111 cut_point = mid;
112
113 if (cut_point != -1 && cut_point >= MIN_SIZE && sig.size() - cut_point >= MIN_SIZE) {
114 return cut_point;
115 }
116 }
117
118 return -1;
119}
120
121/*---------------------------------------------------------------------------*/
122/*---------------------------------------------------------------------------*/
123
124std::pair<AMRPatchPositionSignature, AMRPatchPositionSignature> AMRPatchPositionSignatureCut::
126{
127 // On découpe sur les trois dimensions.
128 CartCoord cut_point_x = _cutDim(sig.sigX());
129 CartCoord cut_point_y = _cutDim(sig.sigY());
130 CartCoord cut_point_z = (sig.mesh()->mesh()->dimension() == 2 ? -1 : _cutDim(sig.sigZ()));
131
132 // Si il est impossible de découper sur l'une des dimensions.
133 if (cut_point_x == -1 && cut_point_y == -1 && cut_point_z == -1) {
134 return {};
135 }
136
137 // On ajuste les points de découpes pour les donner à la méthode
138 // AMRPatchPositionSignature::cut().
139 if (cut_point_x != -1) {
140 cut_point_x += sig.patch().minPoint().x;
141 }
142 if (cut_point_y != -1) {
143 cut_point_y += sig.patch().minPoint().y;
144 }
145 if (cut_point_z != -1) {
146 cut_point_z += sig.patch().minPoint().z;
147 }
148
149 // On doit choisir le meilleur point de découpe parmi les trois.
150 if (cut_point_x != -1 && cut_point_y != -1 && cut_point_z != -1) {
151
152 // Pour choisir, on découpe, on calcule l'efficacité des patchs issus de
153 // la découpe et on choisit la découpe la plus efficace.
154 // TODO : Les méthodes compute() étant des méthodes collectives faisant
155 // plusieurs petites réductions, il faudrait optimiser cette partie
156 // en réunissant les reduces.
157 Real x_efficacity = 0;
158 auto [fst_x, snd_x] = sig.cut(MD_DirX, cut_point_x);
159 {
160 // sig.mesh()->traceMng()->info() << "Cut() -- Compute X -- Cut Point : " << cut_point_x;
161
162 fst_x.compute();
163 snd_x.compute();
164 if (fst_x.isValid() && snd_x.isValid()) {
165
166 // sig.mesh()->traceMng()->info() << "Cut() -- X.fst_x"
167 // << " -- min = " << fst_x.patch().minPoint()
168 // << " -- max = " << fst_x.patch().maxPoint()
169 // << " -- efficacity : " << fst_x.efficacity();
170 // sig.mesh()->traceMng()->info() << "Cut() -- X.snd_x"
171 // << " -- min = " << snd_x.patch().minPoint()
172 // << " -- max = " << snd_x.patch().maxPoint()
173 // << " -- efficacity : " << snd_x.efficacity();
174
175 x_efficacity = (fst_x.efficacity() + snd_x.efficacity()) / 2;
176 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity X : " << x_efficacity;
177 }
178 // else {
179 // sig.mesh()->traceMng()->info() << "Cut() -- Compute X invalid (too small) -- fst_x.length() : " << fst_x.patch().length() << " -- snd_x.length() : " << snd_x.patch().length();
180 // }
181 }
182
183 Real y_efficacity = 0;
184 auto [fst_y, snd_y] = sig.cut(MD_DirY, cut_point_y);
185 {
186 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Y -- Cut Point : " << cut_point_y;
187
188 fst_y.compute();
189 snd_y.compute();
190 if (fst_y.isValid() && snd_y.isValid()) {
191
192 // sig.mesh()->traceMng()->info() << "Cut() -- Y.fst_y"
193 // << " -- min = " << fst_y.patch().minPoint()
194 // << " -- max = " << fst_y.patch().maxPoint()
195 // << " -- efficacity : " << fst_y.efficacity();
196 // sig.mesh()->traceMng()->info() << "Cut() -- Y.snd_y"
197 // << " -- min = " << snd_y.patch().minPoint()
198 // << " -- max = " << snd_y.patch().maxPoint()
199 // << " -- efficacity : " << snd_y.efficacity();
200
201 y_efficacity = (fst_y.efficacity() + snd_y.efficacity()) / 2;
202 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity Y : " << y_efficacity;
203 }
204 // else {
205 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Y invalid (too small) -- fst_y.length() : " << fst_y.patch().length() << " -- snd_y.length() : " << snd_y.patch().length();
206 // }
207 }
208
209 Real z_efficacity = 0;
210 auto [fst_z, snd_z] = sig.cut(MD_DirZ, cut_point_z);
211 {
212 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Z -- Cut Point : " << cut_point_z;
213
214 fst_z.compute();
215 snd_z.compute();
216 if (fst_z.isValid() && snd_z.isValid()) {
217
218 // sig.mesh()->traceMng()->info() << "Cut() -- Z.fst_z"
219 // << " -- min = " << fst_z.patch().minPoint()
220 // << " -- max = " << fst_z.patch().maxPoint()
221 // << " -- efficacity : " << fst_z.efficacity();
222 // sig.mesh()->traceMng()->info() << "Cut() -- Z.snd_z"
223 // << " -- min = " << snd_z.patch().minPoint()
224 // << " -- max = " << snd_z.patch().maxPoint()
225 // << " -- efficacity : " << snd_z.efficacity();
226
227 z_efficacity = (fst_z.efficacity() + snd_z.efficacity()) / 2;
228 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity Z : " << z_efficacity;
229 }
230 // else {
231 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Z invalid (too small) -- fst_z.length() : " << fst_z.patch().length() << " -- snd_z.length() : " << snd_z.patch().length();
232 // }
233 }
234
235 // Si la découpe n'améliore pas l'efficacité, on return.
236 {
237 Real sig_efficacity = sig.efficacity();
238 if (sig_efficacity > x_efficacity && sig_efficacity > y_efficacity && sig_efficacity > z_efficacity) {
239 return {};
240 }
241 }
242
243 // On retourne la meilleure efficacité.
244 if (x_efficacity >= y_efficacity && x_efficacity >= z_efficacity && x_efficacity != 0) {
245 return { fst_x, snd_x };
246 }
247 if (y_efficacity >= x_efficacity && y_efficacity >= z_efficacity && y_efficacity != 0) {
248 return { fst_y, snd_y };
249 }
250 if (z_efficacity == 0) {
251 ARCANE_FATAL("Invalid cut");
252 }
253 return { fst_z, snd_z };
254 }
255
256 // Même principe qu'au-dessus.
257 if (cut_point_x != -1 && cut_point_y != -1) {
258 Real x_efficacity = 0;
259 auto [fst_x, snd_x] = sig.cut(MD_DirX, cut_point_x);
260 {
261 // sig.mesh()->traceMng()->info() << "Cut() -- Compute X -- Cut Point : " << cut_point_x;
262
263 fst_x.compute();
264 snd_x.compute();
265 if (fst_x.isValid() && snd_x.isValid()) {
266
267 // sig.mesh()->traceMng()->info() << "Cut() -- X.fst_x"
268 // << " -- min = " << fst_x.patch().minPoint()
269 // << " -- max = " << fst_x.patch().maxPoint()
270 // << " -- efficacity : " << fst_x.efficacity();
271 // sig.mesh()->traceMng()->info() << "Cut() -- X.snd_x"
272 // << " -- min = " << snd_x.patch().minPoint()
273 // << " -- max = " << snd_x.patch().maxPoint()
274 // << " -- efficacity : " << snd_x.efficacity();
275
276 x_efficacity = (fst_x.efficacity() + snd_x.efficacity()) / 2;
277 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity X : " << x_efficacity;
278 }
279 // else {
280 // sig.mesh()->traceMng()->info() << "Cut() -- Compute X invalid (too small) -- fst_x.length() : " << fst_x.patch().length() << " -- snd_x.length() : " << snd_x.patch().length();
281 // }
282 }
283
284 Real y_efficacity = 0;
285 auto [fst_y, snd_y] = sig.cut(MD_DirY, cut_point_y);
286 {
287 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Y -- Cut Point : " << cut_point_y;
288
289 fst_y.compute();
290 snd_y.compute();
291 if (fst_y.isValid() && snd_y.isValid()) {
292
293 // sig.mesh()->traceMng()->info() << "Cut() -- Y.fst_y"
294 // << " -- min = " << fst_y.patch().minPoint()
295 // << " -- max = " << fst_y.patch().maxPoint()
296 // << " -- efficacity : " << fst_y.efficacity();
297 // sig.mesh()->traceMng()->info() << "Cut() -- Y.snd_y"
298 // << " -- min = " << snd_y.patch().minPoint()
299 // << " -- max = " << snd_y.patch().maxPoint()
300 // << " -- efficacity : " << snd_y.efficacity();
301
302 y_efficacity = (fst_y.efficacity() + snd_y.efficacity()) / 2;
303 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity Y : " << y_efficacity;
304 }
305 // else {
306 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Y invalid (too small) -- fst_y.length() : " << fst_y.patch().length() << " -- snd_y.length() : " << snd_y.patch().length();
307 // }
308 }
309 {
310 Real sig_efficacity = sig.efficacity();
311 if (sig_efficacity > x_efficacity && sig_efficacity > y_efficacity) {
312 return {};
313 }
314 }
315
316 if (x_efficacity >= y_efficacity && x_efficacity != 0) {
317 return { fst_x, snd_x };
318 }
319 if (y_efficacity == 0) {
320 ARCANE_FATAL("Invalid cut");
321 }
322 return { fst_y, snd_y };
323 }
324
325 if (cut_point_x != -1) {
326 Real x_efficacity = 0;
327 auto [fst_x, snd_x] = sig.cut(MD_DirX, cut_point_x);
328
329 // sig.mesh()->traceMng()->info() << "Cut() -- Compute X -- Cut Point : " << cut_point_x;
330
331 fst_x.compute();
332 snd_x.compute();
333 if (fst_x.isValid() && snd_x.isValid()) {
334
335 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity X.fst_x : " << fst_x.efficacity();
336 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity X.snd_x : " << snd_x.efficacity();
337 x_efficacity = (fst_x.efficacity() + snd_x.efficacity()) / 2;
338 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity X : " << x_efficacity;
339 }
340 // else {
341 // sig.mesh()->traceMng()->info() << "Cut() -- Compute X invalid (too small) -- fst_x.length() : " << fst_x.patch().length() << " -- snd_x.length() : " << snd_x.patch().length();
342 // }
343 if (sig.efficacity() > x_efficacity) {
344 return {};
345 }
346 return { fst_x, snd_x };
347 }
348
349 if (cut_point_y != -1) {
350 Real y_efficacity = 0;
351 auto [fst_y, snd_y] = sig.cut(MD_DirY, cut_point_y);
352
353 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Y -- Cut Point : " << cut_point_y;
354
355 fst_y.compute();
356 snd_y.compute();
357 if (fst_y.isValid() && snd_y.isValid()) {
358
359 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity Y.fst_y : " << fst_y.efficacity();
360 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity Y.snd_y : " << snd_y.efficacity();
361 y_efficacity = (fst_y.efficacity() + snd_y.efficacity()) / 2;
362 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity Y : " << y_efficacity;
363 }
364 // else {
365 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Y invalid (too small) -- fst_y.length() : " << fst_y.patch().length() << " -- snd_y.length() : " << snd_y.patch().length();
366 // }
367 if (sig.efficacity() > y_efficacity) {
368 return {};
369 }
370 return { fst_y, snd_y };
371 }
372 if (cut_point_z != -1) {
373 Real z_efficacity = 0;
374 auto [fst_z, snd_z] = sig.cut(MD_DirZ, cut_point_z);
375
376 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Z -- Cut Point : " << cut_point_z;
377
378 fst_z.compute();
379 snd_z.compute();
380 if (fst_z.isValid() && snd_z.isValid()) {
381
382 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity Z.fst_z : " << fst_z.efficacity();
383 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity Z.snd_z : " << snd_z.efficacity();
384 z_efficacity = (fst_z.efficacity() + snd_z.efficacity()) / 2;
385 // sig.mesh()->traceMng()->info() << "Cut() -- efficacity Z : " << z_efficacity;
386 }
387 // else {
388 // sig.mesh()->traceMng()->info() << "Cut() -- Compute Z invalid (too small) -- fst_z.length() : " << fst_z.patch().length() << " -- snd_z.length() : " << snd_z.patch().length();
389 // }
390 if (sig.efficacity() > z_efficacity) {
391 return {};
392 }
393 return { fst_z, snd_z };
394 }
395 return {};
396}
397
400{
401 // On inverse in et out à chaque itération.
403 bool a_a_b_b = false;
404
405 // Tant que la découpe est possible.
406 bool need_cut = true;
407 while (need_cut) {
408 need_cut = false;
409 a_a_b_b = !a_a_b_b;
410
411 UniqueArray<AMRPatchPositionSignature>& array_in = a_a_b_b ? sig_array_a : sig_array_b;
412 UniqueArray<AMRPatchPositionSignature>& array_out = a_a_b_b ? sig_array_b : sig_array_a;
413
414 for (auto& sig : array_in) {
415 // sig.mesh()->traceMng()->info() << "Cut() -- i : " << i;
416
417 // Si la découpe est encore possible.
418 if (!sig.stopCut()) {
419 if (!sig.isComputed()) {
420 sig.compute();
421 }
422 if (sig.canBeCut()) {
423 auto [fst, snd] = cut(sig);
424
425 // Si la découpe est valide, on ajoute les deux nouveau patchs dans
426 // le tableau out.
427 if (fst.isValid()) {
428 need_cut = true;
429 array_out.add(fst);
430 array_out.add(snd);
431 // sig.mesh()->traceMng()->info() << "First Signature :";
432 // sig.mesh()->traceMng()->info() << "\tmin = " << fst.patch().minPoint() << " -- max = " << fst.patch().maxPoint() << " -- length = " << fst.patch().length();
433 // sig.mesh()->traceMng()->info() << "Second Signature :";
434 // sig.mesh()->traceMng()->info() << "\tmin = " << snd.patch().minPoint() << " -- max = " << snd.patch().maxPoint() << " -- length = " << snd.patch().length();
435 continue;
436 }
437 // Si la découpe ne produit pas de patch valide, on stop la découpe
438 // pour ce patch.
439 sig.setStopCut(true);
440 // sig.mesh()->traceMng()->info() << "Invalid Signature";
441 }
442 // Si le patch ne peut plus être découpé, on stop la découpe de ce
443 // patch.
444 else {
445 sig.setStopCut(true);
446 }
447 }
448 // sig.mesh()->traceMng()->info() << "No Update";
449 // sig.mesh()->traceMng()->info() << "\tmin = " << sig.patch().minPoint() << " -- max = " << sig.patch().maxPoint();
450 // Si le patch n'a pas pu être découpé, on le conserve dans le
451 // tableau out.
452 // TODO : Bof
453 if (sig.isValid()) {
454 array_out.add(sig);
455 }
456 }
457 array_in.clear();
458 }
459
460 if (a_a_b_b) {
461 sig_array_a.clear();
462 sig_array_a = sig_array_b;
463 }
464}
465
466/*---------------------------------------------------------------------------*/
467/*---------------------------------------------------------------------------*/
468
469} // End namespace Arcane
470
471/*---------------------------------------------------------------------------*/
472/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
static CartCoord _cutDim(ConstArrayView< CartCoord > sig)
Méthode permettant de chercher le meilleur point pour effectuer une découpe.
static std::pair< AMRPatchPositionSignature, AMRPatchPositionSignature > cut(const AMRPatchPositionSignature &sig)
Méthode permettant de découper un patch en deux.
Classe permettant de gérer les signatures d'un patch.
ConstArrayView< CartCoord > sigX() const
Méthode permettant de récupérer la signature X.
ConstArrayView< CartCoord > sigZ() const
Méthode permettant de récupérer la signature Z.
Real efficacity() const
Méthode permettant de connaitre l'efficacité du patch.
std::pair< AMRPatchPositionSignature, AMRPatchPositionSignature > cut(Integer dim, CartCoord cut_point) const
Méthode permettant de découper le patch. Le patch n'est pas modifié.
AMRPatchPosition patch() const
Méthode permettant de récupérer une copie du patch.
ConstArrayView< CartCoord > sigY() const
Méthode permettant de récupérer la signature Y.
CartCoord3 minPoint() const
Méthode permettant de récupérer la position min de la boite englobante.
Integer size() const
Nombre d'éléments du vecteur.
void clear()
Supprime les éléments du tableau.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
Vue constante d'un tableau de type T.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
Vecteur 1D de données avec sémantique par valeur (style STL).
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
Int32 CartCoord
Représente une coordonnée d'un élément dans la grille cartésienne (en X ou en Y ou en Z).
Int32 Integer
Type représentant un entier.
@ MD_DirZ
Direction Z.
@ MD_DirY
Direction Y.
@ MD_DirX
Direction X.
double Real
Type représentant un réel.