Arcane  v4.1.2.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#include "arcane/utils/FixedArray.h"
18#include "arcane/utils/SmallArray.h"
19
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"
27
28#include "arcane/core/IMeshPartitionConstraintMng.h"
29#include "arcane/impl/ArcaneGeometricMeshPartitionerService_axl.h"
30
31#include "arcane_internal_config.h"
32#include <limits>
33
34/*---------------------------------------------------------------------------*/
35/*---------------------------------------------------------------------------*/
36
37namespace Arcane
38{
39
40/*---------------------------------------------------------------------------*/
41/*---------------------------------------------------------------------------*/
56{
57 private:
58
61 {
62 Real eigen_value;
63 Real3 eigen_vector;
64 };
65
66 public:
67
71 void computeForMatrix(const Real3x3& orig_matrix)
72 {
73 Real3x3 matrix = orig_matrix;
74
75 constexpr int nb_value = 3;
76 // Itère pour calculer les valeurs et vecteurs propres
77 // La méthode de la puissance calcule la valeur propre
78 // la plus élevée. Comme on veut trier les valeurs propres
79 // par ordre croissant, on les range dans l'ordre inverse.
80
81 for (int i = (nb_value - 1); i >= 0; --i) {
82 // Calculer le premier vecteur propre (le plus grand)
83 PowerResult result = _applyPowerIteration(matrix);
84 m_eigen_values[i] = result.eigen_value;
85 m_eigen_vectors[i] = result.eigen_vector;
86
87 // Appliquer la déflation pour éliminer le vecteur propre
88 // qu'on vient de calculer.
89 // On n'a pas besoin de le faire pour la dernière itération
90 if (i != 0)
91 _deflateMatrix(matrix, result.eigen_value, result.eigen_vector);
92 }
93 }
94
95 Real3 eigenValues() const { return m_eigen_values; }
98
99 private:
100
101 // Soustrais un vecteur propre de la matrice pour la déflation
102 static void _deflateMatrix(Real3x3& matrix, double eigenvalue, Real3 eigenvector)
103 {
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];
107 }
108 }
109 }
110
111 // Applique la méthode des puissances
112 static PowerResult _applyPowerIteration(const Real3x3& matrix)
113 {
114 constexpr Int32 max_iteration = 1000;
115 constexpr Real tolerance = 1e-16;
116 Real eigenvalue = 0.0;
117
118 // Initialisation avec un vecteur initial (il pourrait être aléatoire)
119 Real3 b{ 1.0, 1.0, 1.0 };
120 Real3 b_next;
121
122 // Itérations de la méthode des puissances
123 for (Int32 iter = 0; iter < max_iteration; ++iter) {
124 b_next = math::multiply(matrix, b);
125
126 eigenvalue = b_next.normL2();
127 if (math::isNearlyZero(eigenvalue))
128 break;
129 b_next = b_next / eigenvalue;
130
131 // Vérifie la convergence
132 Real diff = math::squareNormL2(b_next - b);
133 if (diff < tolerance) {
134 break; // Si la différence est suffisamment petite, on a convergé
135 }
136
137 b = b_next;
138 }
139
140 return { eigenvalue, b_next };
141 }
142
143 private:
144
147
150};
151
152/*---------------------------------------------------------------------------*/
153/*---------------------------------------------------------------------------*/
157class BinaryTree
158: public TraceAccessor
159{
160 public:
161
176 struct TreeNode
177 {
196
197 public:
198
199 friend std::ostream& operator<<(std::ostream& o, const TreeNode& t)
200 {
201 o << "(index=" << t.index << " level=" << t.level
202 << " parent=" << t.parent_index << " sum_left=" << t.nb_left_child
203 << " sum_right=" << t.nb_right_child << " left=" << t.left_child_index << " right="
205 << " left_id=" << t.left_partition_id << " right_id=" << t.right_partition_id
206 << ")";
207 return o;
208 }
209 };
210
211 public:
212
213 explicit BinaryTree(ITraceMng* tm)
214 : TraceAccessor(tm)
215 {}
216
217 public:
218
219 void doPartition(Int32 nb_part)
220 {
221 m_tree_info.resize(nb_part);
222 m_nb_part = nb_part;
223 Int32 sum = 0;
224 Int32 level = 0;
225 Int32 parent_index = -1;
226 Int32 part_id = 0;
227 _doRecursivePart(0, part_id, sum, parent_index, level);
228 for (const TreeNode& t : m_tree_info) {
229 info() << t;
230 }
231 }
232
234 ConstArrayView<TreeNode> tree() const { return m_tree_info; }
235
236 private:
237
238 UniqueArray<TreeNode> m_tree_info;
239 Int32 m_nb_part = 0;
240
241 void _doRecursivePart(Int32 partition_index, Int32& part_id, Int32& nb_child, Int32 parent_index, Int32 level)
242 {
243 Int32 part0_partition_index = partition_index;
244 Int32 part1_partition_index = partition_index + 1;
245
246 Int32 nb_child_left = 0;
247 Int32 nb_child_right = 0;
248
249 Int32 next_left = (2 * partition_index) + 1;
250 Int32 next_right = (2 * partition_index) + 2;
251
252 m_tree_info[part0_partition_index].parent_index = parent_index;
253
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);
258 }
259 else {
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;
263 ++part_id;
264 ++nb_child_left;
265 }
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);
270 }
271 else {
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;
275 ++part_id;
276 ++nb_child_right;
277 }
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;
287 }
288};
289
290/*---------------------------------------------------------------------------*/
291/*---------------------------------------------------------------------------*/
334class ArcaneGeometricMeshPartitionerService
336, public IMeshPartitioner
337{
338 public:
339
340 explicit ArcaneGeometricMeshPartitionerService(const ServiceBuildInfo& sbi);
341
342 public:
343
344 IMesh* mesh() const override { return BasicService::mesh(); }
345 void build() override {}
346 void partitionMesh(bool initial_partition) override;
347 void partitionMesh(bool initial_partition, Int32 nb_part) override
348 {
349 _partitionMesh(initial_partition, nb_part);
350 }
351
352 void notifyEndPartition() override {}
353
354 public:
355
356 void setMaximumComputationTime(Real v) override { m_max_computation_time = v; }
357 Real maximumComputationTime() const override { return m_max_computation_time; }
358 void setComputationTimes(RealConstArrayView v) override { m_computation_times.copy(v); }
359 RealConstArrayView computationTimes() const override { return m_computation_times; }
360 void setImbalance(Real v) override { m_imbalance = v; }
361 Real imbalance() const override { return m_imbalance; }
362 void setMaxImbalance(Real v) override { m_max_imbalance = v; }
363 Real maxImbalance() const override { return m_max_imbalance; }
364
365 ArrayView<float> cellsWeight() const override { return m_cells_weight; }
366
367 void setCellsWeight(ArrayView<float> weights, Integer nb_weight) override
368 {
369 m_cells_weight = weights;
370 m_nb_weight = nb_weight;
371 }
372
377
378 ILoadBalanceMng* loadBalanceMng() const override
379 {
381 }
382
383 private:
384
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;
391 Int32 m_nb_part = 0;
392
393 private:
394
395 Real3 _computeBarycenter(const VariableCellReal3& cells_center, CellVectorView cells);
396 Real3x3 _computeInertiaTensor(Real3 center, const VariableCellReal3& cells_center,
397 CellVectorView cells);
398 Real3 _findPrincipalAxis(Real3x3 tensor);
399 void _partitionMesh2();
400 void _partitionMesh(bool initial_partition, Int32 nb_part);
401 bool _partitionMeshRecursive(const VariableCellReal3& cells_center,
402 CellVectorView cells, Int32 partition_index, Int32& part_id);
403 void _partitionMeshRecursive2(ConstArrayView<BinaryTree::TreeNode> tree_nodes, const VariableCellReal3& cells_center,
404 CellVectorView cells, Int32 partition_index);
405 void _printOwners();
406 Real3 _computeEigenValuesAndVectors(ITraceMng* tm, Real3x3 tensor, Real3x3& eigen_vectors, Real3& eigen_values);
407};
408
409/*---------------------------------------------------------------------------*/
410/*---------------------------------------------------------------------------*/
411
412ArcaneGeometricMeshPartitionerService::
413ArcaneGeometricMeshPartitionerService(const ServiceBuildInfo& sbi)
415{
416}
417
418/*---------------------------------------------------------------------------*/
419/*---------------------------------------------------------------------------*/
420
421// Fonction pour calculer le moment d'inertie du maillage
422Real3 ArcaneGeometricMeshPartitionerService::
423_computeBarycenter(const VariableCellReal3& cells_center, CellVectorView cells)
424{
425 Real3 center;
426 IParallelMng* pm = mesh()->parallelMng();
427 ENUMERATE_ (Cell, icell, cells) {
428 center += cells_center[icell];
429 }
430 Int64 local_nb_cell = cells.size();
431 Int64 total_nb_cell = pm->reduce(Parallel::ReduceSum, local_nb_cell);
432 if (total_nb_cell == 0)
433 return {};
434 Real3 sum_center = pm->reduce(Parallel::ReduceSum, center);
435 Real3 global_center = sum_center / static_cast<Real>(total_nb_cell);
436 return global_center;
437}
438
439/*---------------------------------------------------------------------------*/
440/*---------------------------------------------------------------------------*/
441/*
442 * \brief Calcule le moment d'inertie du maillage.
443 */
444Real3x3 ArcaneGeometricMeshPartitionerService::
445_computeInertiaTensor(Real3 center, const VariableCellReal3& cells_center, CellVectorView cells)
446{
447 IParallelMng* pm = mesh()->parallelMng();
448
449 Real3x3 tensor;
450
451 ENUMERATE_ (Cell, icell, cells) {
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;
456
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;
463 }
464
465 Real3x3 sum_tensor = pm->reduce(Parallel::ReduceSum, tensor);
466
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];
470
471 return sum_tensor;
472}
473
474/*---------------------------------------------------------------------------*/
475/*---------------------------------------------------------------------------*/
476/*
477 * \brief Trouve l'axe d'inertie principal du maillage.
478 */
479Real3 ArcaneGeometricMeshPartitionerService::
480_findPrincipalAxis(Real3x3 tensor)
481{
482 info() << "Tensor=" << tensor;
483
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];
490 // Si le plus petit vecteur propre est nul, prend le suivant
491 // (en général cela n'arrive pas sauf si l'algorithme dans
492 // 'computeForMatrix' n'a pas convergé).
493 if (math::isNearlyZero(v.normL2())) {
494 v = eigen_vectors[1];
495 if (math::isNearlyZero(v.normL2()))
496 v = eigen_vectors[2];
497 }
498 info() << "EigenVector=" << v;
499 return v;
500}
501
502/*---------------------------------------------------------------------------*/
503/*---------------------------------------------------------------------------*/
504
505// Fonction pour partitionner le maillage en deux sous-domaines
506void ArcaneGeometricMeshPartitionerService::
507_partitionMesh2()
508{
509 // Calcule le centre des mailles
510 VariableCellReal3 cells_center(VariableBuildInfo(mesh(), "ArcaneCellCenter"));
511 IItemFamily* cell_family = mesh()->cellFamily();
512 CellVector cells_vector(cell_family, cell_family->allItems().own().view().localIds());
513 CellVectorView cells = cells_vector.view();
514
515 info() << "** ** DO_PARTITION_MESH2 nb_cell=" << cells.size();
516
517 // Calcule le centre de chaque maille
518 {
519 const VariableNodeReal3& nodes_coordinates = mesh()->nodesCoordinates();
520 ENUMERATE_ (Cell, icell, cells) {
521 Real3 c;
522 for (NodeLocalId n : icell->nodeIds())
523 c += nodes_coordinates[n];
524 cells_center[icell] = c / icell->nbNode();
525 }
526 }
527
528 BinaryTree binary_tree(traceMng());
529 binary_tree.doPartition(m_nb_part);
530
531 bool do_new = true;
532 if (platform::getEnvironmentVariable("GEOMETRIC_PARTITIONER_IMPL") == "1")
533 do_new = false;
534 info() << "Using geoemtric partitioner do_new?=" << do_new;
535 if (do_new) {
536 _partitionMeshRecursive2(binary_tree.tree(), cells_center, cells, 0);
537 }
538 else {
539 Int32 partition_index = 0;
540 Int32 part_id = 0;
541 _partitionMeshRecursive(cells_center, cells, partition_index, part_id);
542 }
543}
544
545/*---------------------------------------------------------------------------*/
546/*---------------------------------------------------------------------------*/
547
548bool ArcaneGeometricMeshPartitionerService::
549_partitionMeshRecursive(const VariableCellReal3& cells_center,
550 CellVectorView cells, Int32 partition_index, Int32& part_id)
551{
552 Int32 part0_partition_index = partition_index;
553 Int32 part1_partition_index = partition_index + 1;
554 // Pour test. A supprimer.
555 Int32 total_nb_cell = mesh()->parallelMng()->reduce(Parallel::ReduceSum, cells.size());
556 info() << "Doing partition partition_index=" << partition_index << " total_nb_cell=" << total_nb_cell;
557 if (part1_partition_index >= m_nb_part)
558 return true;
559
560 info() << "Doing partition really partition_index=" << partition_index;
561 IItemFamily* cell_family = mesh()->cellFamily();
562 VariableItemInt32& cells_new_owner = cell_family->itemsNewOwner();
563
564 // Calculer le centre de masse
565 Real3 center = _computeBarycenter(cells_center, cells);
566 info() << "GlobalCenter=" << center;
567
568 // Calculer le tenseur d'inertie
569 Real3x3 tensor = _computeInertiaTensor(center, cells_center, cells);
570
571 // Trouver l'axe principal d'inertie
572 Real3 eigenvector = _findPrincipalAxis(tensor);
573 info() << "EigenVector=" << eigenvector;
574
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);
580
581 // Regarde dans quelle partie va se trouver la maille
582 // en calculant le produit scalaire entre le vecteur propre
583 // et le vecteur du centre de gravité à la maille.
584 // La valeur du signe indique dans quelle partie on se trouve.
585 info() << "Doing partition setting nb_cell=" << nb_cell << " partition=" << part0_partition_index << " " << part1_partition_index;
586 ENUMERATE_ (Cell, icell, cells) {
587 const Real3 cell_coord = cells_center[icell];
588
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;
593
594 if (projection < 0.0) {
595 part0_cells.add(icell.itemLocalId());
596 }
597 else {
598 part1_cells.add(icell.itemLocalId());
599 }
600 }
601 CellVectorView part0(cell_family, part0_cells);
602 CellVectorView part1(cell_family, part1_cells);
603
604 // Si _partitionMeshRecursive() retourne \a true, alors il n'y a plus de sous-partition
605 // à réaliser. Dans ce cas, on remplit les propriétaires des mailles
606 // pour la partition.
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();
609 ENUMERATE_ (Cell, icell, part0) {
610 cells_new_owner[icell] = part_id;
611 }
612 ++part_id;
613 }
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();
616 ENUMERATE_ (Cell, icell, part1) {
617 cells_new_owner[icell] = part_id;
618 }
619 ++part_id;
620 }
621 return false;
622}
623
624/*---------------------------------------------------------------------------*/
625/*---------------------------------------------------------------------------*/
626
627void ArcaneGeometricMeshPartitionerService::
628_partitionMeshRecursive2(ConstArrayView<BinaryTree::TreeNode> tree_nodes,
629 const VariableCellReal3& cells_center,
630 CellVectorView cells, Int32 partition_index)
631{
632 Int32 part0_partition_index = partition_index;
633 Int32 part1_partition_index = partition_index + 1;
634 IParallelMng* pm = mesh()->parallelMng();
635 // Pour test. À supprimer par la suite
636 Int32 total_nb_cell = pm->reduce(Parallel::ReduceSum, cells.size());
637 info() << "Doing partition (V2) partition_index=" << partition_index << " total_nb_cell=" << total_nb_cell;
638
639 info() << "Doing partition (V2) really partition_index=" << partition_index;
640 IItemFamily* cell_family = mesh()->cellFamily();
641 VariableItemInt32& cells_new_owner = cell_family->itemsNewOwner();
642
643 // Calculer le centre de masse
644 Real3 center = _computeBarycenter(cells_center, cells);
645 info() << "GlobalCenter=" << center;
646
647 // Calculer le tenseur d'inertie
648 Real3x3 tensor = _computeInertiaTensor(center, cells_center, cells);
649
650 // Trouver l'axe principal d'inertie
651 Real3 eigenvector = _findPrincipalAxis(tensor);
652 info() << "EigenVector=" << eigenvector;
653
654 const Int32 nb_cell = cells.size();
655
656 // Calcule pour chaque élément le produit scalaire entre
657 // le vecteur propre et le vecteur reliant le centre de gravité
658 // à cet élément et le range dans \a projections
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();
663 ENUMERATE_ (Cell, icell, cells) {
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);
669 }
670
671 // Calcule globalement le min et le max de la projection.
672 min_projection = pm->reduce(Parallel::ReduceMin, min_projection);
673 max_projection = pm->reduce(Parallel::ReduceMax, max_projection);
674
675 info() << "min_projection=" << min_projection << " max_projection=" << max_projection;
676
677 // Pour tenir compte du ratio entre les deux partitions qui ne vaut pas forcément 0.5,
678 // on détermine plusieurs valeurs de projection qui vont servir à partitionner
679 // Ces valeurs testées sont dans l'intervalle [-min_projection,max_projection].
680 // On \a nb_to_test valeurs entre '-min_projection' et 0, la valeur 0.0 et \a nb_to_test
681 // entre 0 et \a max_projection. On va donc tester `(2*nb_to_test)+1` valeurs.
682
683 UniqueArray<Real> projections_to_test;
684 // TODO: rendre nb_to_test paramètrable.
685 // On pourrait aussi faire une dichomie sur les valeurs de projection
686 // pour mieux approximer l'équilibre et ne pas forcément tester trop de valeurs
687 int nb_to_test = 10;
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;
695 }
696 projections_to_test[nb_to_test] = 0.0; //< Projection centrale
697 info() << "projections_to_test=" << projections_to_test;
698
699 // L'arbre binaire permet de savoir combien il faut faire de partition
700 // du côté gauche et droit. On s'en sert pour calculer un ratio
701 // idéal qu'on range dans \a expected_ratio.
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;
705 // Ratio d'éléments entre les deux partie qu'on souhaite attendre
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);
711 }
712
713 // Ce tableau contiendra, sous forme ce de couple, le nombre d'éléments
714 // de chaque partition pour chaque test.
715 // global_nb_parts[i*2+p] est la valeur de la partition gauche (p==0)
716 // ou droite (p==1) pour le i-ème test.
717 SmallArray<Int64> global_nb_parts(total_nb_to_test*2);
718
719 // Teste toute les partitions et calcule celle dont le ratio est le
720 // plus proche du ratio souhaite. C'est celle qu'on prendra pour
721 // le partitionnement
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];
728 // TODO: Mettre cette boucle en externe
729 ENUMERATE_ (Cell, icell, cells) {
730 Real projection = projections[icell.index()];
731 if (projection < projection_to_test)
732 ++nb_new_part0;
733 else
734 ++nb_new_part1;
735 }
736 global_nb_parts[0+(z*2)] = nb_new_part0;
737 global_nb_parts[1+(z*2)] = nb_new_part1;
738 }
739
740 // Fais la somme des parties sur tous les sous-domaines.
741 pm->reduce(Parallel::ReduceSum, global_nb_parts.view());
742
743 for (Int32 z = 0; z < total_nb_to_test; ++z) {
744 Real ratio_0 = 1.0;
745 Int64 nb_part0 = global_nb_parts[0+(z*2)];
746 Int64 nb_part1 = global_nb_parts[1+(z*2)];
747 if (nb_part0 != 0) {
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);
751 }
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;
762 }
763 }
764
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;
768
769 UniqueArray<Int32> part0_cells;
770 part0_cells.reserve(nb_cell);
771 UniqueArray<Int32> part1_cells;
772 part1_cells.reserve(nb_cell);
773
774 // Regarde dans quelle partie va se trouver la maille
775 // en calculant le produit scalaire entre le vecteur propre
776 // et le vecteur du centre de gravité à la maille.
777 // La valeur du signe indique dans quelle partie on se trouve.
778
779 ENUMERATE_ (Cell, icell, cells) {
780 Real projection = projections[icell.index()];
781 if (projection < projection_to_use) {
782 part0_cells.add(icell.itemLocalId());
783 }
784 else {
785 part1_cells.add(icell.itemLocalId());
786 }
787 }
788
789 CellVectorView part0(cell_family, part0_cells);
790 CellVectorView part1(cell_family, part1_cells);
791
792 Int32 child_left = current_tree_node.left_child_index;
793 if (child_left >= 0) {
794 _partitionMeshRecursive2(tree_nodes, cells_center, part0, child_left);
795 }
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();
799 ENUMERATE_ (Cell, icell, part0) {
800 cells_new_owner[icell] = left_partition_id;
801 }
802 }
803 Int32 child_right = current_tree_node.right_child_index;
804 if (child_right >= 0) {
805 _partitionMeshRecursive2(tree_nodes, cells_center, part1, child_right);
806 }
807
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();
811 ENUMERATE_ (Cell, icell, part1) {
812 cells_new_owner[icell] = right_partition_id;
813 }
814 }
815}
816
817/*---------------------------------------------------------------------------*/
818/*---------------------------------------------------------------------------*/
819
820void ArcaneGeometricMeshPartitionerService::
821_partitionMesh([[maybe_unused]] bool initial_partition, Int32 nb_part)
822{
823 m_nb_part = nb_part;
824
825 IPrimaryMesh* mesh = this->mesh()->toPrimaryMesh();
826
827 info() << "Doing mesh partition with ArcaneGeometricMeshPartitionerService nb_part=" << nb_part;
828 IParallelMng* pm = mesh->parallelMng();
829 Int32 nb_rank = pm->commSize();
830
831 if (nb_rank == 1) {
832 return;
833 }
834
835 _partitionMesh2();
836 _printOwners();
837 VariableItemInt32& cells_new_owner = mesh->itemsNewOwner(IK_Cell);
838 cells_new_owner.synchronize();
839 if (mesh->partitionConstraintMng()) {
840 // Deal with Tied Cells
841 mesh->partitionConstraintMng()->computeAndApplyConstraints();
842 }
843 mesh->utilities()->changeOwnersFromCells();
844}
845
846/*---------------------------------------------------------------------------*/
847/*---------------------------------------------------------------------------*/
848
849void ArcaneGeometricMeshPartitionerService::
850_printOwners()
851{
852 IParallelMng* pm = mesh()->parallelMng();
853 VariableItemInt32& cells_new_owner = mesh()->toPrimaryMesh()->itemsNewOwner(IK_Cell);
854 for (Int32 i = 0; i < m_nb_part; ++i) {
855 Int32 n = 0;
856 ENUMERATE_ (Cell, icell, mesh()->ownCells()) {
857 if (cells_new_owner[icell] == i)
858 ++n;
859 }
860 info() << "NbCell for part=" << i << " total=" << pm->reduce(Parallel::ReduceSum, n);
861 }
862}
863
864/*---------------------------------------------------------------------------*/
865/*---------------------------------------------------------------------------*/
866
868partitionMesh(bool initial_partition)
869{
870 _partitionMesh(initial_partition, mesh()->parallelMng()->commSize());
871}
872
873/*---------------------------------------------------------------------------*/
874/*---------------------------------------------------------------------------*/
875
876#if ARCANE_DEFAULT_PARTITIONER == ARCANEGEOMETRICMESHPARTITIONER_DEFAULT_PARTITIONER
877ARCANE_REGISTER_SERVICE_ARCANEGEOMETRICMESHPARTITIONERSERVICE(DefaultPartitioner,
879#endif
880ARCANE_REGISTER_SERVICE_ARCANEGEOMETRICMESHPARTITIONERSERVICE(ArcaneGeometricMeshPartitioner,
882
883/*---------------------------------------------------------------------------*/
884/*---------------------------------------------------------------------------*/
885
886} // End namespace Arcane
887
888/*---------------------------------------------------------------------------*/
889/*---------------------------------------------------------------------------*/
#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 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.
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.
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.
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 .
Definition MathUtils.h:96
__host__ __device__ Real2 min(Real2 a, Real2 b)
Retourne le minimum de deux Real2.
Definition MathUtils.h:336
T max(const T &a, const T &b, const T &c)
Retourne le maximum de trois éléments.
Definition MathUtils.h:392
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.
@ ReduceMin
Minimum des valeurs.
@ ReduceMax
Maximum 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
ARCCORE_BASE_EXPORT String getEnvironmentVariable(const String &name)
Variable d'environnement du nom name.
-*- 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:488
Int32 nb_right_child
Nombre d'enfants à droite (si non terminal)
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.