Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
HoneyCombMeshGenerator.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/* HoneyCombMeshGenerator.cc (C) 2000-2023 */
9/* */
10/* Hexagonal mesh generation service. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/std/HoneyCombMeshGenerator.h"
15
16#include "arcane/utils/Real2.h"
17
18#include "arcane/core/IMeshBuilder.h"
19#include "arcane/core/IPrimaryMesh.h"
20#include "arcane/core/IItemFamily.h"
21#include "arcane/core/IParallelMng.h"
22#include "arcane/core/MeshBuildInfo.h"
23
24#include "arcane/std/HoneyComb2DMeshGenerator_axl.h"
25#include "arcane/std/HoneyComb3DMeshGenerator_axl.h"
26
27#include <map>
28
29/*---------------------------------------------------------------------------*/
30/*---------------------------------------------------------------------------*/
31
32namespace Arcane
33{
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
37
42class SimpleSequentialMeshBuilder
43: public TraceAccessor
44{
45 private:
46
48 {
49 public:
50
51 bool operator()(const Real3& a, const Real3& b) const
52 {
53 if (!math::isNearlyEqualWithEpsilon(a.x, b.x, m_epsilon))
54 return a.x < b.x;
55 if (!math::isNearlyEqualWithEpsilon(a.y, b.y, m_epsilon))
56 return a.y < b.y;
57 if (!math::isNearlyEqualWithEpsilon(a.z, b.z, m_epsilon))
58 return a.z < b.z;
59 return false;
60 }
61
62 private:
63
64 Real m_epsilon = 1e-14;
65 };
66
67 public:
68
69 explicit SimpleSequentialMeshBuilder(IMesh* pm)
70 : TraceAccessor(pm->traceMng())
71 , m_mesh(pm)
72 {
73 }
74
75 public:
76
79 {
80 auto p = m_nodes_coord_map.find(coord);
81 if (p != m_nodes_coord_map.end())
82 return p->second;
83 Int32 v = m_nodes_coordinates.size();
84 m_nodes_coordinates.add(coord);
85 m_nodes_coord_map.insert(std::make_pair(coord, v));
86 return v;
87 }
88
89 Int32 addCell(Int32 type, ConstArrayView<Real3> nodes_coords)
90 {
91 m_cells_infos.add(type);
92 const Int32 v = m_nb_cell;
93 m_cells_infos.add(v);
94 ++m_nb_cell;
95 for (Real3 coord : nodes_coords)
96 m_cells_infos.add(addNode(coord));
97 return v;
98 }
99 ConstArrayView<Int64> cellsInfos() const { return m_cells_infos; }
100 Int32 nbCell() const { return m_nb_cell; }
101
102 void setNodesCoordinates() const
103 {
104 Int32 nb_node = m_nodes_coordinates.size();
105 UniqueArray<Int64> unique_ids(nb_node);
106 for (Integer i = 0; i < nb_node; ++i)
107 unique_ids[i] = i;
108 UniqueArray<Int32> local_ids(nb_node);
109 IItemFamily* node_family = m_mesh->nodeFamily();
110 node_family->itemsUniqueIdToLocalId(local_ids, unique_ids);
111
112 VariableNodeReal3& mesh_nodes_coordinates(m_mesh->nodesCoordinates());
113 NodeInfoListView nodes(node_family);
114
115 for (Integer i = 0; i < nb_node; ++i) {
116 Node node{ nodes[local_ids[i]] };
117 mesh_nodes_coordinates[node] = m_nodes_coordinates[i];
118 }
119 }
120
121 private:
122
123 using CoordMap = std::map<Real3, Int32, Real3Compare>;
124
125 IMesh* m_mesh = nullptr;
126 CoordMap m_nodes_coord_map;
127 Int32 m_nb_cell = 0;
128 UniqueArray<Int64> m_cells_infos;
131};
132
133/*---------------------------------------------------------------------------*/
134/*---------------------------------------------------------------------------*/
135
136/*---------------------------------------------------------------------------*/
137/*---------------------------------------------------------------------------*/
138
139namespace
140{
141 void
142 _buildCellNodesCoordinates(Real pitch, Real x, Real y, Real z, ArrayView<Real3> coords)
143 {
144 Real p = 0.5 * pitch;
145 Real q = 0.5 * pitch / (math::sqrt(3.0));
146 coords[0] = { x - q, y - p, z };
147 coords[1] = { x + q, y - p, z };
148 coords[2] = { x + 2 * q, y, z };
149 coords[3] = { x + q, y + p, z };
150 coords[4] = { x - q, y + p, z };
151 coords[5] = { x - 2 * q, y, z };
152 }
153
154} // namespace
155
156/*---------------------------------------------------------------------------*/
157/*---------------------------------------------------------------------------*/
158
160{
161 public:
162
163 CellLineInfo(Real2 first_center, Int32 nb_cell)
164 : m_first_center(first_center)
165 , m_nb_cell(nb_cell)
166 {}
167
168 public:
169
170 Real2 m_first_center;
171 Int32 m_nb_cell;
172};
173
174/*---------------------------------------------------------------------------*/
175/*---------------------------------------------------------------------------*/
176
177HoneyComb2DMeshGenerator::
178HoneyComb2DMeshGenerator(IPrimaryMesh* mesh)
180, m_mesh(mesh)
181{
182}
183
184/*---------------------------------------------------------------------------*/
185/*---------------------------------------------------------------------------*/
186
187void HoneyComb2DMeshGenerator::
188_buildCells()
189{
190 // In parallel, only rank 0 builds the mesh
191 IParallelMng* pm = m_mesh->parallelMng();
192 if (pm->commRank() == 0)
193 _buildCells2();
194 else {
195 m_mesh->setDimension(2);
196 m_mesh->allocateCells(0, Int64ConstArrayView(), true);
197 }
198}
199
200/*---------------------------------------------------------------------------*/
201/*---------------------------------------------------------------------------*/
202
203void HoneyComb2DMeshGenerator::
204_buildCells2()
205{
206 SimpleSequentialMeshBuilder simple_mesh_builder(m_mesh);
207
208 const Real pitch = m_pitch;
209 const Integer nb_ring = m_nb_ring;
210
211 info() << "Build Hexagonal 2D Cells nb_layer=" << nb_ring;
212
213 UniqueArray<Real3> cell_nodes_coords(6);
214 UniqueArray<CellLineInfo> cells_line_info;
215
216 // u1, u2 and u3 are the directional vectors following the
217 // directions of the hexagon
218 Real2 u1(0.5 * pitch * math::sqrt(3.0), -0.5 * pitch);
219 Real2 u2(0.5 * pitch * math::sqrt(3.0), 0.5 * pitch);
220 Real2 u3(pitch * 0.0, pitch * 1.0);
221
222 // Cells above the center
223 for (Integer i = (-nb_ring + 1); i < 1; ++i) {
224 Real x0 = u3[0] * i - u1[0] * (nb_ring - 1);
225 Real y0 = u3[1] * i - u1[1] * (nb_ring - 1);
226 Real2 pos(x0, y0);
227 pos += m_origin;
228 Integer nb_cell_in_line = 2 * nb_ring - 1 + i;
229 cells_line_info.add(CellLineInfo(pos, nb_cell_in_line));
230 }
231
232 // Cells below the center
233 for (Integer i = 1; i < nb_ring; ++i) {
234 Real x0{ u2[0] * i - u1[0] * (nb_ring - 1) };
235 Real y0{ u2[1] * i - u1[1] * (nb_ring - 1) };
236 Real2 pos(x0, y0);
237 pos += m_origin;
238 Integer nb_cell_in_line = 2 * nb_ring - 1 - i;
239 cells_line_info.add(CellLineInfo(pos, nb_cell_in_line));
240 }
241
242 for (const CellLineInfo& cli : cells_line_info) {
243 Real2 xy = cli.m_first_center;
244 for (Integer j = 0, n = cli.m_nb_cell; j < n; ++j) {
245 _buildCellNodesCoordinates(m_pitch, xy.x, xy.y, 0.0, cell_nodes_coords);
246 simple_mesh_builder.addCell(IT_Hexagon6, cell_nodes_coords);
247 xy += u1;
248 }
249 }
250
251 m_mesh->setDimension(2);
252 m_mesh->allocateCells(simple_mesh_builder.nbCell(), simple_mesh_builder.cellsInfos(), true);
253
254 simple_mesh_builder.setNodesCoordinates();
255}
256
257/*---------------------------------------------------------------------------*/
258/*---------------------------------------------------------------------------*/
259
260void HoneyComb2DMeshGenerator::
261generateMesh(Real2 origin, Real pitch, Integer nb_ring)
262{
263 m_pitch = pitch;
264 m_nb_ring = nb_ring;
265 m_origin = origin;
266 _buildCells();
267}
268
269/*---------------------------------------------------------------------------*/
270/*---------------------------------------------------------------------------*/
271
275class HoneyComb2DMeshGeneratorService
277{
278 public:
279
280 explicit HoneyComb2DMeshGeneratorService(const ServiceBuildInfo& sbi)
282 {}
283
284 public:
285
286 void fillMeshBuildInfo(MeshBuildInfo& build_info) override
287 {
288 build_info.addNeedPartitioning(true);
289 }
291 {
292 info() << "HoneyComb2DMeshGenerator: allocateMeshItems()";
294 Real pitch = options()->pitchSize();
295 Integer nb_layer = options()->nbLayer();
296 if (pitch <= 0.0)
297 ARCANE_FATAL("Invalid valid value '{0}' for pitch (should be > 0.0)", pitch);
298 if (nb_layer <= 0)
299 ARCANE_FATAL("Invalid valid value '{0}' for 'nb-layer' (should be > 0)", nb_layer);
300 g.generateMesh(options()->origin(), pitch, nb_layer);
301 }
302
303 private:
304};
305
306/*---------------------------------------------------------------------------*/
307/*---------------------------------------------------------------------------*/
308
309ARCANE_REGISTER_SERVICE_HONEYCOMB2DMESHGENERATOR(HoneyComb2D, HoneyComb2DMeshGeneratorService);
310
311/*---------------------------------------------------------------------------*/
312/*---------------------------------------------------------------------------*/
313
314/*---------------------------------------------------------------------------*/
315/*---------------------------------------------------------------------------*/
316
319{
320 public:
321
322 CellLineInfo(Real2 first_center, Real bottom, Real top, Int32 nb_cell)
323 : m_first_center(first_center)
324 , m_bottom(bottom)
325 , m_top(top)
326 , m_nb_cell(nb_cell)
327 {}
328
329 public:
330
331 Real2 m_first_center;
332 Real m_bottom;
333 Real m_top;
334 Int32 m_nb_cell;
335};
336
337/*---------------------------------------------------------------------------*/
338/*---------------------------------------------------------------------------*/
339
340HoneyComb3DMeshGenerator::
341HoneyComb3DMeshGenerator(IPrimaryMesh* mesh)
343, m_mesh(mesh)
344{
345}
346
347/*---------------------------------------------------------------------------*/
348/*---------------------------------------------------------------------------*/
349
350void HoneyComb3DMeshGenerator::
351generateMesh(Real2 origin, Real pitch, Integer nb_ring, ConstArrayView<Real> heights)
352{
353 m_pitch = pitch;
354 m_nb_ring = nb_ring;
355 m_origin = origin;
356 m_heights = heights;
357
358 // Check that we have the correct number of values and that they are increasing
359 const Integer nb_height = m_heights.size();
360 if (nb_height < 2)
361 ARCANE_FATAL("Bad number of heights '{0}' (minimum=2)", nb_height);
362 for (Integer i = 0; i < (nb_height - 1); ++i)
363 if (m_heights[i] > m_heights[i + 1])
364 ARCANE_FATAL("Heights are not increasing ({0} < {1})", m_heights[i], m_heights[i + 1]);
365
366 _buildCells();
367}
368
369/*---------------------------------------------------------------------------*/
370/*---------------------------------------------------------------------------*/
371
372void HoneyComb3DMeshGenerator::
373_buildCells()
374{
375 // In parallel, only rank 0 builds the mesh
376 IParallelMng* pm = m_mesh->parallelMng();
377 if (pm->commRank() == 0)
378 _buildCells2();
379 else {
380 m_mesh->setDimension(3);
381 m_mesh->allocateCells(0, Int64ConstArrayView(), true);
382 }
383}
384
385/*---------------------------------------------------------------------------*/
386/*---------------------------------------------------------------------------*/
387
388void HoneyComb3DMeshGenerator::
389_buildCells2()
390{
391 SimpleSequentialMeshBuilder simple_mesh_builder(m_mesh);
392
393 const Real pitch = m_pitch;
394 const Integer nb_ring = m_nb_ring;
395 const Integer nb_height = m_heights.size();
396 if (nb_height < 2)
397 ARCANE_FATAL("Bad number of heights '{0}' (minimum=2)", nb_height);
398 info() << "Build Hexagonal 3D Cells nb_layer=" << nb_ring << " nb_height=" << nb_height;
399
400 UniqueArray<Real3> cell_nodes_coords(12);
401 UniqueArray<CellLineInfo> cells_line_info;
402
403 // u1, u2 and u3 are the directional vectors following the
404 // directions of the hexagon
405 Real2 u1(0.5 * pitch * math::sqrt(3.0), -0.5 * pitch);
406 Real2 u2(0.5 * pitch * math::sqrt(3.0), 0.5 * pitch);
407 Real2 u3(pitch * 0.0, pitch * 1.0);
408
409 for (Integer zz = 0; zz < (nb_height - 1); ++zz) {
410 // Cells above the center
411 for (Integer i = (-nb_ring + 1); i < 1; ++i) {
412 Real x0 = u3[0] * i - u1[0] * (nb_ring - 1);
413 Real y0 = u3[1] * i - u1[1] * (nb_ring - 1);
414 Real2 pos(x0, y0);
415 pos += m_origin;
416 Integer nb_cell_in_line = 2 * nb_ring - 1 + i;
417 cells_line_info.add(CellLineInfo(pos, m_heights[zz], m_heights[zz + 1], nb_cell_in_line));
418 }
419
420 // Cells below the center
421 for (Integer i = 1; i < nb_ring; ++i) {
422 Real x0{ u2[0] * i - u1[0] * (nb_ring - 1) };
423 Real y0{ u2[1] * i - u1[1] * (nb_ring - 1) };
424 Real2 pos(x0, y0);
425 pos += m_origin;
426 Integer nb_cell_in_line = 2 * nb_ring - 1 - i;
427 cells_line_info.add(CellLineInfo(pos, m_heights[zz], m_heights[zz + 1], nb_cell_in_line));
428 }
429 }
430
431 for (const CellLineInfo& cli : cells_line_info) {
432 Real2 xy = cli.m_first_center;
433 for (Integer j = 0, n = cli.m_nb_cell; j < n; ++j) {
434 _buildCellNodesCoordinates(m_pitch, xy.x, xy.y, cli.m_bottom, cell_nodes_coords.subView(0, 6));
435 _buildCellNodesCoordinates(m_pitch, xy.x, xy.y, cli.m_top, cell_nodes_coords.subView(6, 6));
436 simple_mesh_builder.addCell(IT_Octaedron12, cell_nodes_coords);
437 xy += u1;
438 }
439 }
440
441 m_mesh->setDimension(3);
442 m_mesh->allocateCells(simple_mesh_builder.nbCell(), simple_mesh_builder.cellsInfos(), true);
443
444 simple_mesh_builder.setNodesCoordinates();
445}
446
447/*---------------------------------------------------------------------------*/
448/*---------------------------------------------------------------------------*/
449
453class HoneyComb3DMeshGeneratorService
455{
456 public:
457
458 explicit HoneyComb3DMeshGeneratorService(const ServiceBuildInfo& sbi)
460 {}
461
462 public:
463
464 void fillMeshBuildInfo(MeshBuildInfo& build_info) override
465 {
466 build_info.addNeedPartitioning(true);
467 }
469 {
470 info() << "HoneyComb2DMeshGenerator: allocateMeshItems()";
472 Real pitch = options()->pitchSize();
473 Integer nb_layer = options()->nbLayer();
474 ConstArrayView<Real> heights = options()->heights();
475 Integer nb_height = heights.size();
476 if (pitch <= 0.0)
477 ARCANE_FATAL("Invalid valid value '{0}' for pitch (should be > 0.0)", pitch);
478 if (nb_layer <= 0)
479 ARCANE_FATAL("Invalid valid value '{0}' for 'nb-layer' (should be > 0)", nb_layer);
480 if (nb_height <= 2)
481 ARCANE_FATAL("Invalid valid value '{0}' for 'nb-height' (should be >= 2)", nb_height);
482 g.generateMesh(options()->origin(), pitch, nb_layer, heights);
483 }
484
485 private:
486};
487
488/*---------------------------------------------------------------------------*/
489/*---------------------------------------------------------------------------*/
490
491ARCANE_REGISTER_SERVICE_HONEYCOMB3DMESHGENERATOR(HoneyComb3D, HoneyComb3DMeshGeneratorService);
492
493/*---------------------------------------------------------------------------*/
494/*---------------------------------------------------------------------------*/
495
496} // End namespace Arcane
497
498/*---------------------------------------------------------------------------*/
499/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Integer size() const
Number of elements in the vector.
CaseOptionsHoneyComb2DMeshGenerator * options() const
Options du jeu de données du service.
ArcaneHoneyComb2DMeshGeneratorObject(const Arcane::ServiceBuildInfo &sbi)
Constructeur.
ArcaneHoneyComb3DMeshGeneratorObject(const Arcane::ServiceBuildInfo &sbi)
Constructeur.
CaseOptionsHoneyComb3DMeshGenerator * options() const
Options du jeu de données du service.
Modifiable view of an array of type T.
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.
void fillMeshBuildInfo(MeshBuildInfo &build_info) override
Fills build_info with the necessary information to create the mesh.
void allocateMeshItems(IPrimaryMesh *pm) override
Allocates the mesh entities managed by this service.
void allocateMeshItems(IPrimaryMesh *pm) override
Allocates the mesh entities managed by this service.
void fillMeshBuildInfo(MeshBuildInfo &build_info) override
Fills build_info with the necessary information to create the mesh.
virtual IParallelMng * parallelMng()=0
Parallelism manager.
Interface of the parallelism manager for a subdomain.
virtual Int32 commRank() const =0
Rank of this instance in the communicator.
virtual void allocateCells(Integer nb_cell, Int64ConstArrayView cells_infos, bool one_alloc=true)=0
Allocation of a mesh.
virtual void setDimension(Integer dim)=0
Positions the mesh dimension (1D, 2D, or 3D).
Parameters necessary for building a mesh.
MeshBuildInfo & addNeedPartitioning(bool v)
Indicates whether the generator needs to call a partitioner.
Class managing a 2-dimensional real vector.
Definition Real2.h:122
Class managing a 3-dimensional real vector.
Definition Real3.h:132
Structure containing the information to create a service.
UniqueArray< Real3 > m_nodes_coordinates
uid->coord correspondence for nodes
Int32 addNode(Real3 coord)
Adds or retrieves the uniqueId() of the node with coordinates coord.
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
TraceMessage info() const
Flow for an information message.
ITraceMng * traceMng() const
Trace manager.
1D data vector with value semantics (STL style).
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Coordinate type quantity at node.
__host__ __device__ double sqrt(double v)
Square root of v.
Definition Math.h:142
constexpr __host__ __device__ bool isNearlyEqualWithEpsilon(const _Type &a, const _Type &b, const _Type &epsilon)
Tests if two values are approximately equal. For integer types, this function is equivalent to IsEqua...
Definition Numeric.h:242
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Int32 Integer
Type representing an integer.
ConstArrayView< Int64 > Int64ConstArrayView
C equivalent of a 1D array of 64-bit integers.
Definition UtilsTypes.h:480
double Real
Type representing a real number.
std::int32_t Int32
Signed integer type of 32 bits.
Real y
second component of the triplet
Definition Real3.h:36
Real z
third component of the triplet
Definition Real3.h:37
Real x
first component of the triplet
Definition Real3.h:35