Arcane  v4.1.1.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
ArcaneGeometricMeshPartitionerService.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2025 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/* ArcaneGeometricMeshPartitionerService.cc (C) 2000-2025 */
9/* */
10/* Service de partitionnement géométrique de maillage. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/PlatformUtils.h"
15#include "arcane/utils/NotImplementedException.h"
16#include "arcane/utils/ITraceMng.h"
17
18#include "arcane/core/IParallelMng.h"
19#include "arcane/core/IPrimaryMesh.h"
20#include "arcane/core/IMeshUtilities.h"
21#include "arcane/core/IMeshPartitioner.h"
22#include "arcane/core/IItemFamily.h"
23#include "arcane/core/ItemVector.h"
25
26#include "arcane/core/IMeshPartitionConstraintMng.h"
27#include "arcane/impl/ArcaneGeometricMeshPartitionerService_axl.h"
28
29/*---------------------------------------------------------------------------*/
30/*---------------------------------------------------------------------------*/
31
32namespace Arcane
33{
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
51{
52 private:
53
56 {
57 Real eigen_value;
58 Real3 eigen_vector;
59 };
60
61 public:
62
66 void computeForMatrix(const Real3x3& orig_matrix)
67 {
68 Real3x3 matrix = orig_matrix;
69
70 const int nb_value = 3;
71 // Itère pour calculer les valeurs et vecteurs propre
72 // La méthode de la puissance calcule la valeur propre
73 // la plus élevée. Comme on veut trier les valeurs propres
74 // par ordre croissant, on les range dans l'ordre inverse.
75
76 for (int i = (nb_value - 1); i >= 0; --i) {
77 // Calculer le premier vecteur propre (le plus grand)
78 PowerResult result = _applyPowerIteration(matrix);
79 m_eigen_values[i] = result.eigen_value;
80 m_eigen_vectors[i] = result.eigen_vector;
81
82 // Appliquer la déflation pour éliminer le vecteur propre
83 // qu'on vient de calculer.
84 // On n'a pas besoin de le faire pour la dernière itération
85 if (i != 0)
86 _deflateMatrix(matrix, result.eigen_value, result.eigen_vector);
87 }
88 }
89
90 Real3 eigenValues() const { return m_eigen_values; }
93
94 private:
95
96 // Soustrais un vecteur propre de la matrice pour la déflation
97 void _deflateMatrix(Real3x3& matrix, double eigenvalue, Real3 eigenvector)
98 {
99 for (int i = 0; i < 3; ++i) {
100 for (int j = 0; j < 3; ++j) {
101 matrix[i][j] -= eigenvalue * eigenvector[i] * eigenvector[j];
102 }
103 }
104 }
105
106 // Apploique la méthode des puissances
107 PowerResult _applyPowerIteration(const Real3x3& matrix)
108 {
109 int max_iteration = 1000;
110 Real tolerance = 1e-16;
111 Real eigenvalue = 0.0;
112
113 // Initialisation avec un vecteur initial (il pourrait être aléatoire)
114 Real3 b{ 1.0, 1.0, 1.0 };
115 Real3 b_next;
116
117 // Itérations de la méthode des puissances
118 for (int iter = 0; iter < max_iteration; ++iter) {
119 // Calculer A * b
120 b_next = math::multiply(matrix, b);
121
122 eigenvalue = b_next.normL2();
123 b_next = b_next / eigenvalue;
124
125 // Vérifier la convergence
126 Real diff = math::squareNormL2(b_next - b);
127 if (diff < tolerance) {
128 break; // Si la différence est suffisamment petite, on a convergé
129 }
130
131 b = b_next;
132 }
133
134 return { eigenvalue, b_next };
135 }
136
137 private:
138
141
144};
145
146/*---------------------------------------------------------------------------*/
147/*---------------------------------------------------------------------------*/
190class ArcaneGeometricMeshPartitionerService
192, public IMeshPartitioner
193{
194 public:
195
196 explicit ArcaneGeometricMeshPartitionerService(const ServiceBuildInfo& sbi);
197
198 public:
199
200 IMesh* mesh() const override { return BasicService::mesh(); }
201 void build() override {}
202 void partitionMesh(bool initial_partition) override;
203 void partitionMesh(bool initial_partition, Int32 nb_part) override
204 {
205 _partitionMesh(initial_partition, nb_part);
206 }
207
208 void notifyEndPartition() override {}
209
210 public:
211
212 void setMaximumComputationTime(Real v) override { m_max_computation_time = v; }
213 Real maximumComputationTime() const override { return m_max_computation_time; }
214 void setComputationTimes(RealConstArrayView v) override { m_computation_times.copy(v); }
215 RealConstArrayView computationTimes() const override { return m_computation_times; }
216 void setImbalance(Real v) override { m_imbalance = v; }
217 Real imbalance() const override { return m_imbalance; }
218 void setMaxImbalance(Real v) override { m_max_imbalance = v; }
219 Real maxImbalance() const override { return m_max_imbalance; }
220
221 ArrayView<float> cellsWeight() const override { return m_cells_weight; }
222
223 void setCellsWeight(ArrayView<float> weights, Integer nb_weight) override
224 {
225 m_cells_weight = weights;
226 m_nb_weight = nb_weight;
227 }
228
233
234 ILoadBalanceMng* loadBalanceMng() const override
235 {
237 }
238
239 private:
240
241 Real m_imbalance = 0.0;
242 Real m_max_imbalance = 0.0;
243 Real m_max_computation_time = 0.0;
244 Int32 m_nb_weight = 0;
245 ArrayView<float> m_cells_weight;
246 UniqueArray<Real> m_computation_times;
247 Int32 m_nb_part = 0;
248
249 private:
250
251 Real3 _computeBarycenter(const VariableCellReal3& cells_center, CellVectorView cells);
252 Real3x3 _computeInertiaTensor(Real3 center, const VariableCellReal3& cells_center,
253 CellVectorView cells);
254 Real3 _findPrincipalAxis(Real3x3 tensor);
255 void _partitionMesh2();
256 void _partitionMesh(bool initial_partition, Int32 nb_part);
257 bool _partitionMeshRecursive(const VariableCellReal3& cells_center,
258 CellVectorView cells, Int32 partition_index, Int32& part_id);
259 void _printOwners();
260 Real3 _computeEigenValuesAndVectors(ITraceMng* tm, Real3x3 tensor, Real3x3& eigen_vectors, Real3& eigen_values);
261};
262
263/*---------------------------------------------------------------------------*/
264/*---------------------------------------------------------------------------*/
265
266ArcaneGeometricMeshPartitionerService::
267ArcaneGeometricMeshPartitionerService(const ServiceBuildInfo& sbi)
269{
270}
271
272/*---------------------------------------------------------------------------*/
273/*---------------------------------------------------------------------------*/
274
275// Fonction pour calculer le moment d'inertie du maillage
276Real3 ArcaneGeometricMeshPartitionerService::
277_computeBarycenter(const VariableCellReal3& cells_center, CellVectorView cells)
278{
279 Real3 center;
280 IParallelMng* pm = mesh()->parallelMng();
281 ENUMERATE_ (Cell, icell, cells) {
282 center += cells_center[icell];
283 }
284 Int64 local_nb_cell = cells.size();
285 Int64 total_nb_cell = pm->reduce(Parallel::ReduceSum, local_nb_cell);
286 Real3 sum_center = pm->reduce(Parallel::ReduceSum, center);
287 Real3 global_center = sum_center / static_cast<Real>(total_nb_cell);
288 return global_center;
289}
290
291/*---------------------------------------------------------------------------*/
292/*---------------------------------------------------------------------------*/
293/*
294 * \brief Calcule le moment d'inertie du maillage.
295 */
296Real3x3 ArcaneGeometricMeshPartitionerService::
297_computeInertiaTensor(Real3 center, const VariableCellReal3& cells_center, CellVectorView cells)
298{
299 IParallelMng* pm = mesh()->parallelMng();
300
301 Real3x3 tensor;
302
303 ENUMERATE_ (Cell, icell, cells) {
304 Real3 cell_coord = cells_center[icell];
305 double dx = cell_coord.x - center.x;
306 double dy = cell_coord.y - center.y;
307 double dz = cell_coord.z - center.z;
308
309 tensor[0][0] += dy * dy + dz * dz;
310 tensor[1][1] += dx * dx + dz * dz;
311 tensor[2][2] += dx * dx + dy * dy;
312 tensor[0][1] -= dx * dy;
313 tensor[0][2] -= dx * dz;
314 tensor[1][2] -= dy * dz;
315 }
316
317 Real3x3 sum_tensor = pm->reduce(Parallel::ReduceSum, tensor);
318
319 sum_tensor[1][0] = sum_tensor[0][1];
320 sum_tensor[2][0] = sum_tensor[0][2];
321 sum_tensor[2][1] = sum_tensor[1][2];
322
323 return sum_tensor;
324}
325
326/*---------------------------------------------------------------------------*/
327/*---------------------------------------------------------------------------*/
328/*
329 * \brief Trouve l'axe d'interie principal du maillage.
330 */
331Real3 ArcaneGeometricMeshPartitionerService::
332_findPrincipalAxis(Real3x3 tensor)
333{
334 info() << "Tensor=" << tensor;
335
336 EigenValuesAndVectorComputer eigen_computer;
337 eigen_computer.computeForMatrix(tensor);
338 info() << "EigenValues = " << eigen_computer.eigenValues();
339 info() << "EigenVectors = " << eigen_computer.eigenVectors();
340 Real3 v4 = eigen_computer.eigenVectors()[0];
341 info() << "V4=" << v4;
342 return v4;
343}
344
345/*---------------------------------------------------------------------------*/
346/*---------------------------------------------------------------------------*/
347
348// Fonction pour partitionner le maillage en deux sous-domaines
349void ArcaneGeometricMeshPartitionerService::
350_partitionMesh2()
351{
352 // Calcule le centre des mailles
353 VariableCellReal3 cells_center(VariableBuildInfo(mesh(), "ArcaneCellCenter"));
354 IItemFamily* cell_family = mesh()->cellFamily();
355 CellVector cells_vector(cell_family, cell_family->allItems().own().view().localIds());
356 CellVectorView cells = cells_vector.view();
357
358 info() << "** ** DO_PARTITION_MESH2 nb_cell=" << cells.size();
359
360 // Calcule le centre de chaque maille
361 {
362 const VariableNodeReal3& nodes_coordinates = mesh()->nodesCoordinates();
363 ENUMERATE_ (Cell, icell, cells) {
364 Real3 c;
365 for (NodeLocalId n : icell->nodeIds())
366 c += nodes_coordinates[n];
367 cells_center[icell] = c / icell->nbNode();
368 }
369 }
370
371 Int32 partition_index = 0;
372 Int32 part_id = 0;
373 _partitionMeshRecursive(cells_center, cells, partition_index, part_id);
374}
375
376/*---------------------------------------------------------------------------*/
377/*---------------------------------------------------------------------------*/
378
379bool ArcaneGeometricMeshPartitionerService::
380_partitionMeshRecursive(const VariableCellReal3& cells_center,
381 CellVectorView cells, Int32 partition_index, Int32& part_id)
382{
383 Int32 part0_partition_index = partition_index;
384 Int32 part1_partition_index = partition_index + 1;
385 // Pour test. A supprimer.
386 Int32 total_nb_cell = mesh()->parallelMng()->reduce(Parallel::ReduceSum, cells.size());
387 info() << "Doing partition partition_index=" << partition_index << " total_nb_cell=" << total_nb_cell;
388 if (part1_partition_index >= m_nb_part)
389 return true;
390
391 info() << "Doing partition really partition_index=" << partition_index;
392 IItemFamily* cell_family = mesh()->cellFamily();
393 VariableItemInt32& cells_new_owner = cell_family->itemsNewOwner();
394
395 // Calculer le centre de masse
396 Real3 center = _computeBarycenter(cells_center, cells);
397 info() << "GlobalCenter=" << center;
398
399 // Calculer le tenseur d'inertie
400 Real3x3 tensor = _computeInertiaTensor(center, cells_center, cells);
401
402 // Trouver l'axe principal d'inertie
403 Real3 eigenvector = _findPrincipalAxis(tensor);
404 info() << "EigenVector=" << eigenvector;
405
406 const Int32 nb_cell = cells.size();
407 UniqueArray<Int32> part0_cells;
408 part0_cells.reserve(nb_cell);
409 UniqueArray<Int32> part1_cells;
410 part1_cells.reserve(nb_cell);
411
412 // Regarde dans quel partie va se trouver la maille
413 // en calculant le produit scalare entre le vecteur propre
414 // et le vecteur du centre de gravité à la maille.
415 // La valeur du signe indique dans quelle partie on se trouve.
416 info() << "Doing partition setting partition=" << part0_partition_index << " " << part1_partition_index;
417 ENUMERATE_ (Cell, icell, cells) {
418 const Real3 cell_coord = cells_center[icell];
419
420 Real projection = 0.0;
421 projection += (cell_coord.x - center.x) * eigenvector.x;
422 projection += (cell_coord.y - center.y) * eigenvector.y;
423 projection += (cell_coord.z - center.z) * eigenvector.z;
424
425 if (projection < 0.0) {
426 part0_cells.add(icell.itemLocalId());
427 }
428 else {
429 part1_cells.add(icell.itemLocalId());
430 }
431 }
432 CellVectorView part0(cell_family, part0_cells);
433 CellVectorView part1(cell_family, part1_cells);
434
435 // Pour test, à supprimer par la suite.
436 _printOwners();
437
438 // Si _partitionMeshRecursive retourne \a true, alors il n'y a plus de sous-partition
439 // à réaliser. Dans ce cas on remplit les propriétaires des mailles
440 // pour la partition.
441 if (_partitionMeshRecursive(cells_center, part0, (2 * partition_index) + 1, part_id)) {
442 info() << "Filling left part part_index=" << part_id << " nb_cell=" << part0.size();
443 ENUMERATE_ (Cell, icell, part0) {
444 cells_new_owner[icell] = part_id;
445 }
446 ++part_id;
447 }
448 if (_partitionMeshRecursive(cells_center, part1, (2 * partition_index) + 2, part_id)) {
449 info() << "Filling right part part_index=" << part_id << " nb_cell=" << part1.size();
450 ENUMERATE_ (Cell, icell, part1) {
451 cells_new_owner[icell] = part_id;
452 }
453 ++part_id;
454 }
455 return false;
456}
457
458/*---------------------------------------------------------------------------*/
459/*---------------------------------------------------------------------------*/
460
461void ArcaneGeometricMeshPartitionerService::
462_partitionMesh([[maybe_unused]] bool initial_partition, Int32 nb_part)
463{
464 m_nb_part = nb_part;
465
466 IPrimaryMesh* mesh = this->mesh()->toPrimaryMesh();
467
468 info() << "Doing mesh partition with ArcaneGeometricMeshPartitionerService nb_part=" << nb_part;
469 IParallelMng* pm = mesh->parallelMng();
470 Int32 nb_rank = pm->commSize();
471
472 if (nb_rank == 1) {
473 return;
474 }
475
476 _partitionMesh2();
477 _printOwners();
478 VariableItemInt32& cells_new_owner = mesh->itemsNewOwner(IK_Cell);
479 cells_new_owner.synchronize();
480 if (mesh->partitionConstraintMng()) {
481 // Deal with Tied Cells
482 mesh->partitionConstraintMng()->computeAndApplyConstraints();
483 }
484 mesh->utilities()->changeOwnersFromCells();
485}
486
487/*---------------------------------------------------------------------------*/
488/*---------------------------------------------------------------------------*/
489
490void ArcaneGeometricMeshPartitionerService::
491_printOwners()
492{
493 IParallelMng* pm = mesh()->parallelMng();
494 VariableItemInt32& cells_new_owner = mesh()->toPrimaryMesh()->itemsNewOwner(IK_Cell);
495 for (Int32 i = 0; i < m_nb_part; ++i) {
496 Int32 n = 0;
497 ENUMERATE_ (Cell, icell, mesh()->ownCells()) {
498 if (cells_new_owner[icell] == i)
499 ++n;
500 }
501 info() << "NbCell for part=" << i << " total=" << pm->reduce(Parallel::ReduceSum, n);
502 }
503}
504
505/*---------------------------------------------------------------------------*/
506/*---------------------------------------------------------------------------*/
507
509partitionMesh(bool initial_partition)
510{
511 _partitionMesh(initial_partition, mesh()->parallelMng()->commSize());
512}
513
514/*---------------------------------------------------------------------------*/
515/*---------------------------------------------------------------------------*/
516
517ARCANE_REGISTER_SERVICE_ARCANEGEOMETRICMESHPARTITIONERSERVICE(ArcaneGeometricMeshPartitioner,
519
520/*---------------------------------------------------------------------------*/
521/*---------------------------------------------------------------------------*/
522
523} // End namespace Arcane
524
525/*---------------------------------------------------------------------------*/
526/*---------------------------------------------------------------------------*/
#define ARCANE_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
#define ENUMERATE_(type, name, group)
Enumérateur générique d'un groupe d'entité
Fonctions mathématiques diverses.
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 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 calculer les valeurs et vecteurs propres d'une matrice.
void computeForMatrix(const Real3x3 &orig_matrix)
Calcule les valeurs et vecteurs propres de orig_matrix.
Real3 eigenValues() const
Retourne les valeurs propres de la matrice par ordre croissant.
Real3x3 eigenVectors() const
Retourne les vecteurs propres de la matrice par ordre croissant.
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.
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.
Definition Real3.h:132
Classe gérant une matrice de réel de dimension 3x3.
Definition Real3x3.h:66
Structure contenant les informations pour créer un service.
TraceMessage info() const
Flot pour un message d'information.
ItemVectorT< Cell > CellVector
Vecteur de mailles.
Definition ItemTypes.h:599
ItemVectorViewT< Cell > CellVectorView
Vue sur un vecteur de mailles.
Definition ItemTypes.h:304
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.
constexpr __host__ __device__ Real squareNormL2(const Real2 &v)
Retourne la norme au carré du couple .
Definition Real2.h:451
__host__ __device__ Real3 multiply(const Real3x3 &m, Real3 v)
Produit matrice 3x3 . vecteur.
Definition MathUtils.h:809
-*- 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.
Definition MeshKind.h:52
std::int32_t Int32
Type entier signé sur 32 bits.
ConstArrayView< Real > RealConstArrayView
Equivalent C d'un tableau à une dimension de réels.
Definition UtilsTypes.h:504
Résultat de l'application de la méthode de la puissance.