TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Solv_Optimal.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 <Solv_Optimal.h>
16#include <Param.h>
17#include <LecFicDistribueBin.h>
18#include <LecFicDiffuse.h>
19#include <Matrice_Bloc.h>
20#include <Matrice_Morse_Sym.h>
21#include <SFichier.h>
22#include <petsc_for_kernel.h>
23#undef setbit // Otherwise conflict with PETSc
24#include <MD_Vector_tools.h>
25#include <Perf_counters.h>
26
27Implemente_instanciable(Test_solveur,"Test_solveur",Interprete);
28// XD test_solveur interprete test_solveur BRACE To test several solvers
29// XD attr fichier_secmem chaine fichier_secmem OPT Filename containing the second member B
30// XD attr fichier_matrice chaine fichier_matrice OPT Filename containing the matrix A
31// XD attr fichier_solution chaine fichier_solution OPT Filename containing the solution x
32// XD attr nb_test entier nb_test OPT Number of tests to measure the time resolution (one preconditionnement)
33// XD attr impr rien impr OPT To print the convergence solver
34// XD attr solveur solveur_sys_base solveur OPT To specify a solver
35// XD attr fichier_solveur chaine fichier_solveur OPT To specify a file containing a list of solvers
36// XD attr genere_fichier_solveur floattant genere_fichier_solveur OPT To create a file of the solver with a threshold
37// XD_CONT convergence
38// XD attr seuil_verification floattant seuil_verification OPT Check if the solution satisfy ||Ax-B||<precision
39// XD attr pas_de_solution_initiale rien pas_de_solution_initiale OPT Resolution isn\'t initialized with the solution x
40// XD attr ascii rien ascii OPT Ascii files
41
42Implemente_instanciable_sans_constructeur_ni_destructeur(Solv_Optimal,"Solv_Optimal",solv_iteratif);
43// XD optimal solveur_sys_base optimal BRACE Optimal is a solver which tests several solvers of the previous list to
44// XD_CONT choose the fastest one for the considered linear system.
45// XD attr seuil floattant seuil REQ Convergence threshold
46// XD attr impr rien impr OPT To print the convergency of the fastest solver
47// XD attr quiet rien quiet OPT To disable printing of information
48// XD attr save_matrice|save_matrix rien save_matrice OPT To save the linear system (A, x, B) into a file
49// XD attr frequence_recalc entier frequence_recalc OPT To set a time step period (by default, 100) for re-checking the
50// XD_CONT fatest solver
51// XD attr nom_fichier_solveur chaine nom_fichier_solveur OPT To specify the file containing the list of the tested
52// XD_CONT solvers
53// XD attr fichier_solveur_non_recree rien fichier_solveur_non_recree OPT To avoid the creation of the file containing
54// XD_CONT the list
55
57{
58 return s;
59}
60
62{
63 return is;
64}
65
66void test_un_solveur(SolveurSys& solveur, const Matrice_Base& matrice, const DoubleVect& secmem, DoubleVect& solution, int nmax, ArrOfDouble& temps, double seuil_verification=DMAXFLOAT)
67{
68 DoubleVect solution_ref(solution);
69 int n=temps.size_array();
70 statistics().create_custom_counter("Custom solver",1);
71 for (int i=0; i<n; i++)
72 {
73 solution=solution_ref;
74
75 // etape de resolution
76 statistics().begin_count("Custom solver",statistics().get_last_opened_counter_level()+1);
77 double t_0,t;
78 t_0 = statistics().get_total_time("Custom solver");
79 Cout<<"------------------------------------"<<finl;
80 Cout<<"Try " << i << " of solver " << solveur <<finl;
81 //solveur->fixer_limpr(0);
82 solveur.nommer("test_solver");
83
84 solveur.resoudre_systeme(matrice,secmem,solution);
85 t = statistics().get_time_since_last_open("Custom solver");
86 statistics().end_count("Custom solver");
87 // on recupere un delta time et non un time absolu !!
88 DoubleVect test(secmem);
89 test*=-1;
90 matrice.ajouter_multvect(solution,test);
91 //test-=secmem;
92 double norme=mp_norme_vect(test);
93 double time_resol = t-t_0;
94 Cout<<"CPU= " <<time_resol<<" s , ||Ax -b||= " << norme << finl;
96 temps[i]=Process::mp_max(time_resol);
97
98 if (norme>seuil_verification)
99 {
100 Cerr<<"residue calculated greater than the threshold value indicated ("<<seuil_verification<<")"<<finl;
101 Cerr<<" one will not use the solver "<<solveur<<finl;
102 temps=1.e37;
103 }
104 }
105}
106int test_solveur(SolveurSys& solveur, const Matrice_Base& matrice , const DoubleVect& secmem , DoubleVect& solution , int nmax, ArrOfDouble& temps, Entree& list_solveur, double seuil_verification=DMAXFLOAT)
107{
108 DoubleVect solution_ref(solution);
109 int numero=0,numero_best=-1;
110 double best_time=1e36;
111 Motcle motsolveur("solveur"),motlu;
112 list_solveur >> motlu;
113 int dernier=temps.size_array()-1;
114 while (list_solveur.good())
115 {
116 if (motlu!=motsolveur)
117 {
118 Cerr<<" One expected "<<motsolveur <<" and not "<<motlu<<finl;
120 }
121 numero++;
122 SolveurSys newsolveur;
123 list_solveur>>newsolveur;
124 solution=solution_ref;
125 test_un_solveur(newsolveur, matrice, secmem ,solution, nmax, temps, seuil_verification);
126 if (temps[dernier]<best_time)
127 {
128 solveur=newsolveur;
129 best_time=temps[dernier];
130 numero_best=numero;
131 }
132 list_solveur>>motlu;
133 }
134 if (numero_best==-1)
135 {
136 Cerr<<" None of the tested solvers give the expected residue" <<finl;
137 Cerr<< " does the same solver must be kept ? "<<finl;
138 // exit();
139 }
140 temps=best_time;
141 return numero_best;
142}
143/*! @brief Generates a solver test file that differs based on whether the matrix can be solved with or without GCP.
144 *
145 */
146void generate_defaut(const Matrice_Base& matrice, const double seuil, Sortie& sortie, int limpr=0)
147{
148 Nom impr(" impr " );
149 if (limpr==0) impr=" ";
150 if (limpr==-1) impr=" quiet ";
152 {
153 if((!sub_type(Matrice_Morse_Sym,matrice))&&(!sub_type(Matrice_Bloc,matrice)))
154 {
155 sortie <<" solveur gmres { diag seuil "<<seuil <<" "<<impr<<"}"<<finl;
156#ifdef __PETSCKSP_H
157 sortie <<" solveur petsc bicgstab { precond diag { } seuil "<<seuil <<" "<<impr<<"}"<<finl;
158#endif
159 }
160 else
161 {
162 // pressure-type matrix (?)
163 // Update of tested solvers 24/05/2012
164 sortie <<" solveur gcp { precond ssor { omega 1.6 } seuil "<<seuil <<" "<<impr<<"}"<<finl;
165#ifdef __PETSCKSP_H
166 sortie <<" solveur petsc gcp { precond ssor { omega 1.6 } seuil "<<seuil <<" "<<impr<<"}"<<finl;
167 if (Process::nproc()<512)
168 sortie <<" solveur petsc cholesky { impr }"<< finl;
169 else
170 {
171 // For very large runs, switch from Cholesky to BICGSTAB ILU_SP(1) block preconditioner
172 sortie <<" solveur petsc bicgstab { precond block_jacobi_icc { level 1 } seuil "<<seuil <<" "<<impr<<"}"<<finl;
173 // Consider CG ILU_SP(1) by block because BICGSTAB may struggle to converge during the initial projection...
174 sortie <<" solveur petsc gcp { precond block_jacobi_icc { level 1 } seuil "<<seuil <<" "<<impr<<"}"<<finl;
175 }
176 // SPAI has never proven effective (like all Hypre preconditioners), so it is removed
177 //sortie <<" solveur petsc gcp { precond spai { level 2 epsilon 0.2 } seuil "<<seuil <<" "<<impr<<"}"<<finl;
178#endif
179 }
180 }
181}
183{
184 Matrice matrice;
185 DoubleVect secmem,solution;
186 Nom fichier_secmem("Secmem.sa");
187 Nom fichier_solution("Solution.sa");
188 Nom fichier_matrice("Matrice.sa");
189 Nom fichier_solveur;
190 bool pas_de_solution_init=false;
191 bool ascii = false;
192 bool limpr_ = false;
193 double seuil_verification=DMAXFLOAT;
194 SolveurSys solveur;
195 double seuil_list=0;
196 int nb_test=2; // Each solver is tested twice because the first run may be penalised by preconditioning cost
197 Param param((*this).que_suis_je());
198 param.ajouter("fichier_secmem",&fichier_secmem); // filename containing the right-hand side (Secmem.sa by default)
199 param.ajouter("fichier_matrice",&fichier_matrice); // filename containing the matrix (Matrice.sa by default)
200 param.ajouter("fichier_solution",&fichier_solution); // filename containing the solution (Solution.sa by default)
201 param.ajouter("nb_test",&nb_test); // number of solves to measure time (single preconditioning)
202 param.ajouter_flag("impr",&limpr_); // enable solver output
203 param.ajouter("solveur",&solveur); // specify a solver
204 param.ajouter("fichier_solveur",&fichier_solveur); // specify a file containing solvers
205 param.ajouter("genere_fichier_solveur",&seuil_list); // generate the solver file with a given threshold
206 param.ajouter("seuil_verification",&seuil_verification); // check if the solution satisfies ||Ax-b|| < seuil_verification
207 param.ajouter_flag("pas_de_solution_initiale",&pas_de_solution_init); // pas_de_solution_initiale: do not initialize the solve with the current solution
208 param.ajouter_flag("ascii",&ascii); // when files are in ASCII format
210 int binaire=1;
211 if (ascii)
212 binaire=0;
213 // Re-read the matrix and the right-hand side
214 {
215 LecFicDistribue entree;
216 entree.set_bin(binaire);
217 entree.ouvrir(fichier_matrice);
218 entree>>matrice;
219 Cout<<" size of system "<<matrice.valeur( ).nb_colonnes()<<finl;
220 //matrice->imprimer_formatte(Cout);
221 }
222 {
223 LecFicDistribue entree;
224 entree.set_bin(binaire);
225 entree.ouvrir(fichier_secmem);
227 Cout<<" size of system "<<secmem.size_totale()<<finl;
228 }
229
230
231 if (pas_de_solution_init)
232 {
233 solution=secmem;
234 solution=0.;
235 }
236 else
237 {
238 LecFicDistribue entree;
239 entree.set_bin(binaire);
240 entree.ouvrir(fichier_solution);
241
243 Cout<<" size of system "<<solution.size_totale()<<finl;
244 solution.set_md_vector(secmem.get_md_vector());
245 }
246
247 if (seuil_list!=0)
248 {
249 if (fichier_solveur==Nom())
250 fichier_solveur="list_solveur";
251 if (je_suis_maitre())
252 {
253 SFichier list_solveur(fichier_solveur);
254 generate_defaut(matrice,seuil_list,list_solveur,limpr_);
255 }
256 }
257
258 secmem.echange_espace_virtuel();
259 solution.echange_espace_virtuel();
260 ArrOfDouble temps(nb_test);
261 if (fichier_solveur==Nom())
262 test_un_solveur(solveur, matrice , secmem , solution , -10, temps,seuil_verification);
263 else
264 {
265 LecFicDiffuse list_solveur(fichier_solveur);
266 int numero_best=test_solveur(solveur, matrice , secmem , solution , -10, temps,list_solveur,seuil_verification);
267 Cout <<"------------------------------------------------"<<finl;
268 Cout <<"Best solver : number "<<numero_best<<" "<<solveur<<finl;
269 Cout <<"Best CPU time = "<<temps[0]<<finl;
270 Cout <<"------------------------------------------------"<<finl;
271 }
272 return is;
273}
274
275static int numero_solv_optimal=0; // solver number, used to give distinct default solver file names to each solver
276Solv_Optimal::Solv_Optimal():n_resol_(0),n_reinit_(0)
277{
278 freq_recalc_ = (int)(pow(2.0,(double)((sizeof(int)*8)-1))-1);
279 freq_recalc_ = 100;
280 fichier_solveur_="solveurs_";
281 fichier_solveur_+=Nom(numero_solv_optimal);
282 numero_solv_optimal++;
283
284}
285Solv_Optimal::~Solv_Optimal()
286{
287 if (le_solveur_) Cerr<<" The solver used by Solv_Optimal was "<<le_solveur_<<finl;
288}
290{
291 return s;
292}
293
295{
296 bool impr = false;
297 bool quiet = false;
298 Param param((*this).que_suis_je());
299 param.ajouter("seuil",&seuil_,Param::REQUIRED); // convergence threshold
300 param.ajouter_flag("impr",&impr); // enable solver output
301 param.ajouter_flag("quiet",&quiet);
302 param.ajouter("save_matrice|save_matrix",&save_matrice_); // save the linear system A, x, b
303 param.ajouter("frequence_recalc",&freq_recalc_); // frequency for re-evaluating the optimal solver
304 param.ajouter("nom_fichier_solveur",&fichier_solveur_); // filename containing the tested solvers
305 param.ajouter_flag("fichier_solveur_non_recree",&fichier_solveur_non_recree_); // if set, the file is not created at the start of the computation
306 param.lire_avec_accolades_depuis(is);
307 fixer_limpr(impr);
308 if (quiet)
309 fixer_limpr(-1);
310
311 return is;
312}
313
314/*! @brief Key method of Solv_Optimal: at the first iteration,
315 *
316 * generates the file fichier_solveur_ containing the list of solvers to test,
317 * picks the first solver from the file.
318 * At iteration 3 and every freq_recalc_ iterations thereafter, finds the fastest solver,
319 * taking into account whether the matrix has changed.
320 * Calls test_solveur.
321 *
322 */
323void Solv_Optimal::prepare_resol(const Matrice_Base& matrice, const DoubleVect& secmem, DoubleVect& solution, int nmax)
324{
325 if (n_resol_==0)
326 {
327 // First generate the default file, then create the solver from the first entry in the file
328
330 {
331 SFichier list_solveur(fichier_solveur_);
332 generate_defaut(matrice,seuil_,list_solveur,limpr());
333 }
334 LecFicDiffuse list_solveur2(fichier_solveur_);
335 Nom mot;
336 list_solveur2>>mot;
337 list_solveur2>>le_solveur_;
338 }
339 // OK
340 n_resol_++;
341 if ((n_resol_>=3)&&((n_resol_-3)%freq_recalc_==0))
342 {
343 LecFicDiffuse list_solveur(fichier_solveur_);
344 int nb_ite;
345 if (n_reinit_<2)
346 nb_ite=2; // Constant matrix (solved twice; only the second time is kept, free of any preconditioning overhead)
347 else
348 nb_ite=1; // Non-constant matrix (solved only once)
349 ArrOfDouble temps(nb_ite);
350 statistics().end_count(STD_COUNTERS::system_solver,0,0);
351 int numero_best=test_solveur(le_solveur_, matrice , secmem , solution , nmax, temps,list_solveur,seuil_);
352 statistics().begin_count(STD_COUNTERS::system_solver,statistics().get_last_opened_counter_level()+1);
353 Cout <<"------------------------------------------------"<<finl;
354 Cout <<"Best solver : number "<<numero_best<<" "<<le_solveur_<<finl;
355 Cout <<"Best CPU time = "<<temps[0]<<finl;
356 Cout <<"------------------------------------------------"<<finl;
357 if (je_suis_maitre())
358 {
359 Nom best("best_");
360 best+=fichier_solveur_;
361 SFichier sf(best);
362 sf << le_solveur_ <<finl;
363 }
364 }
365}
366int Solv_Optimal::resoudre_systeme(const Matrice_Base& matrice, const DoubleVect& secmem, DoubleVect& solution)
367{
368 prepare_resol(matrice,secmem,solution,-20);
369 return le_solveur_->resoudre_systeme( matrice, secmem, solution);
370}
371int Solv_Optimal::resoudre_systeme(const Matrice_Base& matrice, const DoubleVect& secmem, DoubleVect& solution, int nmax)
372{
373 prepare_resol(matrice,secmem,solution, nmax);
374 return le_solveur_->resoudre_systeme( matrice, secmem, solution, nmax );
375}
376
377
379{
380 n_reinit_++;
381 if (le_solveur_)
382 le_solveur_->reinit();
383}
384
385
386
387
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
virtual int good()
Definition Entree.cpp:270
void set_bin(bool bin) override
Changes the file write mode.
Definition Entree.cpp:291
Base class for "interpreter" objects.
Definition Interprete.h:38
This class implements the operators and virtual methods of the EFichier class as follows: The file to...
This class implements the operators and virtual methods of the EFichier class as follows: there are a...
int ouvrir(const char *name, IOS_OPEN_MODE mode=ios::in) override
Opens the file with the given mode and prot parameters. These parameters are the parameters of the st...
static void restore_vector_with_md(DoubleVect &, Entree &)
restores a vector saved by dump_vector_with_md.
Matrice_Base class - Base class of the matrix hierarchy.
virtual DoubleVect & ajouter_multvect(const DoubleVect &x, DoubleVect &r) const
Matrix-vector multiply-accumulate operation (saxpy).
Matrice_Morse_Sym class - Represents a sparse symmetric matrix M stored in Morse format.
Matrice class - Generic class in the matrix hierarchy.
Definition Matrice.h:34
A character string (Nom) in uppercase.
Definition Motcle.h:26
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
friend class Entree
Definition Objet_U.h:71
virtual Entree & readOn(Entree &)
Reads an Objet_U from an input stream. Virtual method to override.
Definition Objet_U.cpp:289
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(const char *keyword, const int *value, Param::Nature nat=Param::OPTIONAL)
Register an integer parameter.
Definition Param.cpp:364
@ REQUIRED
Definition Param.h:115
int lire_avec_accolades_depuis(Entree &is)
Parse the parameter block { ... } from is.
Definition Param.cpp:32
static double mp_max(double)
Definition Process.cpp:379
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 imprimer_ram_totale(int all_process=0)
Definition Process.cpp:655
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
static int je_suis_maitre()
Returns 1 if on the master processor of the current group (i.e. me() == 0), 0 otherwise.
Definition Process.cpp:82
SFichier is to the C++ ofstream class what Sortie is to the C++ ostream class.
Definition SFichier.h:29
int resoudre_systeme(const Matrice_Base &, const DoubleVect &, DoubleVect &) override
SolveurSys le_solveur_
bool fichier_solveur_non_recree_
void reinit() override
void prepare_resol(const Matrice_Base &matrice, const DoubleVect &secmem, DoubleVect &solution, int nmax=100)
Key method of Solv_Optimal: at the first iteration,.
int limpr() const
void fixer_limpr(int l)
class SolveurSys A SolveurSys represents any class
Definition SolveurSys.h:32
int resoudre_systeme(const Matrice_Base &matrice, const DoubleVect &secmem, DoubleVect &solution)
void nommer(const Nom &nom) override
Definition SolveurSys.h:37
Base class for output streams.
Definition Sortie.h:52
_SIZE_ size_totale() const
Definition TRUSTVect.tpp:61
virtual void set_md_vector(const MD_Vector &)
virtual const MD_Vector & get_md_vector() const
Definition TRUSTVect.h:123
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")
Entree & interpreter(Entree &) override