14#include "arcane/cartesianmesh/CartesianMeshCoarsening2.h"
16#include "arcane/utils/FatalErrorException.h"
17#include "arcane/utils/ValueConvert.h"
18#include "arcane/utils/SmallArray.h"
20#include "arcane/core/IMesh.h"
21#include "arcane/core/ItemGroup.h"
22#include "arcane/core/IParallelMng.h"
23#include "arcane/core/CartesianGridDimension.h"
24#include "arcane/core/IMeshModifier.h"
25#include "arcane/core/SimpleSVGMeshExporter.h"
26#include "arcane/core/ItemPrinter.h"
27#include "arcane/core/MeshStats.h"
28#include "arcane/core/IGhostLayerMng.h"
30#include "arcane/mesh/CellFamily.h"
32#include "arcane/cartesianmesh/ICartesianMesh.h"
33#include "arcane/cartesianmesh/CellDirectionMng.h"
34#include "arcane/cartesianmesh/internal/ICartesianMeshInternal.h"
36#include <unordered_set>
47CartesianMeshCoarsening2::
52 if (
auto v = Convert::Type<Int32>::tryParseFromEnvironment(
"ARCANE_CARTESIANMESH_COARSENING_VERBOSITY_LEVEL",
true))
53 m_verbosity_level = v.value();
75void CartesianMeshCoarsening2::
76_writeMeshSVG(
const String& name)
78 if (m_verbosity_level <= 0)
81 if (
mesh->dimension() != 2)
85 String filename = String::format(
"mesh_{0}_{1}.svg", name, mesh_rank);
86 info() <<
"WriteMesh name=" << filename;
87 std::ofstream ofile(filename.
localstr());
89 writer.write(
mesh->allCells());
99void CartesianMeshCoarsening2::
100_doDoubleGhostLayers()
118 m_cartesian_mesh->computeDirections();
121 _writeMeshSVG(
"double_ghost");
127void CartesianMeshCoarsening2::
130 if (m_is_create_coarse_called)
132 m_is_create_coarse_called =
true;
134 const bool is_verbose = m_verbosity_level > 0;
137 Integer nb_patch = m_cartesian_mesh->nbPatch();
139 ARCANE_FATAL(
"This method is only valid for 1 patch (nb_patch={0})", nb_patch);
141 if (!
mesh->isAmrActivated())
145 if (nb_dir != 2 && nb_dir != 3)
146 ARCANE_FATAL(
"This method is only valid for 2D or 3D mesh (dim={0})", nb_dir);
148 info() <<
"CoarseCartesianMesh nb_direction=" << nb_dir;
150 for (
Integer idir = 0; idir < nb_dir; ++idir) {
153 info() <<
"NB_OWN_CELL dir=" << idir <<
" n=" << nb_own_cell;
154 if ((nb_own_cell % 2) != 0)
155 ARCANE_FATAL(
"Invalid number of cells ({0}) for direction {1}. Should be a multiple of 2",
159 _writeMeshSVG(
"orig");
172 for (
Int32 i = 0; i < nb_node; ++i)
174 info() <<
"Orig cell_uid=" << cell.
uniqueId() <<
" Nodes=" << uids;
177 for (
Int32 i = 0; i < nb_face; ++i)
179 info() <<
"Orig cell_uid=" << cell.
uniqueId() <<
" Faces=" << uids;
190 m_first_own_cell_unique_id_offset = coarse_grid_cell_offset;
191 info() <<
"FirstCellUniqueIdOffset=" << m_first_own_cell_unique_id_offset;
194 else if (nb_dir == 2)
199 mesh->modifier()->endUpdate();
220 m_cartesian_mesh->_internalApi()->addPatchFromExistingChildren(parent_cells.
view().
localIds());
227 mesh->computeSynchronizeInfos();
231 m_cartesian_mesh->computeDirections();
233 _writeMeshSVG(
"coarse");
239void CartesianMeshCoarsening2::
240_createCoarseCells2D()
242 const bool is_verbose = m_verbosity_level > 0;
267 Int32 nb_coarse_face = 0;
268 Int32 nb_coarse_cell = 0;
279 Int64x3 cell_xy = refined_cell_uid_computer.compute(cell_uid);
280 const Int64 cell_x = cell_xy.x;
281 const Int64 cell_y = cell_xy.y;
287 if ((cell_x % 2) != 0 || (cell_y % 2) != 0)
290 info() <<
"CellToCoarse refined_uid=" << cell_uid <<
" x=" << cell_x <<
" y=" << cell_y;
291 coarse_cells_owner.
add(cell.
owner());
292 const Int64 coarse_cell_x = cell_x / 2;
293 const Int64 coarse_cell_y = cell_y / 2;
294 std::array<Int64, 4> node_uids_container;
296 node_uids[0] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 0);
297 node_uids[1] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 0);
298 node_uids[2] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 2);
299 node_uids[3] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 2);
301 info() <<
"CELLNodes uid=" << node_uids;
302 std::array<Int64, 4> coarse_face_uids = coarse_face_uid_computer.
computeForCell(coarse_cell_x, coarse_cell_y);
305 for (
Int32 z = 0; z < 4; ++z) {
307 faces_infos.
add(IT_Line2);
308 faces_infos.
add(coarse_face_uids[z]);
309 Int64 node_uid0 = node_uids[lface.
node(0)];
310 Int64 node_uid1 = node_uids[lface.
node(1)];
312 if (node_uid0 > node_uid1)
313 std::swap(node_uid0, node_uid1);
315 info() <<
"ADD_FACE coarse_uid=" << coarse_face_uids[z] <<
" n0=" << node_uid0 <<
" n1=" << node_uid1;
316 faces_infos.
add(node_uid0);
317 faces_infos.
add(node_uid1);
322 cells_infos.
add(IT_Quad4);
323 Int64 coarse_cell_uid = coarse_cell_uid_computer.compute(coarse_cell_x, coarse_cell_y);
324 cells_infos.
add(coarse_cell_uid);
326 info() <<
"CoarseCellUid=" << coarse_cell_uid;
328 for (
Int32 z = 0; z < 4; ++z)
329 cells_infos.
add(node_uids[z]);
331 first_child_cells.
add(cell);
336 std::array<Int32, 4> sub_cell_lids_container;
338 Cell cell1 = cdm_x[cell].next();
345 Cell cell2 = cdm_y[cell1].next();
348 Cell cell3 = cdm_y[cell].next();
363 for (
Int32 i = 0; i < 4; ++i)
364 refined_cells_lids.
add(sub_lids[i]);
370 mesh->modifier()->addFaces(nb_coarse_face, faces_infos, faces_local_ids);
378 mesh->modifier()->addCells(add_cells_args);
387 std::array<Int32, 4> sub_cell_lids_container;
389 for (
Int32 i = 0; i < nb_coarse_cell; ++i) {
390 Int32 coarse_cell_lid = cells_local_ids[i];
391 Cell coarse_cell = cells[coarse_cell_lid];
392 Cell first_child_cell = first_child_cells[i];
395 sub_cell_lids[0] = first_child_cell.
localId();
396 sub_cell_lids[1] = cdm_x[first_child_cell].next().localId();
397 sub_cell_lids[2] = cdm_y[CellLocalId(sub_cell_lids[1])].next().localId();
398 sub_cell_lids[3] = cdm_y[first_child_cell].next().localId();
400 info() <<
"AddChildForCoarseCell i=" << i <<
" coarse=" <<
ItemPrinter(coarse_cell)
401 <<
" children_lid=" << sub_cell_lids;
402 for (
Int32 z = 0; z < 4; ++z) {
403 Cell child_cell = cells[sub_cell_lids[z]];
405 info() <<
" AddParentCellToCell: z=" << z <<
" child=" <<
ItemPrinter(child_cell);
406 true_cell_family->_addParentCellToCell(child_cell, coarse_cell);
408 true_cell_family->_addChildrenCellsToCell(coarse_cell, sub_cell_lids);
417 Int32 owner = coarse_cells_owner[index];
419 const Int64 sub_cell_index = index * 4;
420 for (
Int32 z = 0; z < 4; ++z) {
433void CartesianMeshCoarsening2::
434_createCoarseCells3D()
436 const bool is_verbose = m_verbosity_level > 0;
463 Int32 nb_coarse_face = 0;
464 Int32 nb_coarse_cell = 0;
472 static constexpr Int32 const_cell_nb_node = 8;
473 static constexpr Int32 const_cell_nb_face = 6;
474 static constexpr Int32 const_cell_nb_sub_cell = 8;
475 static constexpr Int32 const_face_nb_node = 4;
484 Int64x3 cell_xyz = refined_cell_uid_computer.
compute(cell_uid);
485 const Int64 cell_x = cell_xyz.x;
486 const Int64 cell_y = cell_xyz.y;
487 const Int64 cell_z = cell_xyz.z;
493 if ((cell_x % 2) != 0 || (cell_y % 2) != 0 || (cell_z % 2) != 0)
496 info() <<
"CellToCoarse refined_uid=" << cell_uid <<
" x=" << cell_x <<
" y=" << cell_y <<
" z=" << cell_z;
497 coarse_cells_owner.
add(cell.
owner());
498 const Int64 coarse_cell_x = cell_x / 2;
499 const Int64 coarse_cell_y = cell_y / 2;
500 const Int64 coarse_cell_z = cell_z / 2;
501 std::array<Int64, const_cell_nb_node> node_uids_container;
503 node_uids[0] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 0, cell_z + 0);
504 node_uids[1] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 0, cell_z + 0);
505 node_uids[2] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 2, cell_z + 0);
506 node_uids[3] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 2, cell_z + 0);
507 node_uids[4] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 0, cell_z + 2);
508 node_uids[5] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 0, cell_z + 2);
509 node_uids[6] = refined_node_uid_computer.compute(cell_x + 2, cell_y + 2, cell_z + 2);
510 node_uids[7] = refined_node_uid_computer.compute(cell_x + 0, cell_y + 2, cell_z + 2);
512 info() <<
"CELLNodes uid=" << node_uids;
513 std::array<Int64, const_cell_nb_face> coarse_face_uids = coarse_face_uid_computer.
computeForCell(coarse_cell_x, coarse_cell_y, coarse_cell_z);
517 for (
Int32 z = 0; z < const_cell_nb_face; ++z) {
519 faces_infos.
add(IT_Quad4);
520 faces_infos.
add(coarse_face_uids[z]);
521 for (
Int32 knode = 0; knode < const_face_nb_node; ++knode)
522 face_node_uids[knode] = node_uids[lface.
node(knode)];
525 info() <<
"ADD_FACE coarse_uid=" << coarse_face_uids[z] <<
" n=" << face_sorted_node_uids;
526 faces_infos.
addRange(face_sorted_node_uids);
532 cells_infos.
add(IT_Hexaedron8);
533 Int64 coarse_cell_uid = coarse_cell_uid_computer.
compute(coarse_cell_x, coarse_cell_y, coarse_cell_z);
534 cells_infos.
add(coarse_cell_uid);
536 info() <<
"CoarseCellUid=" << coarse_cell_uid;
538 for (
Int32 z = 0; z < const_cell_nb_node; ++z)
539 cells_infos.
add(node_uids[z]);
541 first_child_cells.
add(cell);
548 std::array<Int32, const_cell_nb_sub_cell> sub_cell_lids_container;
550 Cell cell1 = cdm_x[cell].next();
557 Cell cell2 = cdm_y[cell1].next();
560 Cell cell3 = cdm_y[cell].next();
564 Cell cell4 = cdm_z[cell].next();
568 Cell cell5 = cdm_x[cell4].next();
571 Cell cell6 = cdm_y[cell5].next();
574 Cell cell7 = cdm_y[cell4].next();
598 for (
Int32 i = 0; i < const_cell_nb_sub_cell; ++i)
599 refined_cells_lids.
add(sub_lids[i]);
605 mesh->modifier()->addFaces(nb_coarse_face, faces_infos, faces_local_ids);
613 mesh->modifier()->addCells(add_cells_args);
622 std::array<Int32, const_cell_nb_sub_cell> sub_cell_lids_container;
624 for (
Int32 i = 0; i < nb_coarse_cell; ++i) {
625 Int32 coarse_cell_lid = cells_local_ids[i];
626 Cell coarse_cell = cells[coarse_cell_lid];
627 Cell first_child_cell = first_child_cells[i];
630 sub_cell_lids[0] = first_child_cell.
localId();
631 sub_cell_lids[1] = cdm_x[first_child_cell].next().localId();
632 sub_cell_lids[2] = cdm_y[CellLocalId(sub_cell_lids[1])].next().localId();
633 sub_cell_lids[3] = cdm_y[first_child_cell].next().localId();
635 Cell top_first_child_cell = cdm_z[first_child_cell].next();
636 sub_cell_lids[4] = top_first_child_cell.
localId();
637 sub_cell_lids[5] = cdm_x[top_first_child_cell].next().localId();
638 sub_cell_lids[6] = cdm_y[CellLocalId(sub_cell_lids[5])].next().localId();
639 sub_cell_lids[7] = cdm_y[top_first_child_cell].next().localId();
642 info() <<
"AddChildForCoarseCell i=" << i <<
" coarse=" <<
ItemPrinter(coarse_cell)
643 <<
" children_lid=" << sub_cell_lids;
644 for (
Int32 z = 0; z < const_cell_nb_sub_cell; ++z) {
645 Cell child_cell = cells[sub_cell_lids[z]];
647 info() <<
" AddParentCellToCell: z=" << z <<
" child=" <<
ItemPrinter(child_cell);
648 true_cell_family->_addParentCellToCell(child_cell, coarse_cell);
650 true_cell_family->_addChildrenCellsToCell(coarse_cell, sub_cell_lids);
659 Int32 owner = coarse_cells_owner[index];
661 const Int64 sub_cell_index = index * const_cell_nb_face;
662 for (
Int32 z = 0; z < const_cell_nb_face; ++z) {
678void CartesianMeshCoarsening2::
679_recomputeMeshGenerationInfo()
682 auto* cmgi = ICartesianMeshGenerationInfo::getReference(
mesh,
false);
691 cmgi->setOwnCellOffsets(v[0] / cf, v[1] / cf, v[2] / cf);
695 cmgi->setGlobalNbCells(v[0] / cf, v[1] / cf, v[2] / cf);
699 cmgi->setOwnNbCells(v[0] / cf, v[1] / cf, v[2] / cf);
701 cmgi->setFirstOwnCellUniqueId(m_first_own_cell_unique_id_offset);
707void CartesianMeshCoarsening2::
710 if (!m_is_create_coarse_called)
711 ARCANE_FATAL(
"You need to call createCoarseCells() before");
712 if (m_is_remove_refined_called)
714 m_is_remove_refined_called =
true;
716 const bool is_verbose = m_verbosity_level > 0;
721 info() <<
"RemoveRefinedCells nb_coarse_cell=" << m_coarse_cells_uid.size();
723 info() <<
"CoarseCells=" << m_coarse_cells_uid;
727 std::unordered_set<Int64> coarse_cells_set;
728 for (
Int64 cell_uid : m_coarse_cells_uid)
729 coarse_cells_set.insert(cell_uid);
732 Int32 local_id = icell.itemLocalId();
734 if (coarse_cells_set.find(cell.
uniqueId()) == coarse_cells_set.end())
735 cells_to_remove.
add(local_id);
738 info() <<
"CellsToRemove n=" << cells_to_remove.
size() <<
" list=" << cells_to_remove;
749 MeshStats ms(traceMng(), mesh, mesh->
parallelMng());
754 m_cartesian_mesh->computeDirections();
#define ARCANE_CHECK_POINTER(ptr)
Macro returning the pointer ptr if it is not null or throwing an exception if it is null.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
bool reorderNodesOfFace(Int64ConstArrayView before_ids, Int64ArrayView after_ids)
Reorders the nodes of a face.
Integer size() const
Number of elements in the vector.
Modifiable view of an array of type T.
void addRange(ConstReferenceType val, Int64 n)
Adds n elements of value val to the end of the array.
void resize(Int64 s)
Changes the number of elements in the array to s.
void add(ConstReferenceType val)
Adds element val to the end of the array.
Class for calculating the uniqueId() of a cell in 2D based on its position in the grid.
Class for calculating the uniqueId() of a cell in 3D based on its position in the grid.
Int64 compute(Int64 x, Int64 y, Int64 z)
Calculates the uniqueId() based on coordinates.
Class for calculating the uniqueId() of a face in 2D based on its position in the grid.
std::array< Int64, 4 > computeForCell(Int64 x, Int64 y)
Calculates the uniqueIds() of the 4 faces of the topological coordinate cell (x,y).
Class for calculating the uniqueId() of a face in 2D based on its position in the grid.
std::array< Int64, 6 > computeForCell(Int64 x, Int64 y, Int64 z)
Calculates the uniqueIds() of the 6 faces of the topological coordinate cell (x,y,...
Class for calculating the uniqueId() of a node in 2D based on its position in the grid.
Class for calculating the uniqueId() of a node in 3D based on its position in the grid.
Information about the dimensions of a Cartesian grid.
CellUniqueIdComputer2D getCellComputer2D(Int64 offset) const
Instance to calculate the uniqueIds() of cells for this grid.
CellUniqueIdComputer3D getCellComputer3D(Int64 offset) const
Instance to calculate the uniqueIds() of cells for this grid.
FaceUniqueIdComputer3D getFaceComputer3D(Int64 offset) const
Instance to calculate the uniqueIds() of faces for this grid.
NodeUniqueIdComputer3D getNodeComputer3D(Int64 offset) const
Instance to calculate the uniqueIds() of nodes for this grid.
NodeUniqueIdComputer2D getNodeComputer2D(Int64 offset) const
Instance to calculate the uniqueIds() of nodes for this grid.
FaceUniqueIdComputer2D getFaceComputer2D(Int64 offset) const
Instance to calculate the uniqueIds() of faces for this grid.
void _doDoubleGhostLayers()
Doubles the ghost layer of the initial mesh.
void _createCoarseCells3D()
Int64 _getMaxUniqueId(const ItemGroup &group)
Returns the max of uniqueId() of entities in a group.
void _recomputeMeshGenerationInfo()
Recalculates the information about the number of cells per direction.
UniqueArray< Int64 > m_coarse_cells_uid
uniqueId() of the coarse cells
void _createCoarseCells2D()
Info about the cells in a specific X, Y, or Z direction of a structured mesh.
Int64 globalNbCell() const
Global number of cells in this direction.
Int32 ownNbCell() const
Number of own cells in this direction.
View of cell information.
Face face(Int32 i) const
i-th face of the cell
Int32 nbFace() const
Number of faces of the cell.
Constant view of an array of type T.
Interface of a Cartesian mesh.
virtual void setBuilderVersion(Integer n)=0
Sets the version of the ghost cell builder. For now (version 3.3), the possible values are 2,...
virtual Integer nbGhostLayer() const =0
Number of ghost layers.
virtual Integer builderVersion() const =0
Ghost cell builder version.
virtual void setNbGhostLayer(Integer n)=0
Sets the number of ghost layers.
Interface of an entity family.
virtual void notifyItemsOwnerChanged()=0
Notifies that the entities specific to the family's subdomain have been modified.
virtual ItemVectorView view(Int32ConstArrayView local_ids)=0
View on the entities.
Mesh modification interface.
virtual void updateGhostLayers()=0
Updates the ghost layer.
virtual void setDynamic(bool v)=0
Sets the property indicating whether the mesh can evolve.
virtual void removeCells(Int32ConstArrayView cells_local_id)=0
Removes cells.
virtual void endUpdate()=0
Notifies the instance that mesh modification is finished.
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 char reduce(eReduceType rt, char v)=0
Performs a reduction of type rt on the real v and returns the value.
@ II_JustRefined
The entity has just been refined.
ItemVectorView view() const
View of the group entities.
Utility class for printing information about an entity.
Local information about a cell face.
Integer node(Integer i) const
Local index in the cell of the i-th node of the face.
Info on a mesh entity type.
LocalFace localFace(Integer id) const
Local connectivity of the i-th face of the cell.
Int32ConstArrayView localIds() const
Array of local IDs of entities.
Node node(Int32 i) const
i-th node of the entity
Int32 nbNode() const
Number of nodes of the entity.
Base class for a mesh element.
const ItemTypeInfo * typeInfo() const
Information about the entity type.
impl::MutableItemBase mutableItemBase() const
Mutable internal part of the entity.
constexpr Int32 localId() const
Local identifier of the entity in the processor subdomain.
Int32 owner() const
Owner subdomain number of the entity.
ItemUniqueId uniqueId() const
Unique identifier across all domains.
constexpr bool null() const
true if the entity is null (i.e. not connected to the mesh)
Arguments for IMeshModifier::addCells().
void setAllowBuildFaces(bool v)
Indicates whether associated faces are allowed to be built.
void dumpStats() override
Prints mesh information.
void setOwner(Integer suid, Int32 current_sub_domain)
Sets the sub-domain number of the entity owner.
void addFlags(Int32 added_flags)
Adds the flags added_flags to those of the entity.
1D data array with pre-allocated stack buffer.
Unicode character string.
const char * localstr() const
Returns the conversion of the instance into UTF-8 encoding.
TraceMessage info() const
Flow for an information message.
ITraceMng * traceMng() const
Trace manager.
1D data vector with value semantics (STL style).
T max(const T &a, const T &b, const T &c)
Returns the maximum of three elements.
ItemGroupT< Cell > CellGroup
Group of cells.
@ ReduceMax
Maximum of values.
-- 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.
std::int32_t Int32
Signed integer type of 32 bits.