14#include "arcane/utils/PlatformUtils.h"
15#include "arcane/utils/NotImplementedException.h"
16#include "arcane/utils/ITraceMng.h"
17#include "arcane/utils/FixedArray.h"
18#include "arcane/utils/SmallArray.h"
20#include "arcane/core/IParallelMng.h"
21#include "arcane/core/IPrimaryMesh.h"
22#include "arcane/core/IMeshUtilities.h"
23#include "arcane/core/IMeshPartitioner.h"
24#include "arcane/core/IItemFamily.h"
25#include "arcane/core/ItemVector.h"
28#include "arcane/core/IMeshPartitionConstraintMng.h"
29#include "arcane/impl/ArcaneGeometricMeshPartitionerService_axl.h"
31#include "arcane_internal_config.h"
75 constexpr int nb_value = 3;
80 for (
int i = (nb_value - 1); i >= 0; --i) {
90 _deflateMatrix(matrix, result.eigen_value, result.eigen_vector);
101 static void _deflateMatrix(
Real3x3& matrix,
double eigenvalue,
Real3 eigenvector)
103 for (
int i = 0; i < 3; ++i) {
104 for (
int j = 0; j < 3; ++j) {
105 matrix[i][j] -= eigenvalue * eigenvector[i] * eigenvector[j];
111 static PowerResult _applyPowerIteration(
const Real3x3& matrix)
113 constexpr Int32 max_iteration = 1000;
114 constexpr Real tolerance = 1e-16;
115 Real eigenvalue = 0.0;
118 Real3 b{ 1.0, 1.0, 1.0 };
122 for (
Int32 iter = 0; iter < max_iteration; ++iter) {
125 eigenvalue = b_next.normL2();
126 if (math::isNearlyZero(eigenvalue))
128 b_next = b_next / eigenvalue;
132 if (diff < tolerance) {
139 return { eigenvalue, b_next };
199 friend std::ostream& operator<<(std::ostream& o,
const TreeNode& t)
201 o <<
"(index=" << t.
index <<
" level=" << t.
level
219 void doPartition(Int32 nb_part)
221 m_tree_info.resize(nb_part);
225 Int32 parent_index = -1;
227 _doRecursivePart(0, part_id, sum, parent_index, level);
228 for (
const TreeNode& t : m_tree_info) {
243 Int32 part0_partition_index = partition_index;
244 Int32 part1_partition_index = partition_index + 1;
246 Int32 nb_child_left = 0;
247 Int32 nb_child_right = 0;
249 Int32 next_left = (2 * partition_index) + 1;
250 Int32 next_right = (2 * partition_index) + 2;
252 m_tree_info[part0_partition_index].parent_index = parent_index;
254 if ((next_left + 1) < m_nb_part) {
255 m_tree_info[part0_partition_index].left_child_index = next_left;
256 _doRecursivePart(next_left, part_id, nb_child_left,
257 part0_partition_index, level + 1);
260 info() <<
"DO_PART LEFT parent=" << parent_index <<
" ID=" << part_id
261 <<
" nb_child=" << nb_child <<
" nb_child_left=" << nb_child_left;
262 m_tree_info[part0_partition_index].left_partition_id = part_id;
266 if ((next_right + 1) < m_nb_part) {
267 m_tree_info[part0_partition_index].right_child_index = next_right;
268 _doRecursivePart(next_right, part_id, nb_child_right,
269 part1_partition_index, level + 1);
272 info() <<
"DO_PART RIGHT parent=" << parent_index <<
" ID=" << part_id
273 <<
" nb_child" << nb_child <<
" nb_child_right=" << nb_child_right;
274 m_tree_info[part0_partition_index].right_partition_id = part_id;
278 nb_child += (nb_child_left + nb_child_right);
279 info() <<
"End for me parent=" << parent_index
280 <<
" part0_index=" << part0_partition_index
281 <<
" nb_child_left=" << nb_child_left <<
" nb_child_right=" << nb_child_right
282 <<
" level=" << level;
283 m_tree_info[part0_partition_index].nb_left_child = nb_child_left;
284 m_tree_info[part0_partition_index].nb_right_child = nb_child_right;
285 m_tree_info[part0_partition_index].level = level;
286 m_tree_info[part0_partition_index].index = part0_partition_index;
332class ArcaneGeometricMeshPartitionerService
338 explicit ArcaneGeometricMeshPartitionerService(
const ServiceBuildInfo& sbi);
342 IMesh*
mesh()
const override {
return BasicService::mesh(); }
347 _partitionMesh(initial_partition, nb_part);
355 Real maximumComputationTime()
const override {
return m_max_computation_time; }
367 m_cells_weight = weights;
368 m_nb_weight = nb_weight;
383 Real m_imbalance = 0.0;
384 Real m_max_imbalance = 0.0;
385 Real m_max_computation_time = 0.0;
386 Int32 m_nb_weight = 0;
387 ArrayView<float> m_cells_weight;
388 UniqueArray<Real> m_computation_times;
394 Real3x3 _computeInertiaTensor(Real3 center,
const VariableCellReal3& cells_center,
396 Real3 _findPrincipalAxis(Real3x3 tensor);
397 void _partitionMesh2();
398 void _partitionMesh(
bool initial_partition, Int32 nb_part);
401 void _partitionMeshRecursive2(ConstArrayView<BinaryTree::TreeNode> tree_nodes,
const VariableCellReal3& cells_center,
404 Real3 _computeEigenValuesAndVectors(ITraceMng* tm, Real3x3 tensor, Real3x3& eigen_vectors, Real3& eigen_values);
410ArcaneGeometricMeshPartitionerService::
420Real3 ArcaneGeometricMeshPartitionerService::
426 center += cells_center[icell];
428 Int64 local_nb_cell = cells.size();
430 if (total_nb_cell == 0)
433 Real3 global_center = sum_center /
static_cast<Real>(total_nb_cell);
434 return global_center;
443Real3x3 ArcaneGeometricMeshPartitionerService::
451 Real3 cell_coord = cells_center[icell];
452 double dx = cell_coord.x - center.x;
453 double dy = cell_coord.y - center.y;
454 double dz = cell_coord.z - center.z;
456 tensor[0][0] += dy * dy + dz * dz;
457 tensor[1][1] += dx * dx + dz * dz;
458 tensor[2][2] += dx * dx + dy * dy;
459 tensor[0][1] -= dx * dy;
460 tensor[0][2] -= dx * dz;
461 tensor[1][2] -= dy * dz;
466 sum_tensor[1][0] = sum_tensor[0][1];
467 sum_tensor[2][0] = sum_tensor[0][2];
468 sum_tensor[2][1] = sum_tensor[1][2];
479Real3 ArcaneGeometricMeshPartitionerService::
480_findPrincipalAxis(
Real3x3 tensor)
482 info() <<
"Tensor=" << tensor;
484 EigenValueAndVectorComputer eigen_computer;
485 eigen_computer.computeForMatrix(tensor);
486 info() <<
"EigenValues = " << eigen_computer.eigenValues();
487 info() <<
"EigenVectors = " << eigen_computer.eigenVectors();
488 Real3x3 eigen_vectors = eigen_computer.eigenVectors();
489 Real3 v = eigen_vectors[0];
493 if (math::isNearlyZero(v.normL2())) {
494 v = eigen_vectors[1];
495 if (math::isNearlyZero(v.normL2()))
496 v = eigen_vectors[2];
498 info() <<
"EigenVector=" << v;
506void ArcaneGeometricMeshPartitionerService::
512 CellVector cells_vector(cell_family, cell_family->allItems().own().view().localIds());
515 info() <<
"** ** DO_PARTITION_MESH2 nb_cell=" << cells.size();
522 for (NodeLocalId n : icell->nodeIds())
523 c += nodes_coordinates[n];
524 cells_center[icell] = c / icell->nbNode();
529 binary_tree.doPartition(m_nb_part);
534 info() <<
"Using geoemtric partitioner do_new?=" << do_new;
536 _partitionMeshRecursive2(binary_tree.tree(), cells_center, cells, 0);
539 Int32 partition_index = 0;
541 _partitionMeshRecursive(cells_center, cells, partition_index, part_id);
548bool ArcaneGeometricMeshPartitionerService::
552 Int32 part0_partition_index = partition_index;
553 Int32 part1_partition_index = partition_index + 1;
556 info() <<
"Doing partition partition_index=" << partition_index <<
" total_nb_cell=" << total_nb_cell;
557 if (part1_partition_index >= m_nb_part)
560 info() <<
"Doing partition really partition_index=" << partition_index;
565 Real3 center = _computeBarycenter(cells_center, cells);
566 info() <<
"GlobalCenter=" << center;
569 Real3x3 tensor = _computeInertiaTensor(center, cells_center, cells);
572 Real3 eigenvector = _findPrincipalAxis(tensor);
573 info() <<
"EigenVector=" << eigenvector;
575 const Int32 nb_cell = cells.size();
576 UniqueArray<Int32> part0_cells;
577 part0_cells.reserve(nb_cell);
578 UniqueArray<Int32> part1_cells;
579 part1_cells.reserve(nb_cell);
585 info() <<
"Doing partition setting nb_cell=" << nb_cell <<
" partition=" << part0_partition_index <<
" " << part1_partition_index;
587 const Real3 cell_coord = cells_center[icell];
589 Real projection = 0.0;
590 projection += (cell_coord.x - center.x) * eigenvector.x;
591 projection += (cell_coord.y - center.y) * eigenvector.y;
592 projection += (cell_coord.z - center.z) * eigenvector.z;
594 if (projection < 0.0) {
595 part0_cells.add(icell.itemLocalId());
598 part1_cells.add(icell.itemLocalId());
607 if (_partitionMeshRecursive(cells_center, part0, (2 * partition_index) + 1, part_id)) {
608 info() <<
"Filling left part part_index=" << part_id <<
" nb_cell=" << part0.size();
610 cells_new_owner[icell] = part_id;
614 if (_partitionMeshRecursive(cells_center, part1, (2 * partition_index) + 2, part_id)) {
615 info() <<
"Filling right part part_index=" << part_id <<
" nb_cell=" << part1.size();
617 cells_new_owner[icell] = part_id;
627void ArcaneGeometricMeshPartitionerService::
632 Int32 part0_partition_index = partition_index;
633 Int32 part1_partition_index = partition_index + 1;
637 info() <<
"Doing partition (V2) partition_index=" << partition_index <<
" total_nb_cell=" << total_nb_cell;
639 info() <<
"Doing partition (V2) really partition_index=" << partition_index;
644 Real3 center = _computeBarycenter(cells_center, cells);
645 info() <<
"GlobalCenter=" << center;
648 Real3x3 tensor = _computeInertiaTensor(center, cells_center, cells);
651 Real3 eigenvector = _findPrincipalAxis(tensor);
652 info() <<
"EigenVector=" << eigenvector;
654 const Int32 nb_cell = cells.size();
659 info() <<
"Doing partition (V2) nb_cell=" << nb_cell <<
" setting partition=" << part0_partition_index <<
" " << part1_partition_index;
660 UniqueArray<Real> projections(nb_cell);
661 Real min_projection = std::numeric_limits<Real>::max();
662 Real max_projection = std::numeric_limits<Real>::min();
664 const Real3 cell_coord = cells_center[icell];
665 Real projection =
math::dot(cell_coord - center, eigenvector);
666 projections[icell.index()] = projection;
667 min_projection =
math::min(min_projection, projection);
668 max_projection =
math::max(max_projection, projection);
675 info() <<
"min_projection=" << min_projection <<
" max_projection=" << max_projection;
683 UniqueArray<Real> projections_to_test;
688 const int total_nb_to_test = (2 * nb_to_test) + 1;
689 projections_to_test.resize(total_nb_to_test);
690 for (
Int32 i = 0; i < nb_to_test; ++i) {
691 Real v1 = min_projection / (i + 1);
692 projections_to_test[i] = v1;
693 Real v2 = max_projection / (nb_to_test - i);
694 projections_to_test[i + 1 + nb_to_test] = v2;
696 projections_to_test[nb_to_test] = 0.0;
697 info() <<
"projections_to_test=" << projections_to_test;
702 BinaryTree::TreeNode current_tree_node = tree_nodes[partition_index];
703 Int32 nb_left_child = current_tree_node.nb_left_child;
704 Int32 nb_right_child = current_tree_node.nb_right_child;
706 Real expected_ratio = 1.0;
707 if (nb_left_child != 0) {
708 Real r_nb_left_child =
static_cast<Real>(nb_left_child);
709 Real r_nb_right_child =
static_cast<Real>(nb_right_child);
710 expected_ratio = r_nb_left_child / (r_nb_left_child + r_nb_right_child);
717 SmallArray<Int64> global_nb_parts(total_nb_to_test * 2);
722 Int32 wanted_projection_index = 0;
723 Real best_partition_ratio = std::numeric_limits<Real>::max();
724 for (
Int32 z = 0; z < total_nb_to_test; ++z) {
725 Int32 nb_new_part0 = 0;
726 Int32 nb_new_part1 = 0;
727 const Real projection_to_test = projections_to_test[z];
730 Real projection = projections[icell.index()];
731 if (projection < projection_to_test)
736 global_nb_parts[0 + (z * 2)] = nb_new_part0;
737 global_nb_parts[1 + (z * 2)] = nb_new_part1;
743 for (
Int32 z = 0; z < total_nb_to_test; ++z) {
745 Int64 nb_part0 = global_nb_parts[0 + (z * 2)];
746 Int64 nb_part1 = global_nb_parts[1 + (z * 2)];
748 Real r_nb_part0 =
static_cast<Real>(nb_part0);
749 Real r_nb_part1 =
static_cast<Real>(nb_part1);
750 ratio_0 = r_nb_part0 / (r_nb_part0 + r_nb_part1);
752 Real diff_ratio = math::abs(expected_ratio - ratio_0);
753 info(4) <<
"Partition info nb_part0=" << nb_part0 <<
" nb_part1=" << nb_part1
754 <<
" ratio_0=" << ratio_0
755 <<
" nb_left_child=" << nb_left_child <<
" nb_right_child=" << nb_right_child
756 <<
" expected_ratio=" << expected_ratio
757 <<
" diff_ratio=" << diff_ratio
758 <<
" best_ratio=" << best_partition_ratio;
759 if (diff_ratio < best_partition_ratio) {
760 wanted_projection_index = z;
761 best_partition_ratio = diff_ratio;
765 const Real projection_to_use = projections_to_test[wanted_projection_index];
766 info() <<
"Keep projection index=" << wanted_projection_index <<
" projection=" << projection_to_use
767 <<
" best_ratio=" << best_partition_ratio;
769 UniqueArray<Int32> part0_cells;
770 part0_cells.reserve(nb_cell);
771 UniqueArray<Int32> part1_cells;
772 part1_cells.reserve(nb_cell);
780 Real projection = projections[icell.index()];
781 if (projection < projection_to_use) {
782 part0_cells.add(icell.itemLocalId());
785 part1_cells.add(icell.itemLocalId());
792 Int32 child_left = current_tree_node.left_child_index;
793 if (child_left >= 0) {
794 _partitionMeshRecursive2(tree_nodes, cells_center, part0, child_left);
796 Int32 left_partition_id = current_tree_node.left_partition_id;
797 if (left_partition_id >= 0) {
798 info() <<
"Filling left part part_index=" << left_partition_id <<
" nb_cell=" << part0.size();
800 cells_new_owner[icell] = left_partition_id;
803 Int32 child_right = current_tree_node.right_child_index;
804 if (child_right >= 0) {
805 _partitionMeshRecursive2(tree_nodes, cells_center, part1, child_right);
808 Int32 right_partition_id = current_tree_node.right_partition_id;
809 if (right_partition_id >= 0) {
810 info() <<
"Filling right part part_index=" << right_partition_id <<
" nb_cell=" << part1.size();
812 cells_new_owner[icell] = right_partition_id;
820void ArcaneGeometricMeshPartitionerService::
821_partitionMesh([[maybe_unused]]
bool initial_partition,
Int32 nb_part)
827 info() <<
"Doing mesh partition with ArcaneGeometricMeshPartitionerService nb_part=" << nb_part;
828 IParallelMng* pm =
mesh->parallelMng();
829 Int32 nb_rank = pm->commSize();
838 cells_new_owner.synchronize();
839 if (
mesh->partitionConstraintMng()) {
841 mesh->partitionConstraintMng()->computeAndApplyConstraints();
843 mesh->utilities()->changeOwnersFromCells();
849void ArcaneGeometricMeshPartitionerService::
854 for (
Int32 i = 0; i < m_nb_part; ++i) {
857 if (cells_new_owner[icell] == i)
870 _partitionMesh(initial_partition,
mesh()->parallelMng()->commSize());
876#if ARCANE_DEFAULT_PARTITIONER == ARCANEGEOMETRICMESHPARTITIONER_DEFAULT_PARTITIONER
877ARCANE_REGISTER_SERVICE_ARCANEGEOMETRICMESHPARTITIONERSERVICE(DefaultPartitioner,
880ARCANE_REGISTER_SERVICE_ARCANEGEOMETRICMESHPARTITIONERSERVICE(ArcaneGeometricMeshPartitioner,
#define ARCANE_THROW(exception_class,...)
Macro for throwing an exception with formatting.
Various mathematical functions.
Generation de la classe de base du Service.
ArcaneArcaneGeometricMeshPartitionerServiceObject(const Arcane::ServiceBuildInfo &sbi)
Constructeur.
Mesh geometric partitioning service.
void setImbalance(Real v) override
Sets the computation time imbalance.
void setComputationTimes(RealConstArrayView v) override
Computation time of this subdomain. The first element indicates the computation time of the subdomain...
void setMaxImbalance(Real v) override
Sets the maximum allowed imbalance.
void build() override
Build-level construction of the service.
void notifyEndPartition() override
Notification when a re-partitioning finishes (after entity exchange).
IMesh * mesh() const override
Mesh associated with the partitioner.
Real imbalance() const override
Computation time imbalance.
void partitionMesh(bool initial_partition) override
void setILoadBalanceMng(ILoadBalanceMng *) override
Changes the ILoadBalanceMng to use.
Real maxImbalance() const override
Maximum allowed imbalance.
void setCellsWeight(ArrayView< float > weights, Integer nb_weight) override
Allows defining the weights of objects to be partitioned: ILoadBalanceMng must now be used.
void setMaximumComputationTime(Real v) override
Sets the proportion of computation time.
Modifiable view of an array of type T.
Class to create a binary tree.
ConstArrayView< TreeNode > tree() const
List of tree nodes.
Constant view of an array of type T.
Class to calculate the eigenvalues and eigenvectors of a matrix.
Real3 m_eigen_values
Eigenvalues.
Real3x3 m_eigen_vectors
Eigenvectors.
Real3x3 eigenVectors() const
Returns the eigenvectors of the matrix in ascending order.
Real3 eigenValues() const
Returns the eigenvalues of the matrix in ascending order.
void computeForMatrix(const Real3x3 &orig_matrix)
Calculates the eigenvalues and eigenvectors of orig_matrix.
Interface for registering variables for load balancing.
virtual IItemFamily * cellFamily()=0
Returns the cell family.
Interface of a mesh partitioner.
virtual VariableNodeReal3 & nodesCoordinates()=0
Node coordinates.
virtual IParallelMng * parallelMng()=0
Parallelism manager.
virtual IPrimaryMesh * toPrimaryMesh()=0
Returns the instance in the form of an IPrimaryMesh.
virtual char reduce(eReduceType rt, char v)=0
Performs a reduction of type rt on the real v and returns the value.
virtual VariableItemInt32 & itemsNewOwner(eItemKind kind)=0
Variable containing the identifier of the owning subdomain.
CellGroup ownCells() const
Returns the group containing all cells specific to this domain.
Exception when a function is not implemented.
Class managing a 3-dimensional real vector.
Class managing a 3x3 real matrix.
Structure containing the information to create a service.
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).
__host__ __device__ Real dot(Real2 u, Real2 v)
Dot product of u by v in .
__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.
ItemVectorT< Cell > CellVector
Vector of cells.
ItemVectorViewT< Cell > CellVectorView
View over a vector of cells.
MeshVariableScalarRefT< Cell, Real3 > VariableCellReal3
Coordinate type quantity at cell center.
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Coordinate type quantity at node.
ItemVariableScalarRefT< Int32 > VariableItemInt32
32-bit integer type quantity
@ ReduceSum
Sum of values.
@ ReduceMin
Minimum of values.
@ ReduceMax
Maximum of values.
constexpr __host__ __device__ Real squareNormL2(const Real2 &v)
Returns the squared norm of the pair $ .
__host__ __device__ Real3 multiply(const Real3x3 &m, Real3 v)
3x3 matrix multiplied by a vector.
-- 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.
@ IK_Cell
Cell mesh entity.
double Real
Type representing a real number.
@ Cell
The mesh is AMR by cell.
std::int32_t Int32
Signed integer type of 32 bits.
ConstArrayView< Real > RealConstArrayView
C equivalent of a 1D array of reals.
Information about a tree node.
Int32 nb_right_child
Number of children on the right (if not terminal).
Int32 level
Level in the tree.
Int32 index
Linear index in the tree.
Int32 right_partition_id
Index of the right partition (only for terminal nodes).
Int32 left_partition_id
Index of the left partition (only for terminal nodes).
Int32 parent_index
Index in the tree of the parent (-1 if none).
Int32 left_child_index
Linear index of the left child (-1 if none).
Int32 nb_left_child
Number of children on the left (if not terminal).
Int32 right_child_index
Linear index of the right child (-1 if none).
Result of applying the power method.