14#include "arcane/utils/NotSupportedException.h"
15#include "arcane/utils/PlatformUtils.h"
16#include "arcane/utils/ScopedPtr.h"
18#include "arcane/core/IGridMeshPartitioner.h"
19#include "arcane/core/BasicService.h"
20#include "arcane/core/IPrimaryMesh.h"
22#include "arcane/core/IParallelMng.h"
23#include "arcane/core/ItemPrinter.h"
24#include "arcane/core/IExtraGhostCellsBuilder.h"
25#include "arcane/core/IMeshPartitionConstraintMng.h"
26#include "arcane/core/IMeshUtilities.h"
27#include "arcane/core/IMeshModifier.h"
28#include "arcane/core/IItemFamily.h"
45class SimpleGridMeshPartitioner
61 class GhostCellsBuilder
74 for (
const auto& v : m_ghost_cell_uids) {
76 Int32 nb_ghost = v.second.size();
78 local_ids.
resize(nb_ghost);
79 m_mesh->cellFamily()->itemsUniqueIdToLocalId(local_ids, v.second);
85 auto x = m_ghost_cell_local_ids.find(rank);
86 if (x == m_ghost_cell_local_ids.end())
91 std::map<Int32, UniqueArray<ItemUniqueId>> m_ghost_cell_uids;
92 std::map<Int32, UniqueArray<Int32>> m_ghost_cell_local_ids;
101 Int32 m_nb_direction = 0;
102 Int32 m_offset_y = 0;
103 Int32 m_offset_z = 0;
123 m_is_bounding_box_set =
true;
140 std::array<Int32, 3> m_ijk_part;
141 bool m_is_bounding_box_set =
false;
142 bool m_is_ijk_set =
false;
143 bool m_is_verbose =
false;
144 GhostCellsBuilder* m_ghost_cells_builder =
nullptr;
150 void _addGhostCell(
Int32 rank,
Cell cell);
151 void _buildGridInfo();
152 void _computeSpecificGhostLayer();
159SimpleGridMeshPartitioner::
160SimpleGridMeshPartitioner(
const ServiceBuildInfo& sbi)
181 if (position < coords[0])
186 for (
Int32 z = 0; z < nb_value; ++z) {
188 info() <<
" z=" << z <<
" coord=" << coords[z] <<
" part=" << part_id;
189 if (position > coords[z])
196 part_id = (nb_value - 1);
204void SimpleGridMeshPartitioner::
207 m_ghost_cells_builder->m_ghost_cell_uids[rank].add(cell.
uniqueId());
213void SimpleGridMeshPartitioner::
216 m_grid_info =
new GridInfo();
218 if (!m_is_bounding_box_set)
219 ARCANE_FATAL(
"Bounding box is not set. call method setBoundingBox() before");
221 ARCANE_FATAL(
"Part index is not set. call method setPartIndex() before");
224 const Int32 dimension = mesh->
dimension();
226 IParallelMng* pm = mesh->parallelMng();
230 std::array<Int32, 3> nb_part_by_direction_buf = { 0, 0, 0 };
231 ArrayView<Int32> nb_part_by_direction(3, nb_part_by_direction_buf.data());
232 for (
Integer i = 0; i < 3; ++i)
233 if (m_ijk_part[i] >= 0)
234 nb_part_by_direction[i] = m_ijk_part[i] + 1;
236 auto& nb_direction = m_grid_info->m_nb_direction;
239 if (nb_part_by_direction[2] > 0)
241 else if (nb_part_by_direction[1] > 0)
244 ARCANE_THROW(NotImplementedException,
"SimpleGridMeshPartitioner for 1D mesh");
246 if (nb_direction != dimension)
247 ARCANE_FATAL(
"Invalid number of direction: mesh_dimension={0} nb_direction={1}", dimension, nb_direction);
250 info() <<
"NB_DIRECTION=" << nb_direction <<
" NB_PART=" << nb_part_by_direction;
253 const Real min_value = -FloatInfo<Real>::maxValue();
254 auto& grid_coord = m_grid_info->m_grid_coord;
256 grid_coord.resize(nb_direction);
257 grid_coord.resize(nb_direction);
258 for (
Integer i = 0; i < nb_direction; ++i)
259 grid_coord[i].resize(nb_part_by_direction[i], min_value);
261 for (
Integer i = 0; i < nb_direction; ++i) {
262 Int32 index = m_ijk_part[i];
264 grid_coord[i][index] = m_min_box[i];
266 for (
Integer i = 0; i < nb_direction; ++i) {
268 info() <<
"GRID_COORD dir=" << i <<
" V=" << grid_coord[i];
272 for (
Integer i = 0; i < nb_direction; ++i) {
273 ConstArrayView<Real> coords(grid_coord[0].view());
274 Int32 nb_value = coords.size();
277 for (
Int32 z = 0; z < (nb_value - 1); ++z)
278 if (coords[z] > coords[z + 1])
279 ARCANE_FATAL(
"Grid coord '{0}' is not sorted: {1} > {2}", i, coords[z], coords[z + 1]);
282 m_grid_info->m_offset_y = (nb_direction >= 2) ? nb_part_by_direction[0] : 0;
283 m_grid_info->m_offset_z = (nb_direction == 3) ? (nb_part_by_direction[0] * nb_part_by_direction[1]) : 0;
292 if (m_grid_info.get())
293 ARCANE_FATAL(
"partitionMesh() has already been called. Only one call par SimpleGridMeshPartitioner instance is allowed");
303 const Int32 offset_y = m_grid_info->m_offset_y;
304 const Int32 offset_z = m_grid_info->m_offset_z;
305 const Int32 nb_direction = m_grid_info->m_nb_direction;
311 std::array<Int32, 3> cell_part = { -1, -1, -1 };
314 for (
Integer inode = 0; inode < nb_node; ++inode)
315 cell_center += nodes_coord[cell.
node(inode)];
316 cell_center /=
static_cast<Real>(nb_node);
318 for (
Integer idir = 0; idir < nb_direction; ++idir) {
320 Real cc = cell_center[idir];
323 info() <<
" Cell uid=" << cell.
uniqueId() <<
" idir=" << idir <<
" cc=" << cc;
328 const Int32 new_owner = cell_part[0] + cell_part[1] * offset_y + cell_part[2] * offset_z;
330 info() <<
"CELL=" <<
ItemPrinter(cell) <<
" coord=" << cell_center <<
" new_owner=" << new_owner
331 <<
" dir=" << cell_part[0] <<
" " << cell_part[1] <<
" " << cell_part[2];
332 if (new_owner < 0 || new_owner >= nb_rank)
333 ARCANE_FATAL(
"Bad value for new owner cell={0} new_owner={1} (max={2})",
ItemPrinter(cell), new_owner, nb_rank);
334 cells_new_owner[icell] = new_owner;
337 cells_new_owner.synchronize();
338 if (
mesh->partitionConstraintMng()) {
340 mesh->partitionConstraintMng()->computeAndApplyConstraints();
342 mesh->utilities()->changeOwnersFromCells();
355 const Int32 offset_y = m_grid_info->m_offset_y;
356 const Int32 offset_z = m_grid_info->m_offset_z;
359 for (
Integer k0 = 0, maxk0 = nb_part[0]; k0 < maxk0; ++k0)
360 for (
Integer k1 = 0, maxk1 = nb_part[1]; k1 < maxk1; ++k1)
361 for (
Integer k2 = 0, maxk2 = nb_part[2]; k2 < maxk2; ++k2) {
362 Int32 p0 = min_part[0] + k0;
363 Int32 p1 = min_part[1] + k1;
364 Int32 p2 = min_part[2] + k2;
365 Int32 owner = p0 + (p1 * offset_y) + (p2 * offset_z);
367 if (owner != cell_owner)
368 _addGhostCell(owner, cell);
375void SimpleGridMeshPartitioner::
376_computeSpecificGhostLayer()
378 if (!m_grid_info.get())
379 ARCANE_FATAL(
"partitionMesh() has to be called before this method.");
384 const Int32 nb_direction = m_grid_info->m_nb_direction;
389 std::array<Int32, 3> min_part = { -1, -1, -1 };
390 std::array<Int32, 3> max_part = { -1, -1, -1 };
391 std::array<Int32, 3> nb_node_part = { 1, 1, 1 };
394 Real max_value = FloatInfo<Real>::maxValue();
395 Real min_value = -max_value;
396 Real3 min_box(max_value, max_value, max_value);
397 Real3 max_box(min_value, min_value, min_value);
398 for (Node node : cell.
nodes()) {
399 Real3 pos = nodes_coord[node];
404 for (
Integer idir = 0; idir < nb_direction; ++idir) {
405 ConstArrayView<Real> coords(m_grid_info->m_grid_coord[idir].view());
406 Integer nb_coord = coords.size();
408 const Real min_pos = min_box[idir];
409 const Real max_pos = max_box[idir];
414 info() <<
" Cell uid=" << cell.
uniqueId() <<
" idir=" << idir
415 <<
" min_pos=" << min_pos <<
" max_pos=" << max_pos
416 <<
" min_part=" << min_part_id <<
" max_part_id=" << max_part_id;
425 min_part[idir] = min_part_id;
426 max_part[idir] = max_part_id;
429 Int32 total_nb_part = 1;
430 for (
Integer idir = 0; idir < nb_direction; ++idir) {
431 Int32 nb_part = 1 + (max_part[idir] - min_part[idir]);
432 nb_node_part[idir] = nb_part;
433 total_nb_part *= nb_part;
437 info() <<
" Cell uid=" << cell.
uniqueId() <<
" min_part=" << ArrayView<Int32>(min_part)
438 <<
" max_part=" << ArrayView<Int32>(max_part)
439 <<
" nb_part=" << ArrayView<Int32>(nb_node_part)
440 <<
" total=" << total_nb_part;
446 info() <<
"GHOST_CELLS_TO_SEND";
447 for (
const auto& v : m_ghost_cells_builder->m_ghost_cell_uids) {
448 info() <<
"RANK=" << v.first <<
" ids=" << v.second;
460 if (
mesh != this->mesh())
461 ARCANE_FATAL(
"mesh argument should be the same mesh that the one used to create this instance");
463 if (m_ghost_cells_builder)
464 ARCANE_FATAL(
"Only one call to this method is allower per instance.");
466 mesh->modifier()->setDynamic(
true);
467 mesh->utilities()->partitionAndExchangeMeshWithReplication(
this,
true);
470 m_ghost_cells_builder = scoped_builder.
get();
471 mesh->modifier()->addExtraGhostCellsBuilder(m_ghost_cells_builder);
474 _computeSpecificGhostLayer();
475 mesh->modifier()->updateGhostLayers();
477 mesh->modifier()->removeExtraGhostCellsBuilder(m_ghost_cells_builder);
479 m_ghost_cells_builder =
nullptr;
#define ARCANE_THROW(exception_class,...)
Macro for throwing an exception with formatting.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
This file contains the various service factories and macros for registering services.
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro to declare an interface when registering a service.
void resize(Int64 s)
Changes the number of elements in the array to s.
Constant view of an array of type T.
constexpr Integer size() const noexcept
Number of elements in the array.
Interface of a mesh partitioner on a grid.
virtual Integer dimension()=0
Mesh dimension (1D, 2D, or 3D).
virtual IPrimaryMesh * toPrimaryMesh()=0
Returns the instance in the form of an IPrimaryMesh.
Interface of the parallelism manager for a subdomain.
virtual Int32 commSize() const =0
Number of instances in the communicator.
Utility class for printing information about an entity.
Node node(Int32 i) const
i-th node of the entity
NodeConnectedListViewType nodes() const
List of nodes of the entity.
Int32 nbNode() const
Number of nodes of the entity.
Int32 owner() const
Owner subdomain number of the entity.
ItemUniqueId uniqueId() const
Unique identifier across all domains.
T * get() const
Returns the object referenced by the instance.
Class managing a 3-dimensional real vector.
Encapsulation of an automatically destructing pointer.
Structure containing the information to create a service.
Service creation properties.
Information about extra ghost cells.
Int32ConstArrayView extraCellsToSend(Int32 rank) const override
Local indices of "extraordinary" cells for sending.
void computeExtraCellsToSend() override
Calculates the "extraordinary" cells to send.
void setPartIndex(Int32 i, Int32 j, Int32 k) override
Index (i,j,k) of the part.
void build() override
Build-level construction of the service.
void notifyEndPartition() override
Notification when a re-partitioning finishes (after entity exchange).
void _addCellToIntersectedParts(Cell cell, std::array< Int32, 3 > min_part, std::array< Int32, 3 > nb_part)
IPrimaryMesh * primaryMesh() override
Associated mesh.
Int32 _findPart(RealConstArrayView coords, Real center)
Returns the index in coords of the value immediately lower than position.
void setBoundingBox(Real3 min_val, Real3 max_val) override
Positions the bounding box of our subdomain.
void applyMeshPartitioning(IMesh *mesh) override
Applies the repartitioning to the mesh mesh.
void partitionMesh(bool initial_partition) override
TraceMessage info() const
Flow for an information message.
1D data vector with value semantics (STL style).
__host__ __device__ Real2 min(Real2 a, Real2 b)
Returns the minimum of two Real2.
T max(const T &a, const T &b, const T &c)
Returns the maximum of three elements.
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro for registering a service.
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Coordinate type quantity at node.
ItemVariableScalarRefT< Int32 > VariableItemInt32
32-bit integer type quantity
@ ReduceMax
Maximum of values.
constexpr __host__ __device__ bool isNearlyEqual(const _Type &a, const _Type &b)
Tests if two values are approximately equal. For integer types, this function is equivalent to IsEqua...
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Int32 Integer
Type representing an integer.
ConstArrayView< Int32 > Int32ConstArrayView
C equivalent of a 1D array of 32-bit integers.
@ ST_SubDomain
The service is used at the subdomain level.
@ IK_Cell
Cell mesh entity.
double Real
Type representing a real number.
std::int32_t Int32
Signed integer type of 32 bits.
ConstArrayView< Real > RealConstArrayView
C equivalent of a 1D array of reals.