TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
Multigrille_base.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
16#include <Multigrille_base.h>
17#include <Param.h>
18#include <TRUSTTab.h>
19#include <Param.h>
20#include <Schema_Comm_Vecteurs.h>
21#include <communications.h>
22#include <Matrice_Morse_Sym.h>
23#include <IJK_VDF_converter.h>
24//#define DUMP_LATA_ALL_LEVELS
25#ifdef DUMP_LATA_ALL_LEVELS
26#include <IJK_lata_dump.h>
27#include <IJK_Lata_writer.h>
28#endif
29
30// #define DUMP_X_B_AND_RESIDUE_IN_FILE
31#ifdef DUMP_X_B_AND_RESIDUE_IN_FILE
32#include <SFichier.h>
33static int global_count_dump_in_file = 0;
34#endif
35
36Implemente_base_sans_constructeur(Multigrille_base, "Multigrille_base", SolveurSys_base);
37// XD multigrid_solver interprete nul BRACE Object defining a multigrid solver in IJK discretization
38// XD attr coarsen_operators coarsen_operators coarsen_operators OPT Definition of the number of grids that will be
39// XD_CONT used, in addition to the finest (original) grid, followed by the list of the coarsen operators that will be
40// XD_CONT applied to get those grids
41// XD attr ghost_size entier ghost_size OPT Number of ghost cells known by each processor in each of the three
42// XD_CONT directions
43
44Sortie& Multigrille_base::printOn(Sortie& os) const { return os; }
45
47{
48 param.ajouter("relax_jacobi", &relax_jacobi_); // XD_ADD_P list
49 // XD_CONT Parameter between 0 and 1 that will be used in the Jacobi method to solve equation on each grid. Should be
50 // XD_CONT around 0.7
51 param.ajouter("pre_smooth_steps", &pre_smooth_steps_); // XD_ADD_P listentier
52 // XD_CONT First integer of the list indicates the numbers of integers that has to be read next. Following integers
53 // XD_CONT define the numbers of iterations done before solving the equation on each grid. For example, 2 7 8 means
54 // XD_CONT that we have a list of 2 integers, the first one tells us to perform 7 pre-smooth steps on the first grid,
55 // XD_CONT the second one tells us to perform 8 pre-smooth steps on the second grid. If there are more than 2 grids in
56 // XD_CONT the solver, then the remaining ones will have as many pre-smooth steps as the last mentionned number (here,
57 // XD_CONT 8)
58 param.ajouter("smooth_steps", &smooth_steps_); // XD_ADD_P listentier
59 // XD_CONT First integer of the list indicates the numbers of integers that has to be read next. Following integers
60 // XD_CONT define the numbers of iterations done after solving the equation on each grid. Same behavior as
61 // XD_CONT pre_smooth_steps
62 param.ajouter("nb_full_mg_steps", &nb_full_mg_steps_); // XD_ADD_P listentier
63 // XD_CONT Number of multigrid iterations at each level
64 param.ajouter("solveur_grossier", &solveur_grossier_); // XD_ADD_P solveur_sys_base
65 // XD_CONT Name of the iterative solver that will be used to solve the system on the coarsest grid. This resolution
66 // XD_CONT must be more precise than the ones occurring on the fine grids. The threshold of this solver must therefore
67 // XD_CONT be lower than seuil defined above.
68 param.ajouter("check_residu", &check_residu_);
69 param.ajouter("seuil", &seuil_); // XD_ADD_P floattant
70 // XD_CONT Define an upper bound on the norm of the final residue (i.e. the one obtained after applying the multigrid
71 // XD_CONT solver). With hybrid precision, as long as we have not obtained a residue whose norm is lower than the
72 // XD_CONT imposed threshold, we keep applying the solver
73 param.ajouter("iterations_gcp", &max_iter_gcp_);
74 param.ajouter("iterations_gmres", &max_iter_gmres_);
75 param.ajouter("solv_jacobi", &solv_jacobi_);
76 param.ajouter("n_krilov", &n_krilov_);
77 param.ajouter_flag("impr", &impr_); // XD_ADD_P rien
78 // XD_CONT Flag to display some info on the resolution on eahc grid
79 param.ajouter("solver_precision", &solver_precision_); // XD_ADD_P chaine(into=["mixed","double"])
80 // XD_CONT Precision with which the variables at stake during the resolution of the system will be stored. We can have
81 // XD_CONT a simple or double precision or both. In the case of a hybrid precision, the multigrid solver is launched
82 // XD_CONT in simple precision, but the residual is calculated in double precision.
83 param.dictionnaire("double", precision_double_);
84 param.dictionnaire("float", precision_float_);
85 param.dictionnaire("mixed", precision_mix_);
86 param.ajouter("iterations_mixed_solver", &max_iter_mixed_solver_); // XD_ADD_P entier
87 // XD_CONT Define the maximum number of iterations in mixed precision solver
88}
89
92{
93 check_residu_ = 0;
94 seuil_ = 0.;
95 max_iter_gcp_ = 0; // default, use multigrid solver, not gcp
96 max_iter_gmres_ = 0; // default, use multigrid solver, not gmres
97 n_krilov_ = 3;
98 impr_gmres_ = 2;
99 solv_jacobi_ = 0;
101 relax_jacobi_.resize_array(1);
102 relax_jacobi_[0] = 0.65;
103 max_iter_mixed_solver_ = 4;
104}
105
107{
109 return is;
110}
111
112
113
114#ifdef DUMP_X_B_AND_RESIDUE_IN_FILE
115void dump_x_b_residue_in_file(const IJK_Field_float& x, const IJK_Field_float& b,
116 IJK_Field_float& residu, int grid_level, int step_number,
117 Nom comment)
118{
119
121 {
122 const int ni = x.ni();
123 const int j_fix = 3;
124 const int k_fix = 3;
125 Nom n("plot_step");
126 char ss[4];
127 snprintf(ss, 4, "%03d", step_number);
128 n += Nom(ss);
129 n += Nom("_level");
130 n += Nom(grid_level);
131 n += Nom(".txt");
132 SFichier f(n/* , ios::out --> default*/);
133 f.setf(ios::scientific);
134 for (int i = 0; i < ni; i++)
135 {
136 const float xx = x(i,j_fix, k_fix);
137 const float bb = b(i,j_fix, k_fix);
138 const float rr = residu(i,j_fix, k_fix);
139 f << i << " " << xx << " " << bb << " " << rr << finl;
140 }
141 Cout << "STEP " << global_count_dump_in_file << " at grid level " << grid_level << " " << comment << finl;
142 global_count_dump_in_file++;
143 }
144}
145
146void dump_x_b_residue_in_file(const IJK_Field_double& x, const IJK_Field_double& b, IJK_Field_double& residu,
147 int grid_level, int step_number, Nom comment)
148{
149
151 {
152 const int ni = x.ni();
153 const int j_fix = 3;
154 const int k_fix = 3;
155 Nom n("plot_step");
156 char ss[4];
157 snprintf(ss, 4, "%03d", step_number);
158 n += Nom(ss);
159 n += Nom("_level");
160 n += Nom(grid_level);
161 n += Nom(".txt");
162 SFichier f(n/* , ios::out --> default*/);
163 f.setf(ios::scientific);
164 for (int i = 0; i < ni; i++)
165 {
166 const double xx = x(i,j_fix, k_fix);
167 const double bb = b(i,j_fix, k_fix);
168 const double rr = residu(i,j_fix, k_fix);
169 f << i << " " << xx << " " << bb << " " << rr << finl;
170 }
171 Cout << "STEP " << global_count_dump_in_file << " at grid level " << grid_level << " " << comment << finl;
172 global_count_dump_in_file++;
173 }
174}
175#endif
176
177
178
189
190int Multigrille_base::resoudre_systeme(const Matrice_Base& a, const DoubleVect& b, DoubleVect& x, int n)
191{
192 resoudre_systeme(a, b, x);
193 return 1;
194}
195
196// This solver does not need rhs to have updated virtual space
198{
199 return 0;
200}
201
203{
204 int i1 = level;
205 int i2 = level;
206 if (level > pre_smooth_steps_.size_array() - 1)
207 i1 = pre_smooth_steps_.size_array() - 1;
208 if (level > smooth_steps_.size_array() - 1)
209 i2 = smooth_steps_.size_array() - 1;
210 int nsweeps = std::max(pre_smooth_steps_[i1], smooth_steps_[i2]) + 1;
211 return nsweeps;
212}
213
214
215template <>
217{
218 IJK_Field_float& ijk_b = get_storage_float(STORAGE_RHS, 0);
219 IJK_Field_float& ijk_x = get_storage_float(STORAGE_X, 0);
220 IJK_Field_float& ijk_residu = get_storage_float(STORAGE_RESIDUE, 0);
221
222 prepare_secmem(ijk_b);
223 //pas sur de devoir echanger espace virtuel pour le second membre dans le cas du shear_perio...
225 {
226 ijk_b.echange_espace_virtuel(ijk_b.ghost());
227 }
228
229 double norm_residue;
230 norm_residue = multigrille(ijk_x, ijk_b, ijk_residu);
231 if (norm_residue > seuil_)
232 {
233 Cerr << "Error in Multigrille_base: single precision pure multigrid solver did not converge to requested precision ("
234 << seuil_ << ")\n Residue at end of solver= " << norm_residue << finl;
236 }
237}
238
239template <>
241{
242 IJK_Field_double& ijk_b = get_storage_double(STORAGE_RHS, 0);
243 IJK_Field_double& ijk_x = get_storage_double(STORAGE_X, 0);
244 IJK_Field_double& ijk_residu = get_storage_double(STORAGE_RESIDUE, 0);
245
246 prepare_secmem(ijk_b);
247 //pas sur de devoir echanger espace virtuel pour le second membre dans le cas du shear_perio...
249 {
250 ijk_b.echange_espace_virtuel(ijk_b.ghost());
251 }
253 {
254 if (max_iter_gcp_ > 0)
255 {
256 resoudre_avec_gcp(ijk_x, ijk_b, ijk_residu);
257 }
258 else if (max_iter_gmres_ > 0)
259 {
260 resoudre_avec_gmres(ijk_x, ijk_b, ijk_residu);
261 }
262 else if (solv_jacobi_ > 0)
263 {
264 static int fcount = 0;
265 ijk_x.data() = 0.;
266 for (int i = 0; i < solv_jacobi_; i++)
267 {
268 jacobi_residu(ijk_x, &ijk_b, 0, 2 /* jacobi iterations */, &ijk_residu);
269 dump_lata("x", ijk_x, fcount);
270 dump_lata("residu", ijk_residu, fcount);
271 fcount++;
272 }
273 }
274 else
275 {
276 const double norm_residue = multigrille(ijk_x, ijk_b, ijk_residu);
277 if (norm_residue > seuil_)
278 {
279 Cerr << "Error in Multigrille_base: double precision pure multigrid solver did not converge to requested precision ("
280 << seuil_ << ")\n Residue at end of solver= " << norm_residue << finl;
282 }
283 }
284 }
285 else
286 {
287 // mixed precision solver
288 ijk_x.data() = 0.;
289 IJK_Field_float& float_b = get_storage_float(STORAGE_RHS, 0);
290 IJK_Field_float& float_x = get_storage_float(STORAGE_X, 0);
291 IJK_Field_float& float_residue = get_storage_float(STORAGE_RESIDUE, 0);
292 float_b.data() = 0.;
293
294 const int ni = ijk_x.ni();
295 const int nj = ijk_x.nj();
296 const int nk = ijk_x.nk();
297
298 for (int k = 0; k < nk; k++)
299 for (int j = 0; j < nj; j++)
300 for (int i = 0; i < ni; i++)
301 float_b(i, j, k) = (float)ijk_b(i, j, k);
302
303 int iteration = 0;
304 do
305 {
306 if (iteration > 0)
307 for (int k = 0; k < nk; k++)
308 for (int j = 0; j < nj; j++)
309 for (int i = 0; i < ni; i++)
310 float_b(i, j, k) = (float)(-ijk_residu(i, j, k));
311
312
313 // Launch multigrid solver in single precision:
314 float_x.data() = 0.;
315 prepare_secmem(float_b);
316 //pas sur de devoir echanger espace virtuel pour le second membre dans le cas du shear_perio...
318 float_b.echange_espace_virtuel(float_b.ghost());
319 float_x.shift_k_origin(needed_kshift_for_jacobi(0) - float_x.k_shift());
320 const double single_precision_residue = multigrille(float_x, float_b, float_residue);
321
322 // Update x:
323 for (int k = 0; k < nk; k++)
324 for (int j = 0; j < nj; j++)
325 for (int i = 0; i < ni; i++)
326 ijk_x(i, j, k) += float_x(i, j, k);
327
328 if (single_precision_residue < seuil_)
329 break;
330
331 // Compute residue in double precision:
332 jacobi_residu(ijk_x, &ijk_b, 0, 0 /* jacobi iterations */, &ijk_residu);
333 const double nr = norme_ijk(ijk_residu);
334 if (impr_)
335 Cout << "Mixed precision solver iteration " << iteration
336 << " singleprecision residue= " << single_precision_residue
337 << " doubleprecision residue= " << nr << finl;
338
339 iteration++;
340 if (iteration > max_iter_mixed_solver_)
341 {
342 // Try to solve system on original grid with other solver
343 const double norme_residu_gcp = multigrille_failure();
344 if (norme_residu_gcp < seuil_)
345 break;
346 else
347 {
348 Cerr << "Error in Multigrille_base: mixed precision solver did not converge in "
349 << max_iter_mixed_solver_ << " iterations." << finl;
350 Cerr << " seuil is " << seuil_ << " and the norm of the GCP residu is " << norme_residu_gcp;
351 Process::exit("GCP did not converge after failure!\n");
352 }
353 }
354 }
355 while (1);
356 }
357}
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
void echange_espace_virtuel(int ghost)
Exchange data over "ghost" number of cells.
Classe Matrice_Base Classe de base de la hierarchie des matrices.
virtual int needed_kshift_for_jacobi(int level) const =0
virtual void ajouter_param(Param &)
virtual double multigrille_failure()=0
virtual void prepare_secmem(IJK_Field_float &x) const =0
void solve_ijk_in_storage_template()
virtual IJK_Field_float & get_storage_float(StorageId, int level)=0
virtual void dump_lata(const Nom &field, const IJK_Field_float &data, int tstep) const =0
int get_flag_updated_input() const override
virtual IJK_Field_double & get_storage_double(StorageId, int level)=0
const int precision_double_
int resoudre_systeme(const Matrice_Base &a, const DoubleVect &b, DoubleVect &x, int) override
void resoudre_avec_gmres(IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &x, IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &b, IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &residu)
void resoudre_avec_gcp(IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &x, IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &b, IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &residu)
double multigrille(IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &x, const IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &b, IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &residu)
void resoudre_systeme_template(const Matrice_Base &a, const DoubleVect &b, DoubleVect &x)
virtual void jacobi_residu(IJK_Field_float &x, const IJK_Field_float *secmem, const int grid_level, const int n_jacobi, IJK_Field_float *residu) const =0
int nsweeps_jacobi_residu(int level) const
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
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 dictionnaire(const char *option_name, int value)
Add an (option name, integer value) entry to the dictionary attached to a previously registered integ...
Definition Param.cpp:293
void ajouter(const char *keyword, const int *value, Param::Nature nat=Param::OPTIONAL)
Register an integer parameter.
Definition Param.cpp:364
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
static int je_suis_maitre()
renvoie 1 si on est sur le processeur maitre du groupe courant (c'est a dire me() == 0),...
Definition Process.cpp:86
Cette classe est a la classe C++ ofstream ce que la classe Sortie est a la classe C++ ostream Elle re...
Definition SFichier.h:27
Classe de base des flux de sortie.
Definition Sortie.h:52