TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
Multigrille_base.tpp
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#ifndef Multigrille_base_TPP_H
17#define Multigrille_base_TPP_H
18
19#include <IJK_VDF_converter.h>
20#include <Matrice_Morse_Sym.h>
21#include <IJK_Vector.h>
22#include <Interprete_bloc.h>
23#include <Perf_counters.h>
24#include <Process.h>
25
26template <typename _TYPE_, typename _TYPE_ARRAY_>
35
36template <typename _TYPE_FUNC_, typename _TYPE_, typename _TYPE_ARRAY_>
38{
42 int i, j, k;
43 const int imax = x.ni();
44 const int jmax = x.nj();
45 const int kmax = x.nk();
46 for (k = 0; k < kmax; k++)
47 for (j = 0; j < jmax; j++)
48 for (i = 0; i < imax; i++)
49 {
50 ijk_b(i,j,k) = (_TYPE_FUNC_)rhs(i,j,k);
51 }
52
54
55 for (k = 0; k < kmax; k++)
56 for (j = 0; j < jmax; j++)
57 for (i = 0; i < imax; i++)
58 {
59 x(i,j,k) = (_TYPE_)ijk_x(i,j,k);
60 }
61}
62
63
64// Can be further optimized for float (extend Schema_Comm_Vecteurs to float)
65template <typename _TYPE_, typename _TYPE_ARRAY_>
67{
68 // fetch the vdf_to_ijk translator (assume there is one unique object, with conventional name)
69 const Nom& ijkdis_name = IJK_VDF_converter::get_conventional_name();
70 const IJK_VDF_converter& ijkdis = ref_cast(IJK_VDF_converter, Interprete_bloc::objet_global(ijkdis_name));
72}
73
74// Can be further optimized for float (extend Schema_Comm_Vecteurs to float)
75template <typename _TYPE_, typename _TYPE_ARRAY_>
77{
78 // fetch the vdf_to_ijk translator (assume there is one unique object, with conventional name)
79 const Nom& ijkdis_name = IJK_VDF_converter::get_conventional_name();
80 const IJK_VDF_converter& ijkdis = ref_cast(IJK_VDF_converter, Interprete_bloc::objet_global(ijkdis_name));
82}
83
84template <typename _TYPE_, typename _TYPE_ARRAY_>
89
90// Methode recursive qui resout A*x = b et calcule residu = A*x-b
91// pour le niveau de grille grid_level.
92// Si grid_level = niveau grossier, appel a coarse_solver,
93// sinon iterations sur
94// pre_smoothing, coarsening, appel recursif, interpolation, post_smoothing
95// input: b
96// output: x, residu
97// return value = L2 norm of the residue
98template <typename _TYPE_, typename _TYPE_ARRAY_>
100 int grid_level, int iter_number)
101{
102 statistics().create_custom_counter("projection: multigrid",2,"IJK");
103 double norme_residu_final = 0.;
104 const int needed_kshift = needed_kshift_for_jacobi(grid_level + 1);
105#ifdef DUMP_LATA_ALL_LEVELS
106 IJK_Field_template<_TYPE_,_TYPE_ARRAY_> copy_residu_for_post(residu);
107 copy_residu_for_post.data() = 0.;
109 IJK_Field_template<_TYPE_,_TYPE_ARRAY_> copy_xini_for_post(x);
110 copy_xini_for_post.data() = x.data();
111#endif
112#ifdef DUMP_X_B_AND_RESIDUE_IN_FILE
113 dump_x_b_residue_in_file(x,b,residu, grid_level, global_count_dump_in_file, Nom("avt pre-smooth / recursive call / coarse solver"));
114#endif
115 // Recurse
116 if (grid_level < nb_grid_levels() - 1)
117 {
118 // Pre-smooting
119 {
120 statistics().begin_count("projection: multigrid",statistics().get_last_opened_counter_level()+1);
121 const int pss = (grid_level >= pre_smooth_steps_.size_array())
122 ? pre_smooth_steps_[pre_smooth_steps_.size_array()-1]
123 : pre_smooth_steps_[grid_level];
124 jacobi_residu(x, &b, grid_level, pss /* jacobi iterations */, &residu);
125#ifdef DUMP_X_B_AND_RESIDUE_IN_FILE
126 dump_x_b_residue_in_file(x,b,residu, grid_level, global_count_dump_in_file, Nom("apres pre-smooth"));
127#endif
128 }
129#ifdef DUMP_LATA_ALL_LEVELS
130 copy_x_for_post.data() = x.data();
131#endif
132
133 norme_residu_final = norme_ijk(residu);
134
135 if (impr_)
136 Cout << "level=" << grid_level << " residu(pre)=" << norme_residu_final << finl;
137
141
142 const int nmax = nb_full_mg_steps_.size_array() - 1;
143 int nb_full = 1;
144 if (iter_number != 0 || grid_level <= 1)
145 {
146 if (grid_level > nmax)
147 nb_full = nb_full_mg_steps_[nmax];
148 else
149 nb_full = nb_full_mg_steps_[grid_level];
150 }
151
152 for (int fmg_step = 0; fmg_step < nb_full; fmg_step++)
153 {
154#ifdef DUMP_LATA_ALL_LEVELS
155 copy_residu_for_post = residu;
156#endif
157 // Coarsen residual
158 coarse_b.data() = 0.;
159 coarsen(residu, coarse_b, grid_level);
160
161 // It seems that the residue has non zero sum due to accumulation of
162 // roundoff errors when computing A*x. At the coarse level, we get
163 // a wrong rhs...
164 prepare_secmem(coarse_b);
165
166 // We need one less layer on b than on x to compute jacobi or residue
168 {
169 //pas sur de devoir echanger espace virtuel pour le second membre dans le cas du shear_perio...
170 coarse_b.echange_espace_virtuel(b.ghost()-1);
171 }
172 // Solve for coarse_x
173 coarse_x.shift_k_origin(needed_kshift - coarse_x.k_shift());
174 coarse_x.data() = 0.;
175 //coarse_x.shift_k_origin(coarse_x.k_shift_max() - coarse_x.k_shift());
176#ifdef DUMP_X_B_AND_RESIDUE_IN_FILE
177 // inutile : idem avt avt-presmooth pour grid-level+1
178 // dump_x_b_residue_in_file(coarse_x,coarse_b,coarse_residu, grid_level+1, global_count_dump_in_file, Nom("avt recursive-call"));
179#endif
180 statistics().end_count("projection: multigrid");
181
182 multigrille_(coarse_x, coarse_b, coarse_residu, grid_level+1, fmg_step);
183 statistics().begin_count("projection: multigrid",statistics().get_last_opened_counter_level()+1);
184
185#ifdef DUMP_X_B_AND_RESIDUE_IN_FILE
186 dump_x_b_residue_in_file(coarse_x,coarse_b,coarse_residu, grid_level+1, global_count_dump_in_file, Nom("avt interpol / apres recursive-call/jacobi-residu/ou/coarse-solver "));
187#endif
188
189 // Interpolate and substract to x
190 // Shift by n layers in k for the next jacobi_residu call
191 interpolate_sub_shiftk(coarse_x, x, grid_level);
192#ifdef DUMP_X_B_AND_RESIDUE_IN_FILE
193 IJK_Field_template<_TYPE_,_TYPE_ARRAY_> copy_x_to_compute_res(x);
194 copy_x_to_compute_res.data() = x.data();
195 const int g = x.ghost();
196 const int imin = x.linear_index(-g,-g,-g);
197 const int imax = x.linear_index(x.ni()-1+g, x.nj()-1+g, x.nk()-1+g) + 1;
198 assert(imin == copy_x_to_compute_res.linear_index(-g,-g,-g));
199 assert(imax == copy_x_to_compute_res.linear_index(x.ni()-1+g, x.nj()-1+g, x.nk()-1+g) + 1);
200 _TYPE_ *ptr = x.data().addr();
201 const _TYPE_ *ptr2 = copy_x_to_compute_res.data().addr();
202 for (int i = imin; i < imax; i++)
203 ptr[i] -= ptr2[i];
204
205 jacobi_residu<_TYPE_, _TYPE_ARRAY_>(copy_x_to_compute_res, &b, grid_level, 0 /* no jacobi iterations, just compute residu */, &residu);
206 dump_x_b_residue_in_file(x,b,residu, grid_level, global_count_dump_in_file, Nom("apres interpol"));
207#endif
208 // Post smoothing iterations
209 {
210 const int postss = (grid_level >= smooth_steps_.size_array())
211 ? smooth_steps_[smooth_steps_.size_array()-1]
212 : smooth_steps_[grid_level];
213 jacobi_residu(x, &b, grid_level, postss /* jacobi iterations */, &residu);
214 }
215#ifdef DUMP_X_B_AND_RESIDUE_IN_FILE
216 dump_x_b_residue_in_file(x,b,residu, grid_level, global_count_dump_in_file, Nom("apres post-smooth"));
217#endif
218#ifdef DUMP_LATA_ALL_LEVELS
219 {
220 static ArrOfInt step;
221 if (step.size_array() < grid_level + 1)
222 step.resize_array(grid_level + 1);
223
224 const Nom lata_name = Nom("Multigrid_level") + Nom(grid_level) + Nom(".lata");
225 if (step[grid_level] == 0)
226 {
227 Nom dom = Nom("DOM")+Nom(grid_level);
228 Domaine_IJK& geom = ref_cast_non_const(Domaine_IJK,x.get_domaine() );
229 geom.nommer(dom); // On nomme la geom pour pouvoir l'ecrire.
230 dumplata_header(lata_name, x /* on passe un champ pour ecrire la geometrie */);
231 }
232 dumplata_newtime(lata_name,step[grid_level]);
233 dumplata_scalar(lata_name, "xini", copy_x_for_post, step[grid_level]);
234 dumplata_scalar(lata_name, "x1", copy_x_for_post, step[grid_level]);
235 dumplata_scalar(lata_name, "xf", x, step[grid_level]);
236 dumplata_scalar(lata_name, "b", b, step[grid_level]);
237 dumplata_scalar(lata_name, "residu1", copy_residu_for_post, step[grid_level]);
238 dumplata_scalar(lata_name, "residue", residu, step[grid_level]);
239 step[grid_level]++;
240 }
241#endif
242
243 norme_residu_final = norme_ijk(residu);
244 if (impr_)
245 Cout << "level=" << grid_level << " residu=" << norme_residu_final << finl;
246 // use threshold criteria only if pure multigrid (not gcp with mg preconditionning)
247 if (grid_level == 0 && norme_residu_final < seuil_ && max_iter_gcp_ == 0)
248 break;
249 }
250 statistics().end_count("projection: multigrid");
251 }
252 else
253 {
254 statistics().begin_count("projection: multigrid",statistics().get_last_opened_counter_level()+1);
255#ifdef DUMP_X_B_AND_RESIDUE_IN_FILE
256 // inutile : idem avt avt-presmooth pour grid-level
257 // dump_x_b_residue_in_file(x,b,residu, grid_level, global_count_dump_in_file, Nom("avt coarse-solver"));
258#endif
259 coarse_solver(x, b);
260#ifdef DUMP_X_B_AND_RESIDUE_IN_FILE
261 // inutile : idem avt interpol
262 // dump_x_b_residue_in_file(x,b,residu, grid_level, global_count_dump_in_file, Nom("apres coarse-solver"));
263#endif
264 jacobi_residu(x, &b, grid_level, 0 /* not jacobi */, &residu);
265#ifdef DUMP_X_B_AND_RESIDUE_IN_FILE
266 // inutile : idem avt interpol
267 // dump_x_b_residue_in_file(x,b,residu, grid_level, global_count_dump_in_file, Nom("apres jacobi-residu"));
268#endif
269
270
271 norme_residu_final = norme_ijk(residu);
272
273 if (impr_)
274 Cout << finl << "level=" << grid_level << " residu=" << norme_residu_final
275 << " (coarse solver)" << finl;
276#ifdef DUMP_LATA_ALL_LEVELS
277 {
278 static ArrOfInt step;
279 if (step.size_array() < grid_level + 1)
280 step.resize_array(grid_level + 1);
281
282 const Nom lata_name = Nom("Multigrid_level") + Nom(grid_level) + Nom(".lata");
283 if (step[grid_level] == 0)
284 {
285 Nom dom = Nom("DOM")+Nom(grid_level);
286 x.get_splitting_non_const().get_grid_geometry_non_const().nommer(dom); // On nomme la geom pour pouvoir l'ecrire.
287 dumplata_header(lata_name, x /* on passe un champ pour ecrire la geometrie */);
288 }
289 dumplata_newtime(lata_name,step[grid_level]);
290 dumplata_scalar(lata_name, "x", x, step[grid_level]);
291 dumplata_scalar(lata_name, "b", b, step[grid_level]);
292 dumplata_scalar(lata_name, "residue", residu, step[grid_level]);
293 step[grid_level]++;
294 }
295#endif
296 statistics().end_count("projection: multigrid");
297
298 }
299 return norme_residu_final;
300}
301
302template <typename _TYPE_, typename _TYPE_ARRAY_>
304{
305 const Matrice_Grossiere& mat = coarse_matrix_;
306
307 DoubleVect inco;
308 DoubleVect secmem;
309 const MD_Vector& md = mat.md_vector();
310 inco.resize(md->get_nb_items_tot());
311 inco.set_md_vector(md);
312 secmem = inco;
313
314 int ni = x.ni();
315 int nj = x.nj();
316 int nk = x.nk();
317 int i, j, k;
318
319 for (k = 0; k < nk; k++)
320 for (j = 0; j < nj; j++)
321 for (i = 0; i < ni; i++)
322 secmem[mat.renum(i,j,k)] = b(i,j,k);
323
324 //pas sur de devoir echanger espace virtuel pour le second membre dans le cas du shear_perio...
326 {
327 secmem.echange_espace_virtuel();
328 }
329 solveur_grossier_.resoudre_systeme(mat.matrice(), secmem, inco);
330
331 for (k = 0; k < nk; k++)
332 for (j = 0; j < nj; j++)
333 for (i = 0; i < ni; i++)
334 x(i,j,k) = (_TYPE_)inco[mat.renum(i,j,k)]; //!!!!!!!!!!!!!!!!!! ToDo WARNING: potentiellement conversion de double en float!!!!!!!!!!!!!!!!!!!!!!!!!!!!
335
336}
337
338template <typename _TYPE_, typename _TYPE_ARRAY_>
340{
341 const int g = x.ghost();
342 const int imin = x.linear_index(-g,-g,-g);
343 const int imax = x.linear_index(x.ni()-1+g, x.nj()-1+g, x.nk()-1+g) + 1;
344 _TYPE_ *ptr = x.data().addr();
345 for (int i = imin; i < imax; i++)
346 ptr[i] = -ptr[i];
347}
348
349template <typename _TYPE_, typename _TYPE_ARRAY_>
350void op_multiply(IJK_Field_template<_TYPE_,_TYPE_ARRAY_>& x, _TYPE_ a)
351{
352 const int g = x.ghost();
353 const int imin = x.linear_index(-g,-g,-g);
354 const int imax = x.linear_index(x.ni()-1+g, x.nj()-1+g, x.nk()-1+g) + 1;
355 _TYPE_ *ptr = x.data().addr();
356 for (int i = imin; i < imax; i++)
357 ptr[i] *= a;
358}
359
360template <typename _TYPE_, typename _TYPE_ARRAY_>
362{
363 const int g = x.ghost();
364 const int imin = x.linear_index(-g,-g,-g);
365 const int imax = x.linear_index(x.ni()-1+g, x.nj()-1+g, x.nk()-1+g) + 1;
366 assert(imin == y.linear_index(-g,-g,-g));
367 assert(imax == y.linear_index(x.ni()-1+g, x.nj()-1+g, x.nk()-1+g) + 1);
368 _TYPE_ *ptr = x.data().addr();
369 const _TYPE_ *ptr2 = y.data().addr();
370 for (int i = imin; i < imax; i++)
371 ptr[i] -= ptr2[i];
372}
373
374template <typename _TYPE_, typename _TYPE_ARRAY_>
375void ajoute_alpha_v(IJK_Field_template<_TYPE_,_TYPE_ARRAY_>& x, _TYPE_ alpha, const IJK_Field_template<_TYPE_,_TYPE_ARRAY_>& v)
376{
377 const int g = x.ghost();
378 const int imin = x.linear_index(-g,-g,-g);
379 const int imax = x.linear_index(x.ni()-1+g, x.nj()-1+g, x.nk()-1+g) + 1;
380 assert(imin == v.linear_index(-g,-g,-g));
381 assert(imax == v.linear_index(x.ni()-1+g, x.nj()-1+g, x.nk()-1+g) + 1);
382 _TYPE_ *ptr = x.data().addr();
383 const _TYPE_ *ptr2 = v.data().addr();
384 for (int i = imin; i < imax; i++)
385 ptr[i] += alpha * ptr2[i];
386}
387
388// Ne semble pas fonctionner (manque juste echange espace virtuel sur second membre ?)
389template <typename _TYPE_, typename _TYPE_ARRAY_>
391{
393 alloc_field(Z, 0);
394 alloc_field(P, 0);
395 alloc_field(R, 0);
396 x.data() = 0.;
397 R.data() = b.data();
398 op_negate(R);
399
400 multigrille(P, R, residu);
401
402 _TYPE_ dold = prod_scal_ijk(R, P);
403 op_negate(P);
404
405 for (int iter = 0; iter < max_iter_gcp_; iter++)
406 {
407 // calcul de AP = A * P
408 jacobi_residu(P, 0 /* secmem */, 0 /* grid_level */, 0 /* no jacobi */, &residu);
409
410 _TYPE_ alpha = dold / prod_scal_ijk(P, residu);
411
412 Cout << "alpha=" << alpha << " normeP=" << norme_ijk(P) << " dold=" << dold << finl;
413
414 ajoute_alpha_v(x, alpha, P);
415
416 ajoute_alpha_v(R, alpha, residu);
417
418 _TYPE_ nr = (_TYPE_)norme_ijk(R);
419 Cout << "GCP+MG iteration " << iter << " residu " << nr << finl;
420 if (nr < seuil_)
421 break;
422
423 if (iter == max_iter_gcp_)
424 {
425 Cerr << "Non convergence de Multigrille_poreux::resoudre_avec_gcp en " << max_iter_gcp_
426 << " iterations" << finl;
427 break;
428 }
429
430 // preconditionner
431 multigrille(Z, R, residu);
432
433 _TYPE_ prodscal_RZ = prod_scal_ijk(R, Z);
434 _TYPE_ beta = prodscal_RZ / dold;
435 dold = prodscal_RZ;
436
437 op_multiply(P, beta);
438 op_sub(P, Z);
439 }
440}
441
442template <typename _TYPE_, typename _TYPE_ARRAY_>
443inline double ajouter_alpha_v_multiple_(IJK_Field_template<_TYPE_,_TYPE_ARRAY_>& x, ArrOfDouble& coeff, IJK_Vector<IJK_Field_template, _TYPE_, _TYPE_ARRAY_>& y, int n, int nfirst)
444{
445 if (n > 4)
446 {
447 Cerr << "Erreur ajouter_alpha_v_multiple" << finl;
449 }
450 const int ni = x.ni();
451 const int nj = x.nj();
452 const int nk = x.nk();
453 _TYPE_ * x_ptr = x.data().addr();
454 _TYPE_ * y_ptr[4];
455 _TYPE_ c[4];
456 int nn;
457 double somme = 0.;
458 for (nn = 0; nn < n; nn++)
459 {
460 y_ptr[nn] = y[nfirst + nn].data().addr();
461 c[nn] = (_TYPE_)coeff[nfirst + nn];
462 }
463 for (int k = 0; k < nk; k++)
464 {
465 for (int j = 0; j < nj; j++)
466 {
467 int index = x.linear_index(0,j,k);
468 for (int i = 0; i < ni; i++)
469 {
470 _TYPE_ val = x_ptr[index+i];
471 for (nn = 0; nn < n; nn++)
472 val += c[nn] * y_ptr[nn][index+i];
473 x_ptr[index+i] = val;
474 somme += val * val;
475 }
476 }
477 }
478 return somme;
479}
480
481// Calcule ceci
482// x += coeff[0] * y[0] + ... + coeff[n-1] * y[n-1]
483// Renvoie la somme des x^2 du resultat sur le processeur local
484template <typename _TYPE_, typename _TYPE_ARRAY_>
485double ajouter_alpha_v_multiple(IJK_Field_template<_TYPE_,_TYPE_ARRAY_>& x, ArrOfDouble& coeff, IJK_Vector<IJK_Field_template, _TYPE_, _TYPE_ARRAY_>& y, int n)
486{
487 int i = 0;
488 double somme = 0.;
489 while (i < n)
490 {
491 int nn = n - i;
492 if (nn > 4)
493 nn = 4;
494 if (nn == 1)
495 somme += ajouter_alpha_v_multiple_(x, coeff, y, 1, i);
496 else if (nn == 2)
497 somme += ajouter_alpha_v_multiple_(x, coeff, y, 2, i);
498 else if (nn == 3)
499 somme += ajouter_alpha_v_multiple_(x, coeff, y, 3, i);
500 else if (nn == 4)
501 somme += ajouter_alpha_v_multiple_(x, coeff, y, 4, i);
502
503 i += nn;
504 }
505 return somme;
506}
507
508template <typename _TYPE_, typename _TYPE_ARRAY_>
509inline void calcul_produits_scalaires_(IJK_Vector<IJK_Field_template, _TYPE_, _TYPE_ARRAY_>& x, int n, int nfirst, int m, ArrOfDouble& resu)
510{
511 if (n > 4)
512 {
513 Cerr << "Erreur " << finl;
515 }
516 const int ni = x[0].ni();
517 const int nj = x[0].nj();
518 const int nk = x[0].nk();
519 _TYPE_ * x_ptr = x[m].data().addr();
520 _TYPE_ * y_ptr[4];
521 _TYPE_ c[4] = { 0., 0., 0., 0. };
522 int nn;
523 for (nn = 0; nn < n; nn++)
524 {
525 y_ptr[nn] = x[nfirst + nn].data().addr();
526 c[nn] = 0;
527 }
528 for (int k = 0; k < nk; k++)
529 {
530 for (int j = 0; j < nj; j++)
531 {
532 int index = x[0].linear_index(0,j,k);
533 for (int i = 0; i < ni; i++)
534 {
535 _TYPE_ val = x_ptr[index+i];
536 for (nn = 0; nn < n; nn++)
537 c[nn] += val * y_ptr[nn][index+i];
538 }
539 }
540 }
541 for (nn = 0; nn < n; nn++)
542 resu[nfirst + nn] += c[nn];
543}
544
545// Calcule ceci, pour i=0..n avec n = resu.size_array()-1
546// resu[i] = x[i] scalaire x[n]
547// Renvoie la somme des x^2 du resultat sur le processeur local
548template <typename _TYPE_, typename _TYPE_ARRAY_>
549void calcul_produits_scalaires(IJK_Vector<IJK_Field_template, _TYPE_, _TYPE_ARRAY_>& x, ArrOfDouble& resu)
550{
551 int i = 0;
552 resu = 0.;
553 const int n = resu.size_array() - 1;
554 while (i < n)
555 {
556 int nn = n - i;
557 if (nn > 4)
558 nn = 4;
559 if (nn == 1)
560 calcul_produits_scalaires_(x, 1, i, n, resu);
561 else if (nn == 2)
562 calcul_produits_scalaires_(x, 2, i, n, resu);
563 else if (nn == 3)
564 calcul_produits_scalaires_(x, 3, i, n, resu);
565 else if (nn == 4)
566 calcul_produits_scalaires_(x, 4, i, n, resu);
567 i += nn;
568 }
570}
571
572static inline void triangularise(const DoubleTab& hessenberg, const double norme_b, DoubleTab& resu, ArrOfDouble& r)
573{
574 const int n = hessenberg.dimension(1);
575 assert(hessenberg.dimension(0) == n+1);
576 assert(r.size_array() == n + 1);
577
578 r[0] = norme_b;
579
580 // Triangularisation
581 int i;
582 for(i = 0; i < n; i++)
583 {
584 double ccos, ssin;
585 {
586 const double h_ii = hessenberg(i, i);
587 const double h_i1i = hessenberg(i + 1, i);
588 const double tmp_val = 1. / sqrt(h_ii * h_ii + h_i1i * h_i1i);
589 ccos = h_ii * tmp_val;
590 ssin = - h_i1i * tmp_val;
591 }
592 for (int j = i; j < n; j++)
593 {
594 const double h_ij = hessenberg(i, j);
595 const double h_i1j = hessenberg(i + 1, j);
596 resu(i, j) = ccos * h_ij - ssin * h_i1j;
597 resu(i + 1, j) = ssin * h_ij + ccos * h_i1j;
598 }
599 const double ri = r[i];
600 r[i] = ccos * ri;
601 r[i + 1] = ssin * ri;
602 }
603}
604
605// si plus de 3 vecteurs de base, semble atteindre la limite de precision numerique...
606template <typename _TYPE_, typename _TYPE_ARRAY_>
608{
609 int n_krilov = n_krilov_;
610 DoubleTab hessenberg(n_krilov + 1, n_krilov);
611
612 // Espace de Krilov
614 // Vecteurs des M^(-1) * krilov_space[i] ou M^-1 est le preconditionneur:
616 {
618 for (int ii=0; ii < n_krilov+1; ii++)
619 krilov_space.add(titi);
620 for (int ii=0; ii < n_krilov; ii++)
621 m_krilov_space.add(titi);
622 }
623
624 krilov_space[0] = b;
625 for (int ii=0; ii < n_krilov; ii++)
626 {
627 alloc_field(krilov_space[ii+1], 0);
628 alloc_field(m_krilov_space[ii], 0, true /* with additional layers for jacobi sweeps */);
629 }
630
631 x.data() = 0.;
632
633 for (int iter = 0; ; iter++)
634 {
635
636 // Hypothese de depart: krilov_space[0] = -residu
637 const double norme_b = norme_ijk(krilov_space[0]);
638
639 if (impr_gmres_)
640 Cout << "gmres iteration " << iter << " norme(residu) " << norme_b << finl;
641 if (norme_b < seuil_ || norme_b == 0.)
642 {
643 if (impr_gmres_)
644 Cout << "gmres: norme(residu) < seuil=" << seuil_ << " => return" << finl;
645 return;
646 }
647 if (iter >= max_iter_gmres_)
648 {
649 Cerr << "Error in Multigrille_base::resoudre_avec_gmres: did not converge in " << max_iter_gmres_ << " restarts."
650 << "\n Residue= " << norme_b << finl;
652 }
653 krilov_space[0].data() *= (_TYPE_)(1. / norme_b);
654
655 hessenberg = 0.;
656
657 for (int i = 0; i < n_krilov; i++)
658 {
659 // Produit matrice vecteur : v1 = A * M^(-1) * v0 (ou M^(-1) est une approx de A^(-1) par multigrille)
660 m_krilov_space[i].data() = 0.;
661 m_krilov_space[i].shift_k_origin(needed_kshift_for_jacobi(0) - m_krilov_space[i].k_shift());
662 krilov_space[i].echange_espace_virtuel(krilov_space[i].ghost());
663 // Stockage de M^-1 * v0 dans m_krilov_space[i]
664 // et on met le residu dans krilov_space[i+1]
665 multigrille(m_krilov_space[i], krilov_space[i], krilov_space[i+1]);
666
667 // remarque Titi23
668 // On obtient krilov_space[i+1] = A * m_krilov_space[i] - krilov_space[i]
669 // normalement, on devrait faire
670 // krilov_space[i+1] += krilov_space[i]
671 // L'orthogonalisation va retirer la composante krilov_space[i],
672 // mais va calculer "prod_scal_ijk(krilov_space[i+1], krilov_space[i]) - 1"
673
674 // Orthogonalisation:
675 // v0 = somme pour 0 <= j <= i des (krilov_space[j] * hessenberg(j, i)
676 ArrOfDouble produit_scal(i+2);
677 ArrOfDouble coeff(i+1);
678 calcul_produits_scalaires(krilov_space, produit_scal);
679 for (int j = 0; j <= i; j++)
680 {
681 double h = produit_scal[j];
682 coeff[j] = -h;
683 //norme2_prevue -= h*h;
684 if (j == i)
685 {
686 // voir Titi23 ci-dessus:
687 // on n'a pas rajoute krilov_space[i] toute a l'heure a krilov_space[i+1],
688 // le produit scalaire a stocker dans hessenberg vaut donc 1 de plus:
689 h += 1.;
690 }
691 hessenberg(j, i) = h;
692 }
693 double norme_v0 = ajouter_alpha_v_multiple(krilov_space[i+1], coeff, krilov_space, i+1);
694 norme_v0 = sqrt(mp_sum(norme_v0));
695 hessenberg(i + 1, i) = norme_v0;
696 krilov_space[i+1].data() *= (_TYPE_)(1. / norme_v0);
697 }
698
699 DoubleTab mat(n_krilov + 1, n_krilov);
700 ArrOfDouble r__(n_krilov + 1);
701 triangularise(hessenberg, norme_b, mat, r__);
702
703 //...Solution of linear system
704 for (int i = n_krilov - 1; i >= 0; i--)
705 {
706 r__[i] /= mat(i, i);
707 for (int j = i-1; j >= 0; j--)
708 r__[j] -= mat(j, i) * r__[i];
709 }
710 ajouter_alpha_v_multiple(x, r__, m_krilov_space, n_krilov);
711 if (impr_gmres_)
712 {
713 Cout << "facteurs r : ";
714 for (int i = 0; i < r__.size_array(); i++)
715 Cout << r__[i] << " ";
716 Cout << finl;
717 if (impr_gmres_ > 1)
718 {
719 Cout << "matrice de hessenberg " << hessenberg << finl;
720 }
721 }
722 // On stocke le residu dans krilov_space[0] pour l'iteration suivante:
723 jacobi_residu(x, &b, 0 /* grid_level */, 0 /* no jacobi */, &krilov_space[0]);
724 prepare_secmem(krilov_space[0]);
725 op_negate(krilov_space[0]);
726 }
727}
728
729
730template <typename _TYPE_, typename _TYPE_ARRAY_>
731void Multigrille_base::resoudre_systeme_template(const Matrice_Base& a, const DoubleVect& b, DoubleVect& x)
732{
736
737 convert_to_ijk(b, ijk_b);
738
740
741 convert_from_ijk(ijk_x, x);
742
744
745 if (check_residu_)
746 {
747 // Calcul du residu
748 DoubleVect residu(b);
749 a.multvect(x, residu);
750
751 const Matrice_Bloc& matrice_bloc=ref_cast(Matrice_Bloc,a);
752 const Matrice_Morse_Sym& la_matrice =ref_cast(Matrice_Morse_Sym,matrice_bloc.get_bloc(0,0).valeur());
753 // Terme diagonal multiplie par 2 dans Assembleur_P_VDF.cpp: assembler_QC()
755 residu[0] -= x[0] * la_matrice(0,0) * 0.5;
756 Cout << "Norme de Ax et residu: " << mp_norme_vect(residu);
757 residu -= b;
758 Cout << " " << mp_norme_vect(residu) << finl;
759 }
760
761}
762
763
764#endif
This class encapsulates all the information related to the eulerian mesh for TrioIJK.
Definition Domaine_IJK.h:47
void nommer(const Nom &nom) override
Donne un nom a l'Objet_U Methode virtuelle a surcharger.
void nommer(const Nom &) override
Donne un nom au champ.
int linear_index(int i, int j, int k) const
: This class is an IJK_Field_local with parallel informations.
void echange_espace_virtuel(int ghost)
Exchange data over "ghost" number of cells.
const Domaine_IJK & get_domaine() const
static const char * get_conventional_name()
const VDF_to_IJK & get_vdf_to_ijk(Domaine_IJK::Localisation) const
classe IJK_Vector
Definition IJK_Vector.h:30
static Objet_U & objet_global(const Nom &nom)
cherche l'objet demande dans l'Interprete_bloc courant (Interprete_bloc::interprete_courant()) et dan...
virtual int get_nb_items_tot() const
: 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
const Matrice_Base & matrice() const
const MD_Vector & md_vector() const
const int & renum(int i, int j, int k) const
Classe Matrice_Morse_Sym Represente une matrice M (creuse) symetrique stockee au format Morse.
virtual int needed_kshift_for_jacobi(int level) const =0
virtual void prepare_secmem(IJK_Field_float &x) const =0
void solve_ijk_in_storage_template()
std::enable_if_t< std::is_same< _TYPE_, float >::value, IJK_Field_template< _TYPE_, TRUSTArray< _TYPE_ > > & > get_storage_template(StorageId id, int level)
virtual void interpolate_sub_shiftk(const IJK_Field_float &coarse, IJK_Field_float &fine, int fine_level) const =0
virtual int nb_grid_levels() const =0
void resoudre_systeme_IJK_template(const IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &rhs, IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &x)
void convert_to_ijk(const DoubleVect &x, IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &ijk_x)
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)
virtual void coarsen(const IJK_Field_float &fine, IJK_Field_float &coarse, int fine_level) const =0
virtual void alloc_field(IJK_Field_float &x, int level, bool with_additional_k_layers=false) const =0
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 convert_from_ijk(const IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &ijk_x, DoubleVect &x)
void resoudre_systeme_template(const Matrice_Base &a, const DoubleVect &b, DoubleVect &x)
double multigrille_(IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &x, const IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &b, IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &residu, int grid_level, int iter_number)
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
void resoudre_systeme_IJK(const IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &rhs, IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &x)
void coarse_solver(IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &x, const IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &b)
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
static void mp_sum_for_each_item(TRUSTArray< _TYPE_ > &x, int n=-1)
Definition Process.cpp:193
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
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
_SIZE_ size_array() const
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
virtual void set_md_vector(const MD_Vector &)
void resize(_SIZE_, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTVect.tpp:91
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")
value_type & add()=delete
void convert_from_ijk(const IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &ijk_x, DoubleVect &x, bool add=false) const
void convert_to_ijk(const DoubleVect &x, IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &ijk_x) const