TrioCFD 1.9.9_beta
TrioCFD documentation
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 // A preconditioner must be defined
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) // If reinit_ = 0, do not touch.
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 // Rebuild the entire structure (index arrays and 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 // Determine the number of items actually used:
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 // Remove virtual items
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 // Note: tab2 of the real-virtual part contains indices
171 // relative to the start of the virtual part (hence "+ sz")
172 const int j = tab2[i]-1 + sz; // fortran -> c
173 renum_[j] = 0;
174 }
175 }
176 // Determine the number of non-empty rows of 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 // Compute the required memory size:
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 // Diagonal coefficients are not stored:
209 nnz_reel_reel = mat.get_coeff().size_array() - sz;
210 }
211 mem_size += (int)(nnz_reel_reel * (int)sizeof(double)); // for the coefficients
212 mem_size += (int)(nnz_reel_reel * (int)sizeof(int)); // for the indices
213 // real/virtual matrix
214 mem_size += (nb_lignes_mat_virt+1) * (int)sizeof(nnz_reel_reel); // for 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)); // for the coefficients
218 mem_size += (int)(nnz_reel_virtuel * (int)sizeof(int)); // for the indices
219 // size of tmp_mat_virt_.lignes_non_vides_
220 mem_size += nb_lignes_mat_virt * (int)sizeof(int);
221 // align size to a multiple of 8
222 if (mem_size % 8 != 0)
223 mem_size = (mem_size/8+1)*8;
224
225 // Allocate arrays:
226 // (double arrays first, then integer arrays at the end;
227 // otherwise padding would be needed to realign doubles after integers)
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_ points to the same memory region:
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 // Allocate arrays for the 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 // Done with doubles; now switch to integer arrays:
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 complete.
265 assert(((char*)iptr) <= ((char*)tmp_data_block_.addr() + mem_size));
266
267 // Fill index arrays (tab1_, tab2_ and lignes_non_vides_)
268 if (! precond_diag_)
269 {
270 tmp_mat_.get_set_tab1().inject_array(mat.get_tab1());
271 {
272 // fill tab2 (with optional renumbering)
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 // Build the matrix D^(-1/2) * A * D^(-1/2)
286 // diagonal coefficients are not stored
287 // Filling tab1_ is non-trivial, hence:
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 // Each row has one fewer coefficient than in the original matrix
295 // (the diagonal coefficient is not stored)
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 // Do not insert the diagonal coefficient
299 assert(mat.get_tab2()(src_index) == i_ligne + 1); // index fortran
300 src_index++;
301 // Insert the remaining coefficients:
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 // End of the last row:
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 // fill 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 // compute D^(-1/2)
356 exit();
357 // compute the product 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// Compute 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 // was n odd to start with?
389 if (n == 0)
390 x_ptr[0] = x_ptr[0] * alpha - y_ptr[0];
391}
392
393// Compute vx += alpha * vy
394// Return value: local sum on this processor of vx[i]*vx[i] (after addition)
395// Warning: not implemented for shared items
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 // was n odd to start with?
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 // residu does not need an up-to-date virtual space
463 // but tmp_p_ does need its virtual space to be up to date...
464 if (optimized)
465 {
467 // compute the product; the scalar product is not used:
468 tmp_mat_virt_.ajouter_mult_vect_et_prodscal(tmp_p_avec_items_virt_, residu_);
469 }
470 else
471 {
473 }
474 // WARNING: it is assumed that secmem has been copied into 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: both sums are computed in a single pass
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 // Display the number of iterations regardless
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)
Same as creer_md_vect_renum() but creates a default numbering.
: This class is an OWN_PTR but the pointed object is shared among multiple
Definition MD_Vector.h:48
Matrice_Base class - Base class of the matrix hierarchy.
virtual DoubleVect & multvect(const DoubleVect &, DoubleVect &) const
Multiplication of a vector by the matrix.
virtual const Matrice & get_bloc(int i, int j) const
Matrice_Morse_Sym class - Represents a sparse symmetric matrix M stored in Morse format.
Matrice_Morse class - Represents a (sparse) matrix M, not necessarily square,.
const auto & get_tab2() const
const auto & get_tab1() const
const auto & get_coeff() const
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
@ 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:208
static Sortie & Journal(int message_level=0)
Returns a static Sortie object used as an event journal.
Definition Process.cpp:592
static double mp_sum(double)
Computes the sum of x over all processors in the current group.
Definition Process.cpp:145
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
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)
Base class for output streams.
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")