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