TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Partitionneur_Metis.cpp
1/****************************************************************************
2* Copyright (c) 2026, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15#include <Partitionneur_Metis.h>
16#include <Domaine.h>
17#include <Static_Int_Lists.h>
18
19#include <Param.h>
20
21#include <communications.h>
22#include <Domain_Graph.h>
23#include <metis.h>
24
25inline void not_implemented(const Nom& chaine)
26{
27 Cerr << chaine << " is not implemented yet to the METIS API." << finl;
29}
30
31Implemente_instanciable_32_64(Partitionneur_Metis_32_64,"Partitionneur_Metis",Partitionneur_base_32_64<_T_>);
32// XD partitionneur_metis_64 partitionneur_deriv metis_64 INHERITS_BRACE Metis is an external partitionning library. It
33// XD_CONT is a general algorithm that will generate a partition of big (64b) domain.
34// XD partitionneur_metis partitionneur_deriv metis INHERITS_BRACE Metis is an external partitionning library. It is a
35// XD_CONT general algorithm that will generate a partition of the domain.
36
37namespace
38{
39
40/*! Handy method to convert a METIS idx_t to a '_SIZE_' value.
41 * In the case where METIS is compiled in 64b, and the template is instanciated in 32b, this is actually a down-cast, so check.
42 */
43template<typename _SIZE_>
44_SIZE_ from_idx_t_to_SIZE(idx_t val)
45{
46 assert(val < std::numeric_limits<_SIZE_>::max());
47 return (_SIZE_) val;
48}
49}
50
51
52template <typename _SIZE_>
54{
55 Cerr << "Partitionneur_Metis_32_64<_SIZE_>::printOn invalid\n" << finl;
57 return os;
58}
59
60
61template <typename _SIZE_>
63{
64 param.ajouter("nb_parts",&nb_parties_,Param::REQUIRED);
65 param.ajouter("nb_essais",&nb_essais_);
66 param.ajouter_condition("(value_of_nb_parts_ge_1)_and_(value_of_nb_parts_le_100000)","The following condition must be satisfied : 1 <= nb_parties <= 100000");
67 param.ajouter_non_std("pmetis",(this));
68 param.ajouter_non_std("kmetis",(this)); // XD attr kmetis rien kmetis OPT The default values are pmetis, default
69 // XD_CONT parameters are automatically chosen by Metis. \'kmetis\' is faster than pmetis option but the last option
70 // XD_CONT produces better partitioning quality. In both cases, the partitioning quality may be slightly improved by
71 // XD_CONT increasing the nb_essais option (by default N=1). It will compute N partitions and will keep the best one
72 // XD_CONT (smallest edge cut number). But this option is CPU expensive, taking N=10 will multiply the CPU cost of
73 // XD_CONT partitioning by 10. NL2 Experiments show that only marginal improvements can be obtained with non default
74 // XD_CONT parameters.
75 param.ajouter_non_std("match_type",(this));
76 param.ajouter_non_std("initial_partition_type",(this));
77 param.ajouter_non_std("refinement_type",(this));
78 param.ajouter_flag("use_weights",&use_weights_); // XD attr use_weights rien use_weights OPT If use_weights is
79 // XD_CONT specified, weighting of the element-element links in the graph is used to force metis to keep opposite
80 // XD_CONT periodic elements on the same processor. This option can slightly improve the partitionning quality but it
81 // XD_CONT consumes more memory and takes more time. It is not mandatory since a correction algorithm is always
82 // XD_CONT applied afterwards to ensure a correct partitionning for periodic boundaries.
83 param.ajouter_flag("use_segment_to_build_connectivite_elem_elem",&use_segment_to_build_connectivite_elem_elem_); // option to build the graph from links (segments) for electrical networks, sides, etc.
84}
85
86template <typename _SIZE_>
88{
90 {
91 Cerr << "WARNING! You're using a sequential algorithm on " << this->nproc() << "processors " << finl;
92 Cerr << "Use PARMETIS for parallel domain cutting" << finl;
94 }
95 if (mot=="pmetis")
96 {
97 Cerr << " Algorithm PMETIS" << finl;
98 algo_ = PMETIS;
99 return 1;
100 }
101 else if (mot=="kmetis")
102 {
103 Cerr << " Algorithm KMETIS" << finl;
104 algo_ = KMETIS;
105 return 1;
106 }
107 else if (mot=="match_type")
108 {
109 not_implemented(mot);
110 return 1;
111 }
112 else if (mot=="initial_partition_type")
113 {
114 not_implemented(mot);
115 return 1;
116 }
117 else if (mot=="refinement_type")
118 {
119 not_implemented(mot);
120 return 1;
121 }
122 else
124}
125
126/*! @brief @brief Computes the connectivity graph for Metis, calls the partitioner and fills elem_part (for each element, the number of the part assigned to it).
127 *
128 * Parts are balanced to minimise the number of joint faces
129 * and to balance the number of elements per part.
130 *
131 */
132template <typename _SIZE_>
134{
135#ifdef NO_METIS
136 Cerr << "METIS is not compiled with this version. Use another partition tool like Tranche." << finl;
138#else
139 if (!ref_domaine_)
140 {
141 Cerr << "Error in Partitionneur_Metis_32_64<_SIZE_>::construire_partition\n";
142 Cerr << " The domain has not been associated" << finl;
144 }
145 if (nb_parties_ <= 0)
146 {
147 Cerr << "Error in Partitionneur_Metis_32_64<_SIZE_>::construire_partition\n";
148 Cerr << " The parts number has not been initialized" << finl;
150 }
151
152 // Special case: if nb_parts == 1, METIS does nothing...
153 if (nb_parties_ == 1)
154 {
155 int_t nb_elem = ref_domaine_->nb_elem_tot();
156 if (use_segment_to_build_connectivite_elem_elem_)
157 nb_elem = ref_domaine_->nb_som();
158 elem_part.resize(nb_elem);
159 elem_part = 0;
160 return;
161 }
162
163 if (ref_domaine_->nb_elem() == 0)
164 return;
165
166 Cerr << "Partitionneur_Metis_32_64<_SIZE_>::construire_partition" << finl;
167 Cerr << " Construction of graph connectivity..." << finl;
168 Static_Int_Lists_32_64<_SIZE_> graph_elements_perio;
169 //const Domaine& dom = ref_domaine_.valeur();
170 Domain_Graph graph;
171 if (!use_segment_to_build_connectivite_elem_elem_)
172 graph.construire_graph_elem_elem<_SIZE_>(ref_domaine_.valeur(),
173 use_weights_,
174 graph_elements_perio);
175 else
176 graph.construire_graph_from_segment<_SIZE_>(ref_domaine_.valeur(), use_weights_);
177
178 std::vector<idx_t> partition(graph.nvtxs);
179 idx_t int_parts = nb_parties_;
180 idx_t edgecut = 0; // value returned by metis (total number of joint faces)
181
182 switch(algo_)
183 {
184 case PMETIS:
185 {
186 Cerr << "===============" << finl;
187 Cerr << "Call for PMETIS" << finl;
188 Cerr << "===============" << finl;
189 // See the manual.pdf of METIS 5.0
190 idx_t options[METIS_NOPTIONS];
191 METIS_SetDefaultOptions(options);
192 //options[METIS_OPTION_PTYPE]=METIS_PTYPE_RB|METIS_PTYPE_KWAY; // Methode de partitionnement
193 //options[METIS_OPTION_OBJTYPE]=METIS_OBJTYPE_CUT|METIS_OBJTYPE_VOL; // Objective type
194 //options[METIS_OPTION_CTYPE]=METIS_CTYPE_SHEM|METIS_CTYPE_RM; // Matching scheme during coarsening
195 //options[METIS_OPTION_IPTYPE]=METIS_IPTYPE_GROW; // Algorithm during initial partitioning
196 //options[METIS_OPTION_RTYPE]=METIS_RTYPE_FM; // Algorithm for refinement
197 options[METIS_OPTION_NCUTS]=nb_essais_; // Number of partitionings tested to select the best one
198 options[METIS_OPTION_NUMBERING]=0; // C numbering starting at 0
199 options[METIS_OPTION_DBGLVL]=111111111; // Maximum verbosity mode
200 //options[METIS_OPTION_NO2HOP]=1; // 5.1.0: not perform any 2-hop matchings (as 5.0.3)
201 idx_t ncon=1;
202
203 // Reduced implementation (several default values->nullptr) for METIS 5.0
204 int status = METIS_PartGraphRecursive(&graph.nvtxs, &ncon, graph.xadj.addr(),
205 graph.adjncy.addr(), graph.vwgts.addr(), nullptr, graph.ewgts.addr(),
206 &int_parts, nullptr, nullptr, options,
207 &edgecut, partition.data());
208 if (status != METIS_OK)
209 {
210 Cerr << "Call to METIS failed." << finl;
211 if (status == METIS_ERROR_INPUT) Cerr << "It seems there is an input error." << finl;
212 if (status == METIS_ERROR_MEMORY) Cerr << "It seems it couldn't allocate enough memory." << finl;
213 if (status == METIS_ERROR) Cerr << "It seems there is a METIS internal error." << finl;
214 Cerr << "Contact TRUST support." << finl;
216 }
217 Cerr << "===============" << finl;
218 break;
219 }
220 case KMETIS:
221 {
222 Cerr << " Call for KMETIS" << finl;
223 idx_t options[METIS_NOPTIONS];
224 METIS_SetDefaultOptions(options);
225 //options[METIS_OPTION_PTYPE]=METIS_PTYPE_RB|METIS_PTYPE_KWAY; // Methode de partitionnement
226 //options[METIS_OPTION_OBJTYPE]=METIS_OBJTYPE_CUT|METIS_OBJTYPE_VOL; // Objective type
227 //options[METIS_OPTION_CTYPE]=METIS_CTYPE_SHEM; // Matching scheme during coarsening
228 //options[METIS_OPTION_IPTYPE]=METIS_IPTYPE_GROW; // Algorithm during initial partitioning
229 //options[METIS_OPTION_RTYPE]=METIS_RTYPE_FM; // Algorithm for refinement
230 options[METIS_OPTION_NCUTS]=nb_essais_; // Number of partitionings tested to select the best one
231 options[METIS_OPTION_NUMBERING]=0; // C numbering starting at 0
232 options[METIS_OPTION_DBGLVL]=111111111; // Maximum verbosity mode
233 idx_t ncon=1;
234 // Recommendation from Metis 4.0 doc: METIS_PartGraphKway if int_parts>8, METIS_PartGraphRecursive otherwise...
235 // Indeed seems faster, but the output edgecut is worse...
236 int status = METIS_PartGraphKway(&graph.nvtxs, &ncon, graph.xadj.addr(),
237 graph.adjncy.addr(), graph.vwgts.addr(), nullptr, graph.ewgts.addr(),
238 &int_parts, nullptr, nullptr, options ,
239 &edgecut, partition.data());
240 if (status != METIS_OK)
241 {
242 Cerr << "Call to METIS failed." << finl;
243 if (status == METIS_ERROR_INPUT) Cerr << "It seems there is an input error." << finl;
244 if (status == METIS_ERROR_MEMORY) Cerr << "It seems it couldn't allocate enough memory." << finl;
245 if (status == METIS_ERROR) Cerr << "It seems there is a METIS internal error." << finl;
246 Cerr << "Contact TRUST support." << finl;
248 }
249 break;
250 }
251 default:
252 {
253 Cerr << "Internal error Partitionneur_Metis_32_64: not coded" << finl;
255 }
256 }
257 Cerr << "Partitioning quality : edgecut = " << edgecut << finl;
258 Cerr << "-> It is roughly the total number of edges (faces) which will be shared by the processors." << finl;
259 Cerr << "-> The lesser this number is, the lesser the total volume of communication between processors." << finl;
260 Cerr << "-> You can increase nb_essais option (default 1) to try to reduce (but at a higher CPU cost) this number." << finl;
261 Cerr << "===============" << finl;
262
263 const int_t n = from_idx_t_to_SIZE<_SIZE_>(graph.nvtxs);
264 elem_part.resize(n);
265 for (int_t i = 0; i < n; i++)
266 elem_part[i] = static_cast<int>(partition[i]); // here cast is OK, a partition index (i.e. a proc number) should always be under 32b
267
268 // Correction of the partition for periodicity. (***)
269 if (graph_elements_perio.get_nb_lists() > 0)
270 {
271 Cerr << "Correction of the partition for the periodicity" << finl;
272 this->corriger_bords_avec_liste(ref_domaine_.valeur(), 0, elem_part);
273 Cerr << " If this number is high, you can improve the splitting with the option use_weights\n"
274 << " but it takes more memory)" << finl;
275 }
276
277 if (!use_segment_to_build_connectivite_elem_elem_)
278 {
279 Cerr << "Correction elem0 on processor 0" << finl;
280 this->corriger_elem0_sur_proc0(elem_part);
281 }
282#endif
283}
284
285
286
287template class Partitionneur_Metis_32_64<int>;
288#if INT_is_64_ == 2
290#endif
291
292
Build the graph of the domain that the METIS/PARMETIS/PTSCOTCH libraries need.
ArrOfIdx_ vwgts
void construire_graph_elem_elem(const Domaine_32_64< _SIZE_ > &dom, bool use_weights, Static_Int_Lists_32_64< _SIZE_ > &graph_elements_perio)
void construire_graph_from_segment(const Domaine_32_64< _SIZE_ > &dom, bool use_weights)
ArrOfIdx_ ewgts
ArrOfIdx_ adjncy
ArrOfIdx_ xadj
A character string (Nom) in uppercase.
Definition Motcle.h:26
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
virtual void set_param(Param &) const
Definition Objet_U.h:130
friend class Entree
Definition Objet_U.h:71
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
Helper class to factorize the readOn method of Objet_U classes.
Definition Param.h:112
void ajouter_flag(const char *keyword, const bool *value)
Register a boolean flag whose mere presence switches it to true.
Definition Param.cpp:474
void ajouter_condition(const char *condition, const char *message, const char *name=0)
Declare a post-read logical condition that must hold on the parameter values.
Definition Param.cpp:496
void ajouter(const char *keyword, const int *value, Param::Nature nat=Param::OPTIONAL)
Register an integer parameter.
Definition Param.cpp:364
@ REQUIRED
Definition Param.h:115
void ajouter_non_std(const char *keyword, const Objet_U *value, Param::Nature nat=Param::OPTIONAL)
Register a keyword handled by Objet_U::lire_motcle_non_standard.
Definition Param.cpp:489
Partition of a domain into nb_parties balanced parts using the METIS library.
int lire_motcle_non_standard(const Motcle &, Entree &) override
Reads non-simple-type parameters of an Objet_U from an input stream.
TRUSTVect< int, _SIZE_ > BigIntVect_
void construire_partition(BigIntVect_ &elem_part, int &nb_parts_tot) const override
Computes the connectivity graph for Metis, calls the partitioner and fills elem_part (for each elemen...
Base class for domain partitioners (for splitting a mesh before a parallel computation).
int lire_motcle_non_standard(const Motcle &, Entree &) override
Reads non-simple-type parameters of an Objet_U from an input stream.
static void corriger_bords_avec_liste(const Domaine_t &dom, const int_t my_offset, BigIntVect_ &elem_part)
Computes the periodic element connectivity graphs and calls corriger_periodique_avec_graphe.
static void corriger_elem0_sur_proc0(BigIntVect_ &elem_part)
Corrects the partition so that element 0 of the initial domain is on the first sub-domain of the part...
static bool is_parallel()
Definition Process.cpp:108
static int nproc()
Returns the number of processors in the current group. See Comm_Group::nproc() and PE_Groups::current...
Definition Process.cpp:102
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
Base class for output streams.
Definition Sortie.h:52
This class allows storing lists of integers accessible in constant time.
int_t get_nb_lists() const
Returns the number of stored lists.
_TYPE_ * addr()
void resize(_SIZE_, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTVect.tpp:91