TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
Solv_GCP.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 <Solv_GCP.h>
17#include <SSOR.h>
18#include <Param.h>
19#include <Matrice_Bloc_Sym.h>
20#include <Sparskit.h>
21#include <MD_Vector_base.h>
22#include <MD_Vector_tools.h>
23#include <communications.h>
24#include <TRUSTTab_parts.h>
25#include <Perf_counters.h>
26
27Implemente_instanciable_sans_constructeur(Solv_GCP,"Solv_GCP",solv_iteratif);
28// XD solv_gcp solveur_sys_base gcp BRACE Preconditioned conjugated gradient.
29
31{
32 seuil_=1.e-12;
33}
34
36{
37 s<<" { seuil " << seuil_ ;
38 if (le_precond_)
39 s<<" precond " <<le_precond_;
40 else
41 s<<" precond_nul ";
42 if (limpr()==1) s<<" impr ";
43 if (limpr()==-1) s<<" quiet ";
44 if (save_matrice_) s<<" save_matrice " << save_matrice_;
45 if (nb_it_max_!=-1) s<<" nb_it_max "<<nb_it_max_;
46
47 s<<" } ";
48 return s ;
49}
50
52{
53 bool precond_nul = false;
54 bool impr = false;
55 bool quiet = false;
56 Param param((*this).que_suis_je());
57 param.ajouter("seuil",&seuil_,Param::REQUIRED); // XD attr seuil floattant seuil REQ Value of the final residue. The
58 // XD_CONT gradient ceases iteration when the Euclidean residue standard ||Ax-B|| is less than this value.
59 param.ajouter("nb_it_max",&nb_it_max_); // XD attr nb_it_max entier nb_it_max OPT Keyword to set the maximum
60 // XD_CONT iterations number for the Gcp.
61 param.ajouter_flag("impr",&impr); // XD attr impr rien impr OPT Keyword which is used to request display of the
62 // XD_CONT Euclidean residue standard each time this iterates through the conjugated gradient (display to the standard
63 // XD_CONT outlet).
64 param.ajouter_flag("quiet",&quiet); // XD attr quiet rien quiet OPT To not displaying any outputs of the solver.
65 param.ajouter("save_matrice|save_matrix",&save_matrice_); // XD attr save_matrice|save_matrix entier save_matrice OPT
66 // XD_CONT to save the matrix in a file.
67 param.ajouter("precond",&le_precond_); // XD attr precond precond_base precond OPT Keyword to define system
68 // XD_CONT preconditioning in order to accelerate resolution by the conjugated gradient. Many parallel preconditioning
69 // XD_CONT methods are not equivalent to their sequential counterpart, and you should therefore expect differences,
70 // XD_CONT especially when you select a high value of the final residue (seuil). The result depends on the number of
71 // XD_CONT processors and on the mesh splitting. It is sometimes useful to run the solver with no preconditioning at
72 // XD_CONT all. In particular: NL2 - when the solver does not converge during initial projection, NL2 - when comparing
73 // XD_CONT sequential and parallel computations. NL2 With no preconditioning, except in some particular cases (no open
74 // XD_CONT boundary), the sequential and the parallel computations should provide exactly the same results within fpu
75 // XD_CONT accuracy. If not, there might be a coding error or the system of equations is singular.
76 param.ajouter_flag("precond_nul",&precond_nul); // XD attr precond_nul rien precond_nul OPT Keyword to not use a
77 // XD_CONT preconditioning method.
78 param.ajouter_flag("precond_diagonal", &precond_diag_); // XD attr precond_diagonal rien precond_diagonal OPT Keyword
79 // XD_CONT to use diagonal preconditioning.
80 param.ajouter_flag("optimized", &optimized_); // XD attr optimized rien optimized OPT This keyword triggers a memory
81 // XD_CONT and network optimized algorithms useful for strong scaling (when computing less than 100 000 elements per
82 // XD_CONT processor). The matrix and the vectors are duplicated, common items removed and only virtual items really
83 // XD_CONT used in the matrix are exchanged.NL2 Warning: this is experimental and known to fail in some VEF
84 // XD_CONT computations (L2 projection step will not converge). Works well in VDF.
85 param.lire_avec_accolades_depuis(is);
86 // Obligation de definir un precond
87 if (!le_precond_ && precond_nul==0 && precond_diag_==0)
88 {
89 Cerr << "You forgot to define a preconditionner with the keyword precond." << finl;
90 Cerr << "If you don't want a preconditionner, add for the solver definition:" << finl;
91 Cerr << "precond_nul" << finl;
93 }
94 if (precond_nul)
95 {
96 le_precond_.detach();
97 }
98 assert(seuil_>0);
99 if (impr and quiet)
100 {
101 Cerr << "'impr' and 'quiet' keywords in Solv_GCP are not compatible. Use only one of them." << finl;
103 }
104 else if (impr) { fixer_limpr(1); }
105 else if (quiet) { fixer_limpr(-1); }
106 else { fixer_limpr(0);}
107
108 return is;
109}
110
111int Solv_GCP::resoudre_systeme(const Matrice_Base& matrice, const DoubleVect& secmem, DoubleVect& solution)
112{
113 statistics().end_count(STD_COUNTERS::system_solver,-1,0);
114 int n = resoudre_(matrice, secmem, solution, 100);
115 statistics().begin_count(STD_COUNTERS::system_solver,statistics().get_last_opened_counter_level()+1);
116 return n;
117}
118
119int Solv_GCP::resoudre_systeme(const Matrice_Base& matrice, const DoubleVect& secmem, DoubleVect& solution,
120 int nmax)
121{
122 statistics().end_count(STD_COUNTERS::system_solver,-1,0);
123 int n = resoudre_(matrice, secmem, solution, nmax);
124 statistics().begin_count(STD_COUNTERS::system_solver,statistics().get_last_opened_counter_level()+1);
125 return n;
126}
127
128
130{
131 if (reinit_ > 1) // Si reinit_ = 0, ne pas toucher.
132 reinit_ = 1;
134 if (le_precond_)
135 le_precond_->reinit();
136}
137
138void Solv_GCP::prepare_data(const Matrice_Base& matrice, const DoubleVect& secmem, DoubleVect& solution)
139{
140 if (reinit_ == 0)
141 {
142 // Reconstruction de toute la structure (tableaux d'index et coefficients)
143
144 if (secmem.line_size() != 1)
145 {
146 Cerr << "Error line_size>1 not coded (GCP)" << finl;
147 exit();
148 }
149
150 const Matrice_Bloc& mat_bloc = ref_cast(Matrice_Bloc, matrice);
151 const Matrice_Morse_Sym& mat = ref_cast(Matrice_Morse_Sym, mat_bloc.get_bloc(0,0).valeur());
152 const Matrice_Morse& mat_virt = ref_cast(Matrice_Morse, mat_bloc.get_bloc(0,1).valeur());
153
154 // Determination du nombre d'items reellement utilises:
155 {
156 const int sztot_source = secmem.size_array();
157 const int sz = secmem.size();
158 renum_.reset();
159 renum_.resize(sztot_source, RESIZE_OPTIONS::NOCOPY_NOINIT);
160 renum_ = 0;
161 // Retirer les items virtuels
162 int i;
163 for (i = sz; i < sztot_source; i++)
164 renum_[i] = -1;
165 renum_.set_md_vector(secmem.get_md_vector());
166 const auto& tab2 = mat_virt.get_tab2();
167 const auto n = tab2.size_array();
168 for (i = 0; i < n; i++)
169 {
170 // Attention: tab2 de la partie reele-virtuelle contient des indices
171 // relatifs au debut de la partie virtuelle (d'ou "+ sz")
172 const int j = tab2[i]-1 + sz; // fortran -> c
173 renum_[j] = 0;
174 }
175 }
176 // Determination du nombre de lignes non vides de mat_virt
177 int nb_lignes_mat_virt = 0;
178 {
179 const int n = mat_virt.get_tab1().size_array() - 1;
180 for (int i = 0; i < n; i++)
181 if (mat_virt.get_tab1()(i+1) - mat_virt.get_tab1()(i) > 0)
182 nb_lignes_mat_virt++;
183 }
184
185 // Descripteur contenant uniquement les items utiles:
186 MD_Vector md;
188 const int sz_tot = md->get_nb_items_tot();
189 const int sz = md->get_nb_items_reels();
190
191 // Calcul de la taille memoire requise:
192 int mem_size = 0;
193 mem_size += sz_tot * (int)sizeof(double); // vecteurs avec espace virtuel (tmp_p_)
194 mem_size += sz * (int)sizeof(double) * 3; // vecteurs sans espace virtuel
195 const int nb_lignes_mat = sz;
196 // matrice reel/reel
197 auto nnz_reel_reel(mat.get_tab1()(0));
198 nnz_reel_reel = 0;
199 mem_size += (sz + 1) * (int)sizeof(nnz_reel_reel); // pour tab1_
200 assert(mat.get_tab1().size_array() == sz + 1);
201 assert(mat.get_tab2().size_array() == mat.get_coeff().size_array());
202 if (! precond_diag_)
203 {
204 nnz_reel_reel = mat.get_coeff().size_array();
205 }
206 else
207 {
208 // On ne stocke pas les coefficients diagonaux:
209 nnz_reel_reel = mat.get_coeff().size_array() - sz;
210 }
211 mem_size += (int)(nnz_reel_reel * (int)sizeof(double)); // pour les coefficients
212 mem_size += (int)(nnz_reel_reel * (int)sizeof(int)); // pour les indices
213 // matrice reel/virtuel
214 mem_size += (nb_lignes_mat_virt+1) * (int)sizeof(nnz_reel_reel); // pour tab1_
215 const auto nnz_reel_virtuel = mat_virt.get_coeff().size_array();
216 assert(mat_virt.get_tab2().size_array() == nnz_reel_virtuel);
217 mem_size += (int)(nnz_reel_virtuel * (int)sizeof(double)); // pour les coefficients
218 mem_size += (int)(nnz_reel_virtuel * (int)sizeof(int)); // pour les indices
219 // taille de tmp_mat_virt_.lignes_non_vides_
220 mem_size += nb_lignes_mat_virt * (int)sizeof(int);
221 // aligner la taille sur un multiple de 8
222 if (mem_size % 8 != 0)
223 mem_size = (mem_size/8+1)*8;
224
225 // Allocation des tableaux:
226 // (on met d'abord tous les tableaux de double, puis a la fin les tableaux d'entiers
227 // sinon il faut ajouter du padding pour aligner si on remet des double apres de int)
228 //
229 Journal() << "Solv_GCP::prepare allocating data chunk : " << mem_size << " bytes" << finl;
230 tmp_data_block_.resize_array(mem_size/8, RESIZE_OPTIONS::NOCOPY_NOINIT);
231
232 double *ptr = tmp_data_block_.addr();
233 resu_.ref_data(ptr, sz);
234 ptr += sz;
235 residu_.ref_data(ptr, sz);
236 ptr += sz;
237 tmp_p_avec_items_virt_.ref_data(ptr, sz_tot); // avec espace virtuel
238 tmp_p_avec_items_virt_.set_md_vector(md);
239 // tmp_p_ pointe sur la meme domaine:
240 tmp_p_.ref_data(ptr, sz); // sans l'espace virtuel
241 ptr += sz_tot;
242 tmp_solution_.ref_data(ptr, sz);
243 ptr += sz;
244 // Allocation des tableaux pour les matrices:
245 tmp_mat_.get_set_coeff().ref_data(ptr, nnz_reel_reel);
246 ptr += nnz_reel_reel;
247 tmp_mat_virt_.get_set_coeff().ref_data(ptr, nnz_reel_virtuel);
248 ptr += nnz_reel_virtuel;
249 // On a fini les double, on passe aux tableaux d'entiers:
250 // tab1_ stores trustIdType values, tab2_ stores int values
251 using tab1_ptr_t = decltype(tmp_mat_.get_set_tab1().addr());
252 auto * tidptr = static_cast<tab1_ptr_t>(static_cast<void*>(ptr));
253 tmp_mat_.get_set_tab1().ref_data(tidptr, nb_lignes_mat + 1);
254 tidptr += nb_lignes_mat + 1;
255 tmp_mat_virt_.get_set_tab1().ref_data(tidptr, nb_lignes_mat_virt + 1);
256 tidptr += nb_lignes_mat_virt + 1;
257 int * iptr = (int*)tidptr;
258 tmp_mat_.get_set_tab2().ref_data(iptr, (int)nnz_reel_reel);
259 iptr += nnz_reel_reel;
260 tmp_mat_virt_.lignes_non_vides_.ref_data(iptr, nb_lignes_mat_virt);
261 iptr += nb_lignes_mat_virt;
262 tmp_mat_virt_.get_set_tab2().ref_data(iptr, (int)nnz_reel_virtuel);
263 iptr += nnz_reel_virtuel;
264 // Allocation terminee.
265 assert(((char*)iptr) <= ((char*)tmp_data_block_.addr() + mem_size));
266
267 // Remplissages des tableaux d'index (tab1_, tab2_ et lignes_non_vides_)
268 if (! precond_diag_)
269 {
270 tmp_mat_.get_set_tab1().inject_array(mat.get_tab1());
271 {
272 // remplissage de tab2 (renumerotation eventuelle)
273 for (auto i = 0; i < nnz_reel_reel; i++)
274 {
275 int j = mat.get_tab2()(i)-1; // fortran->c
276 int rj = renum_[j];
277 assert(rj < sz_tot);
278 tmp_mat_.get_set_tab2()(i) = rj+1; // c->fortran
279 }
280 }
281 tmp_mat_.set_nb_columns( sz_tot );
282 }
283 else
284 {
285 // Construction de la matrice D^(-1/2) * A * D^(-1/2)
286 // on ne stocke pas les coeffs diagonaux
287 // Le remplissage de tab1_ n'est pas trivial, du coup:
288 {
289 auto src_index = 0; // index dans mat.tab2_ et coeff_
290 auto dest_index = 0; // index dans tmp_mat_.tab2_ et coeff_
291 int i_ligne;
292 for (i_ligne = 0; i_ligne < nb_lignes_mat; i_ligne++)
293 {
294 // A chaque ligne on a un coefficient de moins que dans la matrice d'origine
295 // (on ne met pas le coeff diagonal)
296 tmp_mat_.get_set_tab1()(i_ligne) = dest_index + 1; // indice fortran du debut de ligne
297 const int ncoeff = (int)(mat.get_tab1()(i_ligne+1) - mat.get_tab1()(i_ligne) - 1);
298 // Ne pas inserer le coeff diagonal
299 assert(mat.get_tab2()(src_index) == i_ligne + 1); // index fortran
300 src_index++;
301 // Inserer les autres coeffs:
302 for (int i = 0; i < ncoeff; i++, src_index++, dest_index++)
303 tmp_mat_.get_set_tab2()(dest_index) = mat.get_tab2()(src_index);
304
305 }
306 // Fin de la derniere ligne:
307 tmp_mat_.get_set_tab1()(i_ligne) = dest_index + 1; // indice fortran du debut de ligne
308 }
309 tmp_mat_.set_nb_columns( sz_tot );
310 }
311 // remplissage de tmp_mat_virt_
312 {
313 tmp_mat_virt_.get_set_tab1()[0] = 1;
314 int i_ligne_dest = 0;
315 int dest_index = 0;
316 for (int i_ligne = 0; i_ligne < nb_lignes_mat; i_ligne++)
317 {
318 const int count = (int)(mat_virt.get_tab1()(i_ligne+1) - mat_virt.get_tab1()(i_ligne));
319 if (count > 0)
320 {
321 tmp_mat_virt_.lignes_non_vides_[i_ligne_dest] = i_ligne + 1; // indice fortran
322 tmp_mat_virt_.get_set_tab1()[i_ligne_dest] = dest_index + 1; // index fortran
323 i_ligne_dest++;
324 auto src_index = mat_virt.get_tab1()(i_ligne) - 1; // fortran->c
325 for (int i = 0; i < count; i++, src_index++, dest_index++)
326 {
327 // mat_virt contient des indices fortran relatifs au debut de la partie virtuelle,
328 // on transform en indice C, relatif au vecteur complet
329 int j = mat_virt.get_tab2()(src_index) + sz - 1;
330 int rj = renum_[j];
331 // on stocke dans tmp_mat_virt des indices de colonnes relatifs au vecteur complet
332 // (pas seulement la partie virtuelle)
333 tmp_mat_virt_.get_set_tab2()[dest_index] = rj + 1; // indice fortran
334 }
335 }
336 }
337 // Fin de la derniere ligne:
338 tmp_mat_virt_.get_set_tab1()[i_ligne_dest] = dest_index + 1; // index fortran
339 }
340 reinit_ = 1;
341 }
342
343 if (reinit_ < 2)
344 {
345 const Matrice_Bloc& mat_bloc = ref_cast(Matrice_Bloc, matrice);
346 const Matrice_Morse_Sym& mat = ref_cast(Matrice_Morse_Sym, mat_bloc.get_bloc(0,0).valeur());
347 const Matrice_Morse& mat_virt = ref_cast(Matrice_Morse, mat_bloc.get_bloc(0,1).valeur());
348 if (!precond_diag_)
349 {
350 tmp_mat_.get_set_coeff() = mat.get_coeff();
351 tmp_mat_virt_.get_set_coeff() = mat_virt.get_coeff();
352 }
353 else
354 {
355 // calcul de D^(-1/2)
356 exit();
357 // calcul du produit D^(-1/2) * A * D^(-1/2)
358
359 }
360 reinit_ = 2;
361 }
362
363 if (!precond_diag_)
364 {
365 tmp_solution_.inject_array(solution, tmp_solution_.size());
366 resu_.inject_array(secmem, resu_.size_array());
367 }
368 else
369 {
370 exit();
371 }
372}
373
374// Calcul de vx = vx * alpha - vy
375static void multiply_sub(DoubleVect& vx, DoubleVect& vy, double alpha)
376{
377 int n = vx.size_reelle_ok() ? vx.size() : vx.size_totale();
378 assert(vy.size_totale() >= n);
379 double *x_ptr = vx.addr();
380 double *y_ptr = vy.addr();
381 for (n = n - 1; n > 0; n -= 2, x_ptr += 2, y_ptr += 2)
382 {
383 double a = x_ptr[0] * alpha - y_ptr[0];
384 double b = x_ptr[1] * alpha - y_ptr[1];
385 x_ptr[0] = a;
386 x_ptr[1] = b;
387 }
388 // n etait-il impair au depart ?
389 if (n == 0)
390 x_ptr[0] = x_ptr[0] * alpha - y_ptr[0];
391}
392
393// Calcul de vx += alpha * vy
394// Valeur de retour: somme locale sur ce processeur des vx[i]*vx[i] (apres ajout)
395// Attention: pas code pour les items communs
396static double ajoute_alpha_v_norme(DoubleVect& vx, double alpha, DoubleVect& vy)
397{
398 int n = vx.size();
399 assert(vy.size() == n);
400 double *x_ptr = vx.addr();
401 double *y_ptr = vy.addr();
402 double norme1 = 0., norme2 = 0.;
403 for (n = n - 1; n > 0; n -= 2, x_ptr += 2, y_ptr += 2)
404 {
405 double a = x_ptr[0] + alpha * y_ptr[0];
406 double b = x_ptr[1] + alpha * y_ptr[1];
407 x_ptr[0] = a;
408 x_ptr[1] = b;
409 norme1 += a * a;
410 norme2 += b * b;
411 }
412 // n etait-il impair au depart ?
413 if (n == 0)
414 {
415 double a = x_ptr[0] + alpha * y_ptr[0];
416 x_ptr[0] = a;
417 norme1 += a * a;
418 }
419 return norme1 + norme2;
420}
421
423 const DoubleVect& secmem,
424 DoubleVect& solution,
425 int nmax)
426{
427 const int n_items_reels = solution.size_reelle_ok() ? solution.size_reelle() : solution.size_totale();
428 {
429 const auto nb_items_seq = solution.get_md_vector()->nb_items_seq_tot();
430 const int ls = secmem.line_size();
431 const auto nb_inco_tot = nb_items_seq * ls;
432 auto nmax0 = std::max(nb_inco_tot, (trustIdType)nmax);
433 auto nmaxmax = 10000000;
434 nmax = static_cast<int>(std::min<trustIdType>(nmax0, nmaxmax));
435 }
436
437 const int avec_precond = bool(le_precond_);
438 const int precond_requires_echange_espace_virtuel =
439 avec_precond && (le_precond_->get_flag_updated_input());
440
441 const int optimized = optimized_;
442
443 if (optimized)
444 {
445 prepare_data(matrice, secmem, solution);
446 }
447 else
448 {
449 resu_.reset();
450 residu_.reset();
452 resu_.copy(solution, RESIZE_OPTIONS::NOCOPY_NOINIT);
453 residu_.copy(solution, RESIZE_OPTIONS::NOCOPY_NOINIT);
454 tmp_p_avec_items_virt_.copy(solution, RESIZE_OPTIONS::NOCOPY_NOINIT);
456 tmp_solution_.ref(solution);
457 resu_.inject_array(secmem);
458 }
459
460 tmp_p_avec_items_virt_.inject_array(tmp_solution_, n_items_reels);
461 tmp_p_avec_items_virt_.echange_espace_virtuel();
462 // On n'a pas besoin que residu ait son espace virtuel a jour
463 // En revanche, on a besoin de l'espace virtuel de tmp_p_...
464 if (optimized)
465 {
467 // calcul du produit, le produit scalaire n'est pas utilise:
468 tmp_mat_virt_.ajouter_mult_vect_et_prodscal(tmp_p_avec_items_virt_, residu_);
469 }
470 else
471 {
473 }
474 // ATTENTION: on suppose que secmem a ete copie dans resu_
475 operator_sub(residu_, resu_, VECT_REAL_ITEMS); // ne pas toucher a l'espace virtuel
476
477 if (avec_precond)
478 {
479 if (precond_requires_echange_espace_virtuel)
480 residu_.echange_espace_virtuel();
481
482 if (optimized)
483 le_precond_->preconditionner(tmp_mat_, residu_, tmp_p_);
484 else
485 le_precond_->preconditionner(matrice, residu_, tmp_p_);
486
487 }
488 else
489 {
490 tmp_p_.inject_array(residu_, n_items_reels);
491 }
492
493 // Reduce 3 mp_sum calls to 1 by using mp_sum_for_each
494 double dold = local_prodscal(residu_, tmp_p_);
495 operator_negate(tmp_p_, VECT_REAL_ITEMS);
496 double norme = local_carre_norme_vect(residu_);
497 double norm_b = local_carre_norme_vect(resu_);
498 Process::mp_sum_for_each(dold, norme, norm_b);
499 norme = sqrt(norme);
500 double norme_b = sqrt(norm_b);
501
502 if (limpr()==1)
503 {
504 double norme_relative=(norme_b>DMINFLOAT?norme/(norme_b+DMINFLOAT):norme);
505 Cout << "Norm of the residue: " << norme << " (" << norme_relative << ")" << finl;
506 }
507 int niter = 0;
508 int nb_it_max=nmax;
509 if (nb_it_max_>-1)
510 nb_it_max=nb_it_max_;
511 while ( ( norme > seuil_ ) && (niter++ < nmax) &&( niter<nb_it_max))
512 {
513 // Precondition pour multvect
514 // (le seul echange espace virtuel de l'algo sauf si le precond en a besoin)
515 tmp_p_avec_items_virt_.echange_espace_virtuel();
516 // En revanche, on n'a pas besoin de l'espace virtuel a jour de resu:
517 double resu_scalaire_p_local;
518 if (optimized)
519 {
520 resu_scalaire_p_local = tmp_mat_.multvect_et_prodscal(tmp_p_avec_items_virt_, resu_);
521 resu_scalaire_p_local += tmp_mat_virt_.ajouter_mult_vect_et_prodscal(tmp_p_avec_items_virt_, resu_);
522 }
523 else
524 {
526 resu_scalaire_p_local = local_prodscal(resu_, tmp_p_avec_items_virt_);
527 }
528 const double resu_scalaire_p = mp_sum(resu_scalaire_p_local);
529 const double alfa = dold / resu_scalaire_p;
530 ajoute_alpha_v(tmp_solution_, alfa, tmp_p_, VECT_REAL_ITEMS);
531
532 double norme_residu_locale;
533 if (optimized)
534 {
535 norme_residu_locale = ajoute_alpha_v_norme(residu_, alfa, resu_);
536 }
537 else
538 {
539 ajoute_alpha_v(residu_, alfa, resu_);
540 norme_residu_locale = local_carre_norme_vect(residu_);
541 }
542
543 if(avec_precond)
544 {
545 if (precond_requires_echange_espace_virtuel)
546 residu_.echange_espace_virtuel();
547 if (optimized)
548 le_precond_->preconditionner(tmp_mat_, residu_, resu_);
549 else
550 le_precond_->preconditionner(matrice, residu_, resu_);
551
552 double residu_scalaire_resu = local_prodscal(residu_, resu_);
553 norme = norme_residu_locale;
554 // optimisation: on calcule en une seule fois les deux sommes
555 mp_sum_for_each(residu_scalaire_resu, norme);
556 assert(residu_scalaire_resu >= 0);
557 multiply_sub(tmp_p_, resu_, residu_scalaire_resu / dold);
558 dold = residu_scalaire_resu;
559 }
560 else
561 {
562 const double dnew = mp_carre_norme_vect(residu_);
563 norme = mp_sum(norme_residu_locale);
564 assert(dnew >= 0);
565 multiply_sub(tmp_p_, residu_, dnew / dold);
566 dold = dnew;
567 }
568 norme = sqrt(norme);
569
570 if (limpr()==1)
571 {
572 Cout << norme << " ";
573 if ((niter % 15) == 0) Cout << finl ;
574 }
575 }
576 if ((nb_it_max_<0)&& (norme > seuil_))
577 {
578 Cerr << "No convergence after : " << niter << " iterations\n";
579 Cerr << " Residue : "<< norme << "\n";
580 Cerr << " threshold : "<< seuil_ << "\n";
581 Cerr << "Change your data set." << finl;
582 exit();
583 }
584
585 if (optimized)
586 solution.inject_array(tmp_solution_, n_items_reels);
587
588 // The user wants a result with updated virtual space:
590 solution.echange_espace_virtuel();
591
592 // On affiche quand meme le nombre d'iterations
593 if (limpr()>-1)
594 {
595 double norme_relative=(norme_b>0?norme/(norme_b+DMINFLOAT):norme);
596 Cout << finl;
597 Cout << "Final residue: " << norme << " ( " << norme_relative << " )"<<finl;
598 }
599 return(niter);
600
601}
602
603
604
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
virtual int get_nb_items_tot() const
virtual trustIdType nb_items_seq_tot() const
virtual int get_nb_items_reels() const
static void creer_md_vect_renum_auto(IntVect &flags_renum, MD_Vector &md_vect)
Idem que creer_md_vect_renum() mais cree une numerotation par defaut.
: Cette classe est un OWN_PTR mais l'objet pointe est partage entre plusieurs
Definition MD_Vector.h:48
Classe Matrice_Base Classe de base de la hierarchie des matrices.
virtual DoubleVect & multvect(const DoubleVect &, DoubleVect &) const
Multiplication d'un vecteur par la matrice.
virtual const Matrice & get_bloc(int i, int j) const
Classe Matrice_Morse_Sym Represente une matrice M (creuse) symetrique stockee au format Morse.
Classe Matrice_Morse Represente une matrice M (creuse), non necessairement carree.
const auto & get_tab2() const
const auto & get_tab1() const
const auto & get_coeff() const
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
@ REQUIRED
Definition Param.h:115
static void mp_sum_for_each(T &arg1, T &arg2)
C++14 compatible mp_sum_for_each: combine multiple mp_sum calls into one collective operation Usage: ...
Definition Process.cpp:207
static Sortie & Journal(int message_level=0)
Renvoie un objet statique de type Sortie qui sert de journal d'evenements.
Definition Process.cpp:588
static double mp_sum(double)
Calcule la somme de x sur tous les processeurs du groupe courant.
Definition Process.cpp:146
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
DoubleVect resu_
Definition Solv_GCP.h:62
bool optimized_
Definition Solv_GCP.h:47
DoubleVect tmp_solution_
Definition Solv_GCP.h:69
int nb_it_max_
Definition Solv_GCP.h:87
DoubleVect residu_
Definition Solv_GCP.h:63
ArrOfDouble tmp_data_block_
Definition Solv_GCP.h:77
DoubleVect tmp_p_
Definition Solv_GCP.h:68
void reinit() override
Definition Solv_GCP.cpp:129
bool precond_diag_
Definition Solv_GCP.h:57
Matrice_SuperMorse tmp_mat_virt_
Definition Solv_GCP.h:73
IntVect renum_
Definition Solv_GCP.h:80
int resoudre_(const Matrice_Base &, const DoubleVect &, DoubleVect &, int)
Definition Solv_GCP.cpp:422
int reinit_
Definition Solv_GCP.h:86
int resoudre_systeme(const Matrice_Base &, const DoubleVect &, DoubleVect &) override
Definition Solv_GCP.cpp:111
void prepare_data(const Matrice_Base &matrice, const DoubleVect &secmem, DoubleVect &solution)
Definition Solv_GCP.cpp:138
DoubleVect tmp_p_avec_items_virt_
Definition Solv_GCP.h:59
Matrice_Morse_Sym tmp_mat_
Definition Solv_GCP.h:71
int limpr() const
int get_flag_updated_result() const
virtual void reinit()
void fixer_limpr(int l)
Classe de base des flux de sortie.
Definition Sortie.h:52
_SIZE_ size_array() const
_TYPE_ * addr()
TRUSTArray & inject_array(const TRUSTArray &source, _SIZE_ nb_elements=-1, _SIZE_ first_element_dest=0, _SIZE_ first_element_source=0)
_SIZE_ size() const
Definition TRUSTVect.tpp:45
_SIZE_ size_totale() const
Definition TRUSTVect.tpp:61
int line_size() const
Definition TRUSTVect.tpp:67
_SIZE_ size_reelle() const
Definition TRUSTVect.tpp:27
_SIZE_ size_reelle_ok() const
Definition TRUSTVect.tpp:38
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")