Arcane  4.2.3.0
User documentation
Loading...
Searching...
No Matches
FaceDirectionMng.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/* FaceDirectionMng.cc (C) 2000-2026 */
9/* */
10/* Information about the faces of a direction X Y or Z of a structured mesh. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/cartesianmesh/FaceDirectionMng.h"
15
16#include "arcane/utils/FatalErrorException.h"
17#include "arcane/utils/Real3.h"
18#include "arcane/utils/PlatformUtils.h"
19
20#include "arcane/core/IItemFamily.h"
21#include "arcane/core/ItemGroup.h"
22#include "arcane/core/IMesh.h"
23#include "arcane/core/VariableTypes.h"
24
25#include "arcane/cartesianmesh/ICartesianMesh.h"
26#include "arcane/cartesianmesh/CellDirectionMng.h"
27#include "arcane/cartesianmesh/internal/ICartesianMeshInternal.h"
28
29/*---------------------------------------------------------------------------*/
30/*---------------------------------------------------------------------------*/
31
32namespace Arcane
33{
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
37
39{
40 public:
41
42 Impl()
44 {}
45
46 public:
47
48 FaceGroup m_inner_all_items;
49 FaceGroup m_outer_all_items;
50 FaceGroup m_inpatch_all_items;
51 FaceGroup m_overlap_all_items;
52 FaceGroup m_all_items;
53 ICartesianMesh* m_cartesian_mesh = nullptr;
54 Integer m_patch_index = -1;
56};
57
58/*---------------------------------------------------------------------------*/
59/*---------------------------------------------------------------------------*/
60
63: m_direction(MD_DirInvalid)
64, m_p(nullptr)
65{
66}
67
68/*---------------------------------------------------------------------------*/
69/*---------------------------------------------------------------------------*/
70
71void FaceDirectionMng::
72_internalInit(ICartesianMesh* cm, eMeshDirection dir, Integer patch_index)
73{
74 if (m_p)
75 ARCANE_FATAL("Initialisation already done");
76 m_p = new Impl();
77 m_direction = dir;
78 m_p->m_cartesian_mesh = cm;
79 m_p->m_patch_index = patch_index;
80}
81
82/*---------------------------------------------------------------------------*/
83/*---------------------------------------------------------------------------*/
84
85void FaceDirectionMng::
86_internalDestroy()
87{
88 delete m_p;
89 m_p = nullptr;
90}
91
92/*---------------------------------------------------------------------------*/
93/*---------------------------------------------------------------------------*/
94
95void FaceDirectionMng::
96_internalResizeInfos(Int32 new_size)
97{
98 m_p->m_infos.resize(new_size);
99 m_infos_view = m_p->m_infos.view();
100}
101
102/*---------------------------------------------------------------------------*/
103/*---------------------------------------------------------------------------*/
104
105void FaceDirectionMng::
106_internalComputeInfos(const CellDirectionMng& cell_dm, const VariableCellReal3& cells_center,
107 const VariableFaceReal3& faces_center)
108{
109 IMesh* mesh = m_p->m_cartesian_mesh->mesh();
110 IItemFamily* face_family = mesh->faceFamily();
111 IItemFamily* cell_family = mesh->cellFamily();
112 int dir = (int)m_direction;
113 String base_group_name = String("Direction") + dir;
114 if (m_p->m_patch_index >= 0)
115 base_group_name = base_group_name + String("AMRPatch") + m_p->m_patch_index;
116
117 // Calculates the list of faces in a given direction.
118 // For each cell, it is necessary to add to the list of faces
119 // the two faces in the desired direction, taking care
120 // not to add the same face twice.
121 UniqueArray<Int32> faces_lid;
122 {
123 CellGroup all_cells = cell_dm.allCells();
124 faces_lid.reserve(all_cells.size());
125 // Set of faces already added
126 UniqueArray<bool> done_faces(face_family->maxLocalId(), false);
127 ENUMERATE_CELL (icell, all_cells) {
128 DirCellFace dcf(cell_dm.cellFace(*icell));
129 Face next_face = dcf.next();
130 Face prev_face = dcf.previous();
131
132 //! Adds the previous face to the list of faces in this direction
133 Int32 prev_lid = prev_face.localId();
134 if (!done_faces[prev_lid]) {
135 faces_lid.add(prev_lid);
136 done_faces[prev_lid] = true;
137 }
138 Int32 next_lid = next_face.localId();
139 if (!done_faces[next_lid]) {
140 faces_lid.add(next_lid);
141 done_faces[next_lid] = true;
142 }
143 }
144 }
145
146 FaceGroup all_faces = face_family->createGroup(String("AllFaces") + base_group_name, Int32ConstArrayView(), true);
147 all_faces.setItems(faces_lid, true);
148
149 UniqueArray<Int32> inner_lids;
150 UniqueArray<Int32> outer_lids;
151 ENUMERATE_FACE (iitem, all_faces) {
152 Int32 lid = iitem.itemLocalId();
153 Face face = *iitem;
154 // TODO: do not use nbCell() but do this via the marker used previously
155 if (face.nbCell() == 1)
156 outer_lids.add(lid);
157 else
158 inner_lids.add(lid);
159 }
160 m_p->m_inner_all_items = face_family->createGroup(String("AllInner") + base_group_name, inner_lids, true);
161 m_p->m_outer_all_items = face_family->createGroup(String("AllOuter") + base_group_name, outer_lids, true);
162 m_p->m_all_items = all_faces;
163 m_cells = CellInfoListView(cell_family);
164
165 _computeCellInfos(cell_dm, cells_center, faces_center);
166}
167
168/*---------------------------------------------------------------------------*/
169/*---------------------------------------------------------------------------*/
170
171void FaceDirectionMng::
172_internalComputeInfos(const CellDirectionMng& cell_dm)
173{
174 IMesh* mesh = m_p->m_cartesian_mesh->mesh();
175 IItemFamily* face_family = mesh->faceFamily();
176 IItemFamily* cell_family = mesh->cellFamily();
177 int dir = (int)m_direction;
178 String base_group_name = String("Direction") + dir;
179 if (m_p->m_patch_index >= 0)
180 base_group_name = base_group_name + String("AMRPatch") + m_p->m_patch_index;
181
182 // Calculates the list of faces in a given direction.
183 // For each cell, it is necessary to add to the list of faces
184 // the two faces in the desired direction, taking care
185 // not to add the same face twice.
186 UniqueArray<Int32> faces_lid;
187 {
188 CellGroup all_cells = cell_dm.allCells();
189 faces_lid.reserve(all_cells.size());
190 // Set of faces already added
191 UniqueArray<bool> done_faces(face_family->maxLocalId(), false);
192 ENUMERATE_ (Cell, icell, all_cells) {
193 DirCellFace dcf(cell_dm.cellFace(*icell));
194 Face next_face = dcf.next();
195 Face prev_face = dcf.previous();
196
197 //! Adds the previous face to the list of faces in this direction
198 Int32 prev_lid = prev_face.localId();
199 if (!done_faces[prev_lid]) {
200 faces_lid.add(prev_lid);
201 done_faces[prev_lid] = true;
202 }
203 Int32 next_lid = next_face.localId();
204 if (!done_faces[next_lid]) {
205 faces_lid.add(next_lid);
206 done_faces[next_lid] = true;
207 }
208 }
209 }
210
211 FaceGroup all_faces = face_family->createGroup(String("AllFaces") + base_group_name, Int32ConstArrayView(), true);
212 all_faces.setItems(faces_lid, true);
213
214 UniqueArray<Int32> inner_cells_lid;
215 UniqueArray<Int32> outer_cells_lid;
216 cell_dm.innerCells().view().fillLocalIds(inner_cells_lid);
217 cell_dm.outerCells().view().fillLocalIds(outer_cells_lid);
218
219 UniqueArray<Int32> inner_lids;
220 UniqueArray<Int32> outer_lids;
221 UniqueArray<Int32> inpatch_lids;
222 UniqueArray<Int32> overlap_lids;
223 ENUMERATE_ (Face, iface, all_faces) {
224 Int32 lid = iface.itemLocalId();
225 Face face = *iface;
226 if (face.nbCell() == 1) {
227 if (inner_cells_lid.contains(face.cell(0).localId())) {
228 inner_lids.add(lid);
229 inpatch_lids.add(lid);
230 }
231 else if (outer_cells_lid.contains(face.cell(0).localId())) {
232 outer_lids.add(lid);
233 inpatch_lids.add(lid);
234 }
235 else {
236 overlap_lids.add(lid);
237 }
238 }
239 else {
240 bool c0_inner_cell = inner_cells_lid.contains(face.cell(0).localId());
241 bool c1_inner_cell = inner_cells_lid.contains(face.cell(1).localId());
242 if (c0_inner_cell || c1_inner_cell) {
243 inner_lids.add(lid);
244 inpatch_lids.add(lid);
245 }
246 else {
247 bool c0_outer_cell = outer_cells_lid.contains(face.cell(0).localId());
248 bool c1_outer_cell = outer_cells_lid.contains(face.cell(1).localId());
249 if (c0_outer_cell || c1_outer_cell) {
250 outer_lids.add(lid);
251 inpatch_lids.add(lid);
252 }
253 else {
254 overlap_lids.add(lid);
255 }
256 }
257 }
258 }
259 m_p->m_inner_all_items = face_family->createGroup(String("AllInner") + base_group_name, inner_lids, true);
260 m_p->m_outer_all_items = face_family->createGroup(String("AllOuter") + base_group_name, outer_lids, true);
261 m_p->m_inpatch_all_items = face_family->createGroup(String("AllInPatch") + base_group_name, inpatch_lids, true);
262 m_p->m_overlap_all_items = face_family->createGroup(String("AllOverlap") + base_group_name, overlap_lids, true);
263 m_p->m_all_items = all_faces;
264 m_cells = CellInfoListView(cell_family);
265
266 _computeCellInfos();
267}
268
269/*---------------------------------------------------------------------------*/
270/*---------------------------------------------------------------------------*/
271
272bool FaceDirectionMng::
273_hasFace(Cell cell, Int32 face_local_id) const
274{
275 for (FaceLocalId iface_lid : cell.faceIds()) {
276 if (iface_lid == face_local_id)
277 return true;
278 }
279 return false;
280}
281
282/*---------------------------------------------------------------------------*/
283/*---------------------------------------------------------------------------*/
284/*!
285 * \brief Calculates the cells before and after a face, in a given direction.
286 *
287 * To be independent of how the mesh is created, we use the coordinates
288 * of the face centers and the cell centers.
289 */
290void FaceDirectionMng::
291_computeCellInfos(const CellDirectionMng& cell_dm, const VariableCellReal3& cells_center,
292 const VariableFaceReal3& faces_center)
293{
294 eMeshDirection dir = m_direction;
295
296 // Create the set of cells in the patch and use it
297 // to ensure that every front/back cell is in
298 // this set
299 UniqueArray<bool> is_patch_cell(cell_dm.allCells().itemFamily()->maxLocalId(), false);
300 ENUMERATE_CELL (icell, cell_dm.allCells()) {
301 is_patch_cell[icell.itemLocalId()] = true;
302 }
303
304 ENUMERATE_FACE (iface, m_p->m_all_items) {
305 Face face = *iface;
306 Int32 face_lid = iface.itemLocalId();
307 Real3 face_coord = faces_center[iface];
308 Cell front_cell = face.frontCell();
309 Cell back_cell = face.backCell();
310
311 // Checks that the cells are in our patch.
312 if (!front_cell.null())
313 if (!is_patch_cell[front_cell.localId()])
314 front_cell = Cell();
315 if (!back_cell.null())
316 if (!is_patch_cell[back_cell.localId()])
317 back_cell = Cell();
318
319 bool is_inverse = false;
320 if (!front_cell.null()) {
321 Real3 front_coord = cells_center[front_cell];
322 if (dir == MD_DirX) {
323 if (front_coord.x < face_coord.x)
324 is_inverse = true;
325 }
326 else if (dir == MD_DirY) {
327 if (front_coord.y < face_coord.y)
328 is_inverse = true;
329 }
330 else if (dir == MD_DirZ) {
331 if (front_coord.z < face_coord.z)
332 is_inverse = true;
333 }
334 }
335 else {
336 Real3 back_coord = cells_center[back_cell];
337 if (dir == MD_DirX) {
338 if (back_coord.x > face_coord.x)
339 is_inverse = true;
340 }
341 else if (dir == MD_DirY) {
342 if (back_coord.y > face_coord.y)
343 is_inverse = true;
344 }
345 else if (dir == MD_DirZ) {
346 if (back_coord.z > face_coord.z)
347 is_inverse = true;
348 }
349 }
350 // If the face has two connected cells, look at the AMR level of these
351 // two cells and if they are different, only keep the cell
352 // whose AMR level is that of the face.
353 if (!back_cell.null() && !front_cell.null()) {
354 Int32 back_level = back_cell.level();
355 Int32 front_level = front_cell.level();
356 if (back_level != front_level) {
357 // The face does not have its level information, but if the two
358 // cells are not of the same level, the face belongs only to one
359 // of the two cells. We therefore only keep that one.
360 if (!_hasFace(back_cell, face_lid))
361 back_cell = Cell();
362 if (!_hasFace(front_cell, face_lid))
363 front_cell = Cell();
364 }
365 }
366 if (is_inverse)
367 m_infos_view[face_lid] = ItemDirectionInfo(back_cell, front_cell);
368 else
369 m_infos_view[face_lid] = ItemDirectionInfo(front_cell, back_cell);
370 }
371}
372
373/*---------------------------------------------------------------------------*/
374/*---------------------------------------------------------------------------*/
375
376void FaceDirectionMng::
377_computeCellInfos() const
378{
379 Ref<ICartesianMeshNumberingMngInternal> numbering = m_p->m_cartesian_mesh->_internalApi()->cartesianMeshNumberingMngInternal();
380 eMeshDirection dir = m_direction;
381 // ITraceMng* tm = m_p->m_cartesian_mesh->traceMng();
382
383 ENUMERATE_ (Face, iface, m_p->m_all_items) {
384 Face face = *iface;
385 Cell front_cell = face.frontCell();
386 Cell back_cell = face.backCell();
387 // tm->info() << "FaceUID : " << face.uniqueId()
388 // << " -- backCellUID : " << back_cell.uniqueId()
389 // << " -- backCellLevel : " << back_cell.level()
390 // << " -- frontCellUID : " << front_cell.uniqueId()
391 // << " -- frontCellLevel : " << front_cell.level()
392 // << " -- dir : " << dir;
393 bool is_inverse = false;
394 if (!front_cell.null() && !back_cell.null()) {
395
396 // If the face has two connected cells, look at the AMR level of these
397 // two cells and if they are different, only keep the cell
398 // whose AMR level is that of the face.
399 Int32 front_cell_level = front_cell.level();
400 Int32 back_cell_level = back_cell.level();
401 if (front_cell_level != back_cell_level) {
402 Int32 face_level = numbering->faceLevel(face.uniqueId());
403 if (front_cell_level != face_level) {
404 front_cell = Cell();
405 }
406 else {
407 back_cell = Cell();
408 }
409 }
410
411 if (back_cell.uniqueId() > front_cell.uniqueId()) {
412 is_inverse = true;
413 }
414 }
415 // The order of numbering is described in the file
416 // CartesianMeshAMRPatchMng.cc (tag #priority_owner_2d).
417 if (back_cell.null()) {
418 Int64 uids[6];
419 ArrayView av_uids(numbering->nbFaceByCell(), uids);
420 numbering->cellFaceUniqueIds(front_cell, av_uids);
421 if (m_p->m_cartesian_mesh->mesh()->dimension() == 2) {
422 if (dir == MD_DirX) {
423 if (face.uniqueId() == av_uids[1])
424 is_inverse = true;
425 else if (face.uniqueId() != av_uids[3])
426 ARCANE_FATAL("Bad connectivity, did you call computeDirection() ? -- Expected : {0} -- Found : {1}", av_uids[3], face.uniqueId());
427 }
428 else if (dir == MD_DirY) {
429 if (face.uniqueId() == av_uids[2])
430 is_inverse = true;
431 else if (face.uniqueId() != av_uids[0])
432 ARCANE_FATAL("Bad connectivity, did you call computeDirection() ? -- Expected : {0} -- Found : {1}", av_uids[0], face.uniqueId());
433 }
434 }
435 else if (m_p->m_cartesian_mesh->mesh()->dimension() == 3) {
436 if (dir == MD_DirX) {
437 if (face.uniqueId() == av_uids[4])
438 is_inverse = true;
439 else if (face.uniqueId() != av_uids[1])
440 ARCANE_FATAL("Bad connectivity, did you call computeDirection() ? -- Expected : {0} -- Found : {1}", av_uids[1], face.uniqueId());
441 }
442 else if (dir == MD_DirY) {
443 if (face.uniqueId() == av_uids[5])
444 is_inverse = true;
445 else if (face.uniqueId() != av_uids[2])
446 ARCANE_FATAL("Bad connectivity, did you call computeDirection() ? -- Expected : {0} -- Found : {1}", av_uids[2], face.uniqueId());
447 }
448 else if (dir == MD_DirZ) {
449 if (face.uniqueId() == av_uids[3])
450 is_inverse = true;
451 else if (face.uniqueId() != av_uids[0])
452 ARCANE_FATAL("Bad connectivity, did you call computeDirection() ? -- Expected : {0} -- Found : {1}", av_uids[0], face.uniqueId());
453 }
454 }
455 }
456 else if (front_cell.null()) {
457 Int64 uids[6];
458 ArrayView av_uids(numbering->nbFaceByCell(), uids);
459 numbering->cellFaceUniqueIds(back_cell, av_uids);
460 if (m_p->m_cartesian_mesh->mesh()->dimension() == 2) {
461 if (dir == MD_DirX) {
462 if (face.uniqueId() == av_uids[3])
463 is_inverse = true;
464 else if (face.uniqueId() != av_uids[1])
465 ARCANE_FATAL("Bad connectivity, did you call computeDirection() ? -- Expected : {0} -- Found : {1}", av_uids[1], face.uniqueId());
466 }
467 else if (dir == MD_DirY) {
468 if (face.uniqueId() == av_uids[0])
469 is_inverse = true;
470 else if (face.uniqueId() != av_uids[2])
471 ARCANE_FATAL("Bad connectivity, did you call computeDirection() ? -- Expected : {0} -- Found : {1}", av_uids[2], face.uniqueId());
472 }
473 }
474 else if (m_p->m_cartesian_mesh->mesh()->dimension() == 3) {
475 if (dir == MD_DirX) {
476 if (face.uniqueId() == av_uids[1])
477 is_inverse = true;
478 else if (face.uniqueId() != av_uids[4])
479 ARCANE_FATAL("Bad connectivity, did you call computeDirection() ? -- Expected : {0} -- Found : {1}", av_uids[4], face.uniqueId());
480 }
481 else if (dir == MD_DirY) {
482 if (face.uniqueId() == av_uids[2])
483 is_inverse = true;
484 else if (face.uniqueId() != av_uids[5])
485 ARCANE_FATAL("Bad connectivity, did you call computeDirection() ? -- Expected : {0} -- Found : {1}", av_uids[5], face.uniqueId());
486 }
487 else if (dir == MD_DirZ) {
488 if (face.uniqueId() == av_uids[0])
489 is_inverse = true;
490 else if (face.uniqueId() != av_uids[3])
491 ARCANE_FATAL("Bad connectivity, did you call computeDirection() ? -- Expected : {0} -- Found : {1}", av_uids[3], face.uniqueId());
492 }
493 }
494 }
495 // tm->info() << "FaceUID : " << face.uniqueId()
496 // << " -- backCellUID : " << back_cell.uniqueId()
497 // << " -- frontCellUID : " << front_cell.uniqueId()
498 // << " -- is_inverse : " << is_inverse
499 // << " -- dir : " << dir;
500
501 if (is_inverse)
502 m_infos_view[iface.itemLocalId()] = ItemDirectionInfo(back_cell, front_cell);
503 else
504 m_infos_view[iface.itemLocalId()] = ItemDirectionInfo(front_cell, back_cell);
505 }
506}
507
508/*---------------------------------------------------------------------------*/
509/*---------------------------------------------------------------------------*/
510
512allFaces() const
513{
514 return m_p->m_all_items;
515}
516
517/*---------------------------------------------------------------------------*/
518/*---------------------------------------------------------------------------*/
519
521overlapFaces() const
522{
523 return m_p->m_overlap_all_items;
524}
525
526/*---------------------------------------------------------------------------*/
527/*---------------------------------------------------------------------------*/
528
530inPatchFaces() const
531{
532 return m_p->m_inpatch_all_items;
533}
534
535/*---------------------------------------------------------------------------*/
536/*---------------------------------------------------------------------------*/
537
539innerFaces() const
540{
541 return m_p->m_inner_all_items;
542}
543
544/*---------------------------------------------------------------------------*/
545/*---------------------------------------------------------------------------*/
546
548outerFaces() const
549{
550 return m_p->m_outer_all_items;
551}
552
553/*---------------------------------------------------------------------------*/
554/*---------------------------------------------------------------------------*/
555
556} // End namespace Arcane
557
558/*---------------------------------------------------------------------------*/
559/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
#define ENUMERATE_FACE(name, group)
Generic enumerator for a face group.
#define ENUMERATE_(type, name, group)
Generic enumerator for an entity group.
#define ENUMERATE_CELL(name, group)
Generic enumerator for a cell group.
Info about the cells in a specific X, Y, or Z direction of a structured mesh.
Cell of a mesh.
Definition Item.h:1300
FaceGroup inPatchFaces() const
Group of all faces within the patch in the direction.
DirFace face(Face f) const
Direction face corresponding to face f.
FaceGroup overlapFaces() const
Group of all overlap faces in the direction.
FaceDirectionMng()
Creates an empty instance.
FaceGroup innerFaces() const
Group of all internal faces in the direction.
FaceGroup outerFaces() const
Group of all external faces in the direction.
FaceGroup allFaces() const
Group of all faces in the direction.
void setItems(Int32ConstArrayView items_local_id)
Sets the entities of the group.
Definition ItemGroup.cc:484
1D data vector with value semantics (STL style).
void resize(Int64 s)
Changes the number of elements in the array to s.
ItemGroupT< Cell > CellGroup
Group of cells.
Definition ItemTypes.h:184
ItemGroupT< Face > FaceGroup
Group of faces.
Definition ItemTypes.h:179
MeshVariableScalarRefT< Cell, Real3 > VariableCellReal3
Coordinate type quantity at cell center.
MeshVariableScalarRefT< Face, Real3 > VariableFaceReal3
Coordinate type quantity at face.
IMemoryAllocator * getDefaultDataAllocator()
Default allocator for data.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
ConstArrayView< Int32 > Int32ConstArrayView
C equivalent of a 1D array of 32-bit integers.
Definition UtilsTypes.h:476
eMeshDirection
Direction type for a structured mesh.
@ MD_DirInvalid
Invalid or uninitialized direction.
@ MD_DirZ
Z Direction.
@ MD_DirY
Y Direction.
@ MD_DirX
X Direction.
@ Cell
The mesh is AMR by cell.
Definition MeshKind.h:53
std::int32_t Int32
Signed integer type of 32 bits.