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;
81 for (
int i = (nb_value - 1); i >= 0; --i) {
91 _deflateMatrix(matrix, result.eigen_value, result.eigen_vector);
102 static void _deflateMatrix(
Real3x3& matrix,
double eigenvalue,
Real3 eigenvector)
104 for (
int i = 0; i < 3; ++i) {
105 for (
int j = 0; j < 3; ++j) {
106 matrix[i][j] -= eigenvalue * eigenvector[i] * eigenvector[j];
112 static PowerResult _applyPowerIteration(
const Real3x3& matrix)
114 constexpr Int32 max_iteration = 1000;
115 constexpr Real tolerance = 1e-16;
116 Real eigenvalue = 0.0;
119 Real3 b{ 1.0, 1.0, 1.0 };
123 for (
Int32 iter = 0; iter < max_iteration; ++iter) {
126 eigenvalue = b_next.normL2();
127 if (math::isNearlyZero(eigenvalue))
129 b_next = b_next / eigenvalue;
133 if (diff < tolerance) {
140 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;
334class ArcaneGeometricMeshPartitionerService
340 explicit ArcaneGeometricMeshPartitionerService(
const ServiceBuildInfo& sbi);
344 IMesh*
mesh()
const override {
return BasicService::mesh(); }
349 _partitionMesh(initial_partition, nb_part);
357 Real maximumComputationTime()
const override {
return m_max_computation_time; }
369 m_cells_weight = weights;
370 m_nb_weight = nb_weight;
385 Real m_imbalance = 0.0;
386 Real m_max_imbalance = 0.0;
387 Real m_max_computation_time = 0.0;
388 Int32 m_nb_weight = 0;
389 ArrayView<float> m_cells_weight;
390 UniqueArray<Real> m_computation_times;
396 Real3x3 _computeInertiaTensor(Real3 center,
const VariableCellReal3& cells_center,
398 Real3 _findPrincipalAxis(Real3x3 tensor);
399 void _partitionMesh2();
400 void _partitionMesh(
bool initial_partition, Int32 nb_part);
403 void _partitionMeshRecursive2(ConstArrayView<BinaryTree::TreeNode> tree_nodes,
const VariableCellReal3& cells_center,
406 Real3 _computeEigenValuesAndVectors(ITraceMng* tm, Real3x3 tensor, Real3x3& eigen_vectors, Real3& eigen_values);
412ArcaneGeometricMeshPartitionerService::
422Real3 ArcaneGeometricMeshPartitionerService::
428 center += cells_center[icell];
430 Int64 local_nb_cell = cells.size();
432 if (total_nb_cell == 0)
435 Real3 global_center = sum_center /
static_cast<Real>(total_nb_cell);
436 return global_center;
444Real3x3 ArcaneGeometricMeshPartitionerService::
452 Real3 cell_coord = cells_center[icell];
453 double dx = cell_coord.x - center.x;
454 double dy = cell_coord.y - center.y;
455 double dz = cell_coord.z - center.z;
457 tensor[0][0] += dy * dy + dz * dz;
458 tensor[1][1] += dx * dx + dz * dz;
459 tensor[2][2] += dx * dx + dy * dy;
460 tensor[0][1] -= dx * dy;
461 tensor[0][2] -= dx * dz;
462 tensor[1][2] -= dy * dz;
467 sum_tensor[1][0] = sum_tensor[0][1];
468 sum_tensor[2][0] = sum_tensor[0][2];
469 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 pour envoyer une exception avec formattage.
Fonctions mathématiques diverses.
Generation de la classe de base du Service.
ArcaneArcaneGeometricMeshPartitionerServiceObject(const Arcane::ServiceBuildInfo &sbi)
Constructeur.
Service de partitionnement géométrique de maillage.
void setImbalance(Real v) override
Positionne le déséquilibre de temps de calcul.
void setComputationTimes(RealConstArrayView v) override
Temps de calcul de se sous-domaine. Le premier élément indique le temps de calcul du sous-domaine cor...
void setMaxImbalance(Real v) override
Positionne le déséquilibre maximal autorisé
void build() override
Construction de niveau build du service.
void notifyEndPartition() override
Notification lors de la fin d'un re-partitionnement (après échange des entités)
IMesh * mesh() const override
Maillage associé au partitionneur.
Real imbalance() const override
Déséquilibre de temps de calcul.
void partitionMesh(bool initial_partition) override
void setILoadBalanceMng(ILoadBalanceMng *) override
Change le ILoadBalanceMng à utiliser.
Real maxImbalance() const override
Déséquilibre maximal autorisé
void setCellsWeight(ArrayView< float > weights, Integer nb_weight) override
Permet de définir les poids des objets à partitionner : on doit utiliser le ILoadBalanceMng maintenan...
void setMaximumComputationTime(Real v) override
Positionne la proportion du temps de calcul.
Vue modifiable d'un tableau d'un type T.
Classe pour créer un arbre binaire.
ConstArrayView< TreeNode > tree() const
Liste des noeuds de l'arbre.
Vue constante d'un tableau de type T.
Classe pour calculer les valeurs et vecteurs propres d'une matrice.
Real3 m_eigen_values
Valeurs propres.
Real3x3 m_eigen_vectors
Vecteurs propres.
Real3x3 eigenVectors() const
Retourne les vecteurs propres de la matrice par ordre croissant.
Real3 eigenValues() const
Retourne les valeurs propres de la matrice par ordre croissant.
void computeForMatrix(const Real3x3 &orig_matrix)
Calcule les valeurs et vecteurs propres de orig_matrix.
Interface d'enregistrement des variables pour l'equilibrage de charge.
virtual IItemFamily * cellFamily()=0
Retourne la famille des mailles.
Interface d'un partitionneur de maillage.
virtual VariableNodeReal3 & nodesCoordinates()=0
Coordonnées des noeuds.
virtual IParallelMng * parallelMng()=0
Gestionnaire de parallèlisme.
virtual IPrimaryMesh * toPrimaryMesh()=0
Retourne l'instance sous la forme d'un IPrimaryMesh.
virtual char reduce(eReduceType rt, char v)=0
Effectue la réduction de type rt sur le réel v et retourne la valeur.
virtual VariableItemInt32 & itemsNewOwner(eItemKind kind)=0
Variable contenant l'identifiant du sous-domaine propriétaire.
Interface du gestionnaire de traces.
CellGroup ownCells() const
Retourne le groupe contenant toutes les mailles propres à ce domaine.
Exception lorsqu'une fonction n'est pas implémentée.
Classe gérant un vecteur de réel de dimension 3.
Classe gérant une matrice de réel de dimension 3x3.
Structure contenant les informations pour créer un service.
Classe d'accès aux traces.
TraceAccessor(ITraceMng *m)
Construit un accesseur via le gestionnaire de trace m.
TraceMessage info() const
Flot pour un message d'information.
ITraceMng * traceMng() const
Gestionnaire de trace.
Vecteur 1D de données avec sémantique par valeur (style STL).
__host__ __device__ Real dot(Real2 u, Real2 v)
Produit scalaire de u par v dans .
__host__ __device__ Real2 min(Real2 a, Real2 b)
Retourne le minimum de deux Real2.
T max(const T &a, const T &b, const T &c)
Retourne le maximum de trois éléments.
ItemVectorT< Cell > CellVector
Vecteur de mailles.
ItemVectorViewT< Cell > CellVectorView
Vue sur un vecteur de mailles.
MeshVariableScalarRefT< Cell, Real3 > VariableCellReal3
Grandeur au centre des mailles de type coordonnées.
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Grandeur au noeud de type coordonnées.
ItemVariableScalarRefT< Int32 > VariableItemInt32
Grandeur de type entier 32 bits.
@ ReduceSum
Somme des valeurs.
@ ReduceMin
Minimum des valeurs.
@ ReduceMax
Maximum des valeurs.
constexpr __host__ __device__ Real squareNormL2(const Real2 &v)
Retourne la norme au carré du couple .
__host__ __device__ Real3 multiply(const Real3x3 &m, Real3 v)
Produit matrice 3x3 . vecteur.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
@ IK_Cell
Entité de maillage de genre maille.
double Real
Type représentant un réel.
@ Cell
Le maillage est AMR par maille.
std::int32_t Int32
Type entier signé sur 32 bits.
ConstArrayView< Real > RealConstArrayView
Equivalent C d'un tableau à une dimension de réels.
Information sur un nœud de l'arbre.
Int32 nb_right_child
Nombre d'enfants à droite (si non terminal)
Int32 level
Niveau dans l'arbre.
Int32 index
Index linéaire dans l'arbre.
Int32 right_partition_id
Indice de la partition de droite (uniquement pour les noeuds terminaux)
Int32 left_partition_id
Indice de la partition de gauche (uniquement pour les noeuds terminaux)
Int32 parent_index
Index dans l'arbre du parent (-1 si aucun)
Int32 left_child_index
Index linéaire du fils de gauche (-1 si aucune)
Int32 nb_left_child
Nombre d'enfants à gauche (si non terminal)
Int32 right_child_index
Index linéaire du fils de droite (-1 si aucune)
Résultat de l'application de la méthode de la puissance.