TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
SSOR.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 <Matrice_Morse_Sym.h>
17#include <Matrice_Bloc_Sym.h>
18#include <MD_Vector_tools.h>
19#include <MD_Vector_base.h>
20#include <TRUSTTab_parts.h>
21#include <Motcle.h>
22#include <Param.h>
23#include <SSOR.h>
24
25Implemente_instanciable_sans_constructeur(SSOR,"SSOR",Precond_base);
26// XD ssor precond_base ssor BRACE Symmetric successive over-relaxation algorithm.
27
29
30Sortie& SSOR::printOn(Sortie& s ) const
31{
32 s << " { omega "<<omega_ << " } ";
33 return s;
34}
35
37{
38 Param param(que_suis_je());
39 param.ajouter("omega", &omega_); // XD attr omega floattant omega OPT Over-relaxation facteur (between 1 and 2,
40 // XD_CONT default value 1.6).
41 param.lire_avec_accolades(is);
42
44 {
45 Cerr << "SSOR::readOn, omega is not within [0, 2]: SSOR not activated (you should use precond nul instead) " << finl;
46 }
47 return is;
48}
49
50void SSOR::prepare_(const Matrice_Base& la_matrice, const DoubleVect& secmem)
51{
52 if (get_status() >= REINIT_ALL)
53 {
54 md_secmem_ = secmem.get_md_vector();
55 line_size_ = secmem.line_size();
56 // Pour le prochain preconditionnement, verifier la matrice
57 avec_assert_ = 1;
58
59 if (nproc() == 1 || !(md_secmem_)) algo_items_communs_ = 0;
60 else
61 {
62 // Nombre d'items sequentiels sur ce proc
63 const int sz_tot = secmem.size_totale();
64 items_a_traiter_.reset();
65 items_a_traiter_.resize(sz_tot / line_size_, line_size_, RESIZE_OPTIONS::NOCOPY_NOINIT);
66 items_a_traiter_.set_md_vector(md_secmem_);
67 int n = md_secmem_->get_sequential_items_flags(items_a_traiter_, line_size_);
68 int sz = md_secmem_->get_nb_items_reels();
69
70 if (sz < 0) // size() est invalide, les items reels ne sont pas groupes a debut !
72 else
73 {
74 assert(sz >= n);
75 if (mp_sum(sz) > mp_sum(n)) algo_items_communs_ = 1; // Il y a des items partages parmi les items reels
76 else
77 {
79 items_a_traiter_.reset();
80 }
81 }
82 }
83 }
84
85 if (get_status() >= REINIT_COEFF) { /* Do nothing */ }
86 Precond_base::prepare_(la_matrice, secmem);
87}
88
89/*! @brief Calcule la solution du systeme lineaire: A * solution = b avec la methode de relaxation SSOR.
90 *
91 */
92int SSOR::preconditionner_(const Matrice_Base& la_matrice, const DoubleVect& b, DoubleVect& solution)
93{
94 // pour compatibilite historique:
96 {
97 operator_egal(solution, b);
98 return 1;
99 }
100
101 operator_egal(solution, b);
102
103 if (sub_type(Matrice_Morse_Sym, la_matrice))
104 {
105 const Matrice_Morse_Sym& matrice = ref_cast(Matrice_Morse_Sym, la_matrice);
106 ssor(matrice, solution);
107 }
108 else if (sub_type(Matrice_Bloc_Sym, la_matrice))
109 {
110 // Matrice correspondant a un vecteur multi-localisation (MD_Vector_composite)
111 const Matrice_Bloc_Sym& matrice = ref_cast(Matrice_Bloc_Sym, la_matrice);
112 ssor(matrice, solution);
113 }
114 else if (sub_type(Matrice_Bloc, la_matrice))
115 {
116 // On suppose une matrice reelle-reelle et une matrice reelle-virtuelle
117 const Matrice_Bloc& mat = ref_cast(Matrice_Bloc, la_matrice);
118 const Matrice_Morse_Sym& matrice = ref_cast(Matrice_Morse_Sym, mat.get_bloc(0, 0).valeur());
119 ssor(matrice, solution);
120 }
121 else
122 {
123 Cerr << "SSOR::preconditionner not coded for type " << la_matrice.que_suis_je() << finl;
124 exit();
125 }
127 return 1;
128}
129
130void traite_diagonale(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur)
131{
132 const int nb_lignes_a_traiter = vecteur.size_reelle_ok() ? vecteur.size_reelle() : vecteur.size_totale();
133 const auto& tab1 = mat.get_tab1();
134 const auto& coeff = mat.get_coeff();
135 const double psi = (2. - omega) / omega;
136 const double *coeff_fortran = coeff.addr() - 1; // indexable par index fortran
137 const auto *tab1_ptr = tab1.addr();
138 double *vect_ptr = vecteur.addr();
139 for (int i = nb_lignes_a_traiter; i; i--, tab1_ptr++, vect_ptr++)
140 {
141 const auto j = *tab1_ptr;
142 // Coefficient diagonale de la ligne i:
143 const double coeff_i_i = coeff_fortran[j];
144 (*vect_ptr) *= psi * coeff_i_i;
145 }
146}
147
148enum class descente_enum { NORMAL , NORMAL_ASSERT , DIAG , DIAG_ASSERT };
149
150template<descente_enum _TYPE_>
151void descente_generique(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur)
152{
153 static constexpr bool IS_NORMAL_ASSERT = (_TYPE_ == descente_enum::NORMAL_ASSERT), IS_DIAG_ASSERT = (_TYPE_ == descente_enum::DIAG_ASSERT), NOT_DIAG = (_TYPE_ != descente_enum::DIAG && _TYPE_ != descente_enum::DIAG_ASSERT);
154 const auto& tab1 = mat.get_tab1();
155 const auto& tab2 = mat.get_tab2();
156 const auto& coeff = mat.get_coeff();
157 const int nb_lignes_a_traiter = vecteur.size_reelle_ok() ? vecteur.size_reelle() : vecteur.size_totale();
158 // pointeur "fortran" vers le tableau solution (indexable avec index fortran) le pointeur est constant, pas le tableau pointe.
159 double * const sol_fortran = vecteur.addr() - 1;
160 const auto *tab1_ptr = tab1.addr();
161 assert(nb_lignes_a_traiter <= tab1.size_array() + 1);
162 assert(*tab1_ptr == 1); // sinon 2 lignes ci-dessous fausses.
163 const int *tab2_ptr = tab2.addr();
164 const double *coeff_ptr = coeff.addr();
165 auto last_tab1_de_i = *tab1_ptr;
166 tab1_ptr++;
167 for (int i = 1; i <= nb_lignes_a_traiter; i++, tab1_ptr++)
168 {
169 const auto tab1_de_i = *tab1_ptr; // = tab1[i]
170 const int nvois = (int)(tab1_de_i - last_tab1_de_i);
171
172 if (IS_NORMAL_ASSERT || IS_DIAG_ASSERT) assert(nvois >= 0 && (tab1_de_i - 1) <= tab2.size_array());
173
174 last_tab1_de_i = tab1_de_i;
175 // Ce test doit rester, sinon on pollue les autres lignes du vecteur sol avec des valeurs dependant des items communs et virtuels
176 {
177 double v_i;
178 if (NOT_DIAG)
179 {
180 // Le premier coeff doit etre le coef diagonal et doit etre strictement positif
181 if (IS_NORMAL_ASSERT) assert(nvois >= 1 && (*tab2_ptr) == i && (*coeff_ptr) > 0.);
182
183 const double omega_coeff_i_i = omega / (*coeff_ptr);
184 v_i = sol_fortran[i] *= omega_coeff_i_i;
185 tab2_ptr++;
186 coeff_ptr++;
187 }
188 else // PRECOND DIAG !!
189 {
190 // Pas de coefficient diagonal stocke (ni dans tab2 ni dans coeff), la diagonale vaut 1:
191 v_i = sol_fortran[i] *= omega;
192 }
193
194 for (int j = nvois-1; j; j--, tab2_ptr++, coeff_ptr++)
195 {
196 const int i2 = *tab2_ptr; // indice de colonne pour le prochain coefficient
197 const double coeff_i_i2 = *coeff_ptr;
198 // la matrice n'a que des coeffs diagonaux superieurs et on a deja traite la diagonale, donc i2 > i. Pas d'items virtuels autorises !
199 if (IS_NORMAL_ASSERT || IS_DIAG_ASSERT) assert(i2 > i && i2 <= nb_lignes_a_traiter);
200 // B.M.: ... en revanche, le test sur les items communs est superflu ici car la valeur sera annulee (voir **Annulation items communs**),
201 // gain de perfs si on ne fait pas le test
202 sol_fortran[i2] -= coeff_i_i2 * v_i;
203 }
204 }
205 }
206}
207
208void descente(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur)
209{
210 descente_generique<descente_enum::NORMAL>(omega,mat,vecteur);
211}
212
213void descente_assert(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur)
214{
215 descente_generique<descente_enum::NORMAL_ASSERT>(omega,mat,vecteur);
216}
217
218void descente_diag_ok_assert(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur)
219{
220 descente_generique<descente_enum::NORMAL_ASSERT>(omega,mat,vecteur); /* meme qu'avant :D */
221}
222
223void descente_precond_diag(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur)
224{
225 descente_generique<descente_enum::DIAG>(omega,mat,vecteur);
226}
227
228void descente_assert_precond_diag(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur)
229{
230 descente_generique<descente_enum::DIAG_ASSERT>(omega,mat,vecteur);
231}
232
233// Descente sur un bloc extradiagonal. Methode appelee par SSOR(const Matrice_bloc & ...)
234// vecteur: de taille "nombre de lignes de la matrice", vecteur2: "nombre de colonnes"
235void descente_bloc_extradiag_assert(const Matrice_Morse& mat, const DoubleVect& vecteur, DoubleVect& vecteur2)
236{
237 const auto& tab1 = mat.get_tab1();
238 const auto& tab2 = mat.get_tab2();
239 const auto& coeff = mat.get_coeff();
240 const int nb_lignes = vecteur.size_reelle_ok() ? vecteur.size_reelle() : vecteur.size_totale();
241 const double *vecteur_ptr = vecteur.addr();
242 double *vecteur2_fortran_ptr = vecteur2.addr() - 1;
243 const int *tab2_fortran_ptr = tab2.addr() - 1;
244 const double *coeff_fortran_ptr = coeff.addr() - 1;
245 assert(coeff.size_array() == tab2.size_array());
246 for (int i_ligne = 0; i_ligne < nb_lignes; i_ligne++, vecteur_ptr++)
247 {
248 {
249 const double v_i = *vecteur_ptr;
250 auto index = tab1[i_ligne];
251 const auto index_fin = tab1[i_ligne + 1];
252 // Il peut n'y avoir aucun coefficient sur la ligne => index_fin == index
253 assert(index > 0 && index_fin >= index && index_fin <= tab2.size_array() + 1);
254 const int *tab2_ptr = tab2_fortran_ptr + index;
255 const double *coeff_ptr = coeff_fortran_ptr + index;
256 for (; index < index_fin; index++, tab2_ptr++, coeff_ptr++)
257 {
258 const int i_colonne = *tab2_ptr;
259 assert(i_colonne >= 1 && i_colonne <= vecteur2.size_array());
260 const double c = *coeff_ptr;
261 // pas de test item commun sur les colonnes, voir **Annulation items communs**
262 vecteur2_fortran_ptr[i_colonne] -= c * v_i;
263 }
264 }
265 }
266}
267
268template<descente_enum _TYPE_>
269void descente_generique(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur, const ArrOfInt& items_a_traiter)
270{
271 static constexpr bool IS_NORMAL_ASSERT = (_TYPE_ == descente_enum::NORMAL_ASSERT), IS_DIAG_ASSERT = (_TYPE_ == descente_enum::DIAG_ASSERT), NOT_DIAG = (_TYPE_ != descente_enum::DIAG && _TYPE_ != descente_enum::DIAG_ASSERT);
272 const auto& tab1 = mat.get_tab1();
273 const auto& tab2 = mat.get_tab2();
274 const auto& coeff = mat.get_coeff();
275 const int nb_lignes_a_traiter = vecteur.size_reelle_ok() ? vecteur.size_reelle() : vecteur.size_totale();
276 // pointeur "fortran" vers le tableau solution (indexable avec index fortran) le pointeur est constant, pas le tableau pointe.
277 double * const sol_fortran = vecteur.addr() - 1;
278 const int *flags_ptr = items_a_traiter.addr();
279 assert(nb_lignes_a_traiter <= items_a_traiter.size_array());
280 const auto *tab1_ptr = tab1.addr();
281 assert(nb_lignes_a_traiter <= tab1.size_array() + 1);
282 assert(*tab1_ptr == 1); // sinon 2 lignes ci-dessous fausses.
283 const int *tab2_ptr = tab2.addr();
284 const double *coeff_ptr = coeff.addr();
285 auto last_tab1_de_i = *tab1_ptr;
286 tab1_ptr++;
287 for (int i = 1; i <= nb_lignes_a_traiter; i++, tab1_ptr++)
288 {
289 const auto tab1_de_i = *tab1_ptr; // = tab1[i]
290 const int nvois = (int)(tab1_de_i - last_tab1_de_i);
291
292 if (IS_NORMAL_ASSERT || IS_DIAG_ASSERT) assert(nvois >= 0 && (tab1_de_i - 1) <= tab2.size_array());
293
294 last_tab1_de_i = tab1_de_i;
295 // Ce test doit rester, sinon on pollue les autres lignes du vecteur sol avec des valeurs dependant des items communs et virtuels
296 if (IS_NORMAL_ASSERT || IS_DIAG_ASSERT) assert((flags_ptr - items_a_traiter.addr()) == (i-1));
297
298 const int item_a_traiter = *(flags_ptr++);
299 if (item_a_traiter)
300 {
301 double v_i;
302 if (NOT_DIAG)
303 {
304 // Le premier coeff doit etre le coef diagonal et doit etre strictement positif
305 if (IS_NORMAL_ASSERT) assert(nvois >= 1 && (*tab2_ptr) == i && (*coeff_ptr) > 0.);
306
307 const double omega_coeff_i_i = omega / (*coeff_ptr);
308 v_i = sol_fortran[i] *= omega_coeff_i_i;
309 tab2_ptr++;
310 coeff_ptr++;
311 }
312 else // PRECOND DIAG !!
313 {
314 // Pas de coefficient diagonal stocke (ni dans tab2 ni dans coeff), la diagonale vaut 1:
315 v_i = sol_fortran[i] *= omega;
316 }
317
318 for (int j = nvois-1; j; j--, tab2_ptr++, coeff_ptr++)
319 {
320 const int i2 = *tab2_ptr; // indice de colonne pour le prochain coefficient
321 const double coeff_i_i2 = *coeff_ptr;
322 // la matrice n'a que des coeffs diagonaux superieurs et on a deja traite la diagonale, donc i2 > i.
323 if (IS_NORMAL_ASSERT || IS_DIAG_ASSERT) assert(i2 > i && i2 <= vecteur.size_totale());
324
325 // B.M.: ... en revanche, le test sur les items communs est superflu ici car
326 // la valeur sera annulee (voir **Annulation items communs**), gain de perfs si on ne fait pas le test
327 sol_fortran[i2] -= coeff_i_i2 * v_i;
328 }
329 }
330 else
331 {
332 // **Annulation items communs**
333 // c'est la derniere fois qu'on ecrit dans sol_fortran[i] car la matrice est diagonale superieure. Pour eviter le test sur items_a_traiter_
334 // dans la remontee, on annule la solution pour les items communs et virtuels (sol_fortran[i] ne sera plus modifie ensuite dans la descente)
335 sol_fortran[i] = 0.;
336 coeff_ptr += nvois;
337 tab2_ptr += nvois;
338 }
339 }
340 // **Annulation items communs** : Pour la remontee il faut annuler les valeurs dans les cases virtuelles
341 {
342 const int fin = vecteur.size_totale();
343 for (int i = nb_lignes_a_traiter+1; i <= fin; i++)
344 sol_fortran[i] = 0.;
345 }
346}
347
348void descente(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur, const ArrOfInt& items_a_traiter)
349{
350 descente_generique<descente_enum::NORMAL>(omega,mat,vecteur,items_a_traiter);
351}
352
353void descente_assert(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur, const ArrOfInt& items_a_traiter)
354{
355 descente_generique<descente_enum::NORMAL_ASSERT>(omega,mat,vecteur,items_a_traiter);
356}
357
358void descente_diag_ok_assert(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur, const ArrOfInt& items_a_traiter)
359{
360 descente_generique<descente_enum::NORMAL_ASSERT>(omega,mat,vecteur,items_a_traiter); /* meme qu'avant :D */
361}
362
363void descente_precond_diag(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur, const ArrOfInt& items_a_traiter)
364{
365 descente_generique<descente_enum::DIAG>(omega,mat,vecteur,items_a_traiter);
366}
367
368void descente_assert_precond_diag(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur, const ArrOfInt& items_a_traiter)
369{
370 descente_generique<descente_enum::DIAG_ASSERT>(omega,mat,vecteur,items_a_traiter);
371}
372
373// Descente sur un bloc extradiagonal. Methode appelee par SSOR(const Matrice_bloc & ...)
374// vecteur: de taille "nombre de lignes de la matrice", vecteur2: "nombre de colonnes"
375void descente_bloc_extradiag_assert(const Matrice_Morse& mat, const DoubleVect& vecteur, DoubleVect& vecteur2, const ArrOfInt& items_a_traiter)
376{
377 const auto& tab1 = mat.get_tab1();
378 const auto& tab2 = mat.get_tab2();
379 const auto& coeff = mat.get_coeff();
380 const int nb_lignes = vecteur.size_reelle_ok() ? vecteur.size_reelle() : vecteur.size_totale();
381 const int *flags_ptr = items_a_traiter.addr();
382 const double *vecteur_ptr = vecteur.addr();
383 double *vecteur2_fortran_ptr = vecteur2.addr() - 1;
384 const int *tab2_fortran_ptr = tab2.addr() - 1;
385 const double *coeff_fortran_ptr = coeff.addr() - 1;
386 assert(coeff.size_array() == tab2.size_array());
387 for (int i_ligne = 0; i_ligne < nb_lignes; i_ligne++, vecteur_ptr++)
388 {
389 if (*(flags_ptr++))
390 {
391 const double v_i = *vecteur_ptr;
392 auto index = tab1[i_ligne];
393 const auto index_fin = tab1[i_ligne + 1];
394 // Il peut n'y avoir aucun coefficient sur la ligne => index_fin == index
395 assert(index > 0 && index_fin >= index && index_fin <= tab2.size_array() + 1);
396 const int *tab2_ptr = tab2_fortran_ptr + index;
397 const double *coeff_ptr = coeff_fortran_ptr + index;
398 for (; index < index_fin; index++, tab2_ptr++, coeff_ptr++)
399 {
400 const int i_colonne = *tab2_ptr;
401 assert(i_colonne >= 1 && i_colonne <= vecteur2.size_array());
402 const double c = *coeff_ptr;
403 // pas de test item commun sur les colonnes, voir **Annulation items communs**
404 vecteur2_fortran_ptr[i_colonne] -= c * v_i;
405 }
406 }
407 }
408}
409
410enum class remontee_enum { NORMAL , NORMAL_ASSERT , DIAG_OK_ASSERT , DIAG , DIAG_ASSERT };
411
412template<remontee_enum _TYPE_>
413void remontee_generique(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur)
414{
415 static constexpr bool IS_NORMAL_ASSERT = (_TYPE_ == remontee_enum::NORMAL_ASSERT), IS_DIAG_OK_ASSERT = (_TYPE_ == remontee_enum::DIAG_OK_ASSERT), IS_DIAG_ASSERT = (_TYPE_ == remontee_enum::DIAG_ASSERT),
416 NOT_DIAG = (_TYPE_ != remontee_enum::DIAG && _TYPE_ != remontee_enum::DIAG_ASSERT);
417 const auto& tab1 = mat.get_tab1();
418 const auto& tab2 = mat.get_tab2();
419 const auto& coeff = mat.get_coeff();
420
421 const int nb_lignes_a_traiter = vecteur.size_reelle_ok() ? vecteur.size_reelle() : vecteur.size_totale();
422 const double psi = IS_DIAG_OK_ASSERT ? -1e10 : (2. - omega) / omega;
423
424 // pointeur "fortran" vers le tableau solution (indexable avec index fortran)
425 const double *const sol_fortran = vecteur.addr() - 1;
426 const auto *tab1_ptr = tab1.addr() + nb_lignes_a_traiter;
427 auto last_tab1_de_i = *tab1_ptr;
428 tab1_ptr--;
429 // On ne va pas a la fin de tab2 car on n'est pas sur que nb_lignes_a_traiter = tab1.size_array() :
430 // -2 car last_tab1_de_i est l'indice du premier coefficient de la ligne suivante en fortran
431 // (dont -1 pour fortran->c et -1 pour passer au dernier coeff de la ligne precedente)
432 const int *tab2_ptr = tab2.addr() + last_tab1_de_i - 2;
433 const double *coeff_ptr = coeff.addr() + last_tab1_de_i - 2;
434 double *soli_ptr = vecteur.addr() + nb_lignes_a_traiter - 1;
435 for (int i = nb_lignes_a_traiter; i; i--, tab1_ptr--, soli_ptr--)
436 {
437 const auto tab1_de_i = *tab1_ptr; // = tab1[i]
438 const int nvois = (int)(last_tab1_de_i - tab1_de_i);
439
440 if (IS_NORMAL_ASSERT || IS_DIAG_OK_ASSERT || IS_DIAG_ASSERT) assert(nvois >= 0 && tab1_de_i > 0);
441
442 last_tab1_de_i = tab1_de_i;
443 // Ce test doit rester car il ne faut pas modifier sol[i] pour les items communs
444 // et virtuels (ils sont nuls et doivent le rester pour ne pas polluer les autres lignes):
445 if (1)
446 {
447 // Operation "diagonale":
448 double x = 0.;
449 for (int j = nvois - 1; j; j--, tab2_ptr--, coeff_ptr--)
450 {
451 const int i2 = *tab2_ptr;
452 const double coeff_i_i2 = *coeff_ptr;
453 // Operation nulle pour les items communs et virtuels
454 // (on a annule le second membre lors de la descente)
455 x += coeff_i_i2 * sol_fortran[i2];
456 }
457
458 if (NOT_DIAG)
459 {
460 // ici coeff_ptr est le coeff diagonal
461 if (IS_NORMAL_ASSERT || IS_DIAG_OK_ASSERT) assert((*tab2_ptr) == i);
462
463 const double coeff_i_i = *coeff_ptr;
464 const double omega_coeff_i_i = omega / coeff_i_i;
465 // Si IS_DIAG_OK_ASSERT : La diagonale a deja ete multipliee par psi * coeff_i_i
466 *soli_ptr = IS_DIAG_OK_ASSERT ? ((*soli_ptr) - x) * omega_coeff_i_i : (*soli_ptr) * psi * omega - x * omega_coeff_i_i;
467 coeff_ptr--;
468 tab2_ptr--;
469 }
470 else // PRECOND DIAG !!
471 {
472 // Preconditionnement diagonal, pas de coefficient diagonal stocke:
473 *soli_ptr = ((*soli_ptr) * psi - x) * omega;
474 }
475 }
476 else
477 {
478 assert((*soli_ptr) == 0.);
479 coeff_ptr -= nvois;
480 tab2_ptr -= nvois;
481 }
482 }
483}
484
485void remontee(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur)
486{
487 remontee_generique<remontee_enum::NORMAL>(omega,mat,vecteur);
488}
489
490void remontee_assert(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur)
491{
492 remontee_generique<remontee_enum::NORMAL_ASSERT>(omega,mat,vecteur);
493}
494
495void remontee_diag_ok_assert(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur)
496{
497 remontee_generique<remontee_enum::DIAG_OK_ASSERT>(omega,mat,vecteur);
498}
499
500void remontee_precond_diag(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur)
501{
502 remontee_generique<remontee_enum::DIAG>(omega,mat,vecteur);
503}
504
505void remontee_assert_precond_diag(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur)
506{
507 remontee_generique<remontee_enum::DIAG_ASSERT>(omega,mat,vecteur);
508}
509
510// Remontee sur un bloc extradiagonal. Methode appelee par SSOR(const Matrice_bloc & ...)
511// vecteur: de taille "nombre de lignes de la matrice", vecteur2: "nombre de colonnes"
512void remontee_bloc_extradiag_assert(const Matrice_Morse& mat, DoubleVect& vecteur, const DoubleVect& vecteur2)
513{
514 const auto& tab1 = mat.get_tab1();
515 const auto& tab2 = mat.get_tab2();
516 const auto& coeff = mat.get_coeff();
517 const int nb_lignes = vecteur.size_reelle_ok() ? vecteur.size_reelle() : vecteur.size_totale();
518 double *vecteur_ptr = vecteur.addr();
519 const double *vecteur2_fortran_ptr = vecteur2.addr() - 1;
520 const int *tab2_fortran_ptr = tab2.addr() - 1;
521 const double *coeff_fortran_ptr = coeff.addr() - 1;
522 assert(coeff.size_array() == tab2.size_array());
523 for (int i_ligne = 0; i_ligne < nb_lignes; i_ligne++, vecteur_ptr++)
524 {
525 {
526 double x = *vecteur_ptr;
527 auto index = tab1[i_ligne];
528 const auto index_fin = tab1[i_ligne + 1];
529 // Il peut n'y avoir aucun coefficient sur la ligne => index_fin == index
530 assert(index > 0 && index_fin >= index && index_fin <= tab2.size_array() + 1);
531 const int *tab2_ptr = tab2_fortran_ptr + index;
532 const double *coeff_ptr = coeff_fortran_ptr + index;
533 for (; index < index_fin; index++, tab2_ptr++, coeff_ptr++)
534 {
535 const int i_colonne = *tab2_ptr;
536 assert(i_colonne >= 1 && i_colonne <= vecteur2.size_array());
537 const double c = *coeff_ptr;
538 const double x2 = vecteur2_fortran_ptr[i_colonne];
539 // pas de test item commun sur les colonnes, voir **Annulation items communs**
540 x -= c * x2;
541 }
542 *vecteur_ptr = x;
543 }
544 }
545}
546
547template<remontee_enum _TYPE_>
548void remontee_generique(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur, const ArrOfInt& items_a_traiter)
549{
550 static constexpr bool IS_NORMAL_ASSERT = (_TYPE_ == remontee_enum::NORMAL_ASSERT), IS_DIAG_OK_ASSERT = (_TYPE_ == remontee_enum::DIAG_OK_ASSERT), IS_DIAG_ASSERT = (_TYPE_ == remontee_enum::DIAG_ASSERT),
551 NOT_DIAG = (_TYPE_ != remontee_enum::DIAG && _TYPE_ != remontee_enum::DIAG_ASSERT);
552 const auto& tab1 = mat.get_tab1();
553 const auto& tab2 = mat.get_tab2();
554 const auto& coeff = mat.get_coeff();
555
556 const int nb_lignes_a_traiter = vecteur.size_reelle_ok() ? vecteur.size_reelle() : vecteur.size_totale();
557 const int *flags_ptr = items_a_traiter.addr() + nb_lignes_a_traiter - 1;
558 assert(nb_lignes_a_traiter <= items_a_traiter.size_array());
559 const double psi = IS_DIAG_OK_ASSERT ? -1e10 : (2. - omega) / omega;
560
561 // pointeur "fortran" vers le tableau solution (indexable avec index fortran)
562 const double * const sol_fortran = vecteur.addr() - 1;
563 const auto *tab1_ptr = tab1.addr() + nb_lignes_a_traiter;
564 auto last_tab1_de_i = *tab1_ptr;
565 tab1_ptr--;
566 // On ne va pas a la fin de tab2 car on n'est pas sur que nb_lignes_a_traiter = tab1.size_array() :
567 // -2 car last_tab1_de_i est l'indice du premier coefficient de la ligne suivante en fortran
568 // (dont -1 pour fortran->c et -1 pour passer au dernier coeff de la ligne precedente)
569 const int *tab2_ptr = tab2.addr() + last_tab1_de_i - 2;
570 const double *coeff_ptr = coeff.addr() + last_tab1_de_i - 2;
571 double * soli_ptr = vecteur.addr() + nb_lignes_a_traiter - 1;
572 for (int i = nb_lignes_a_traiter; i; i--, tab1_ptr--, soli_ptr--)
573 {
574 const auto tab1_de_i = *tab1_ptr; // = tab1[i]
575 const int nvois = (int)(last_tab1_de_i - tab1_de_i);
576 if (IS_NORMAL_ASSERT || IS_DIAG_OK_ASSERT || IS_DIAG_ASSERT) assert(nvois >= 0 && tab1_de_i > 0);
577
578 last_tab1_de_i = tab1_de_i;
579 // Ce test doit rester car il ne faut pas modifier sol[i] pour les items communs
580 // et virtuels (ils sont nuls et doivent le rester pour ne pas polluer les autres lignes):
581 if (*(flags_ptr--))
582 {
583 // Operation "diagonale":
584 double x = 0.;
585 for (int j = nvois-1; j; j--, tab2_ptr--, coeff_ptr--)
586 {
587 const int i2 = *tab2_ptr;
588 const double coeff_i_i2 = *coeff_ptr;
589 // Operation nulle pour les items communs et virtuels
590 // (on a annule le second membre lors de la descente)
591 x += coeff_i_i2 * sol_fortran[i2];
592 }
593 if (NOT_DIAG)
594 {
595 // ici coeff_ptr est le coeff diagonal
596 if (IS_NORMAL_ASSERT || IS_DIAG_OK_ASSERT) assert((*tab2_ptr) == i);
597
598 const double coeff_i_i = *coeff_ptr;
599 const double omega_coeff_i_i = omega / coeff_i_i;
600 // Si IS_DIAG_OK_ASSERT : La diagonale a deja ete multipliee par psi * coeff_i_i
601 *soli_ptr = IS_DIAG_OK_ASSERT ? ((*soli_ptr) - x) * omega_coeff_i_i : (*soli_ptr) * psi * omega - x * omega_coeff_i_i;
602 coeff_ptr--;
603 tab2_ptr--;
604 }
605 else // PRECOND DIAG !!
606 {
607 // Preconditionnement diagonal, pas de coefficient diagonal stocke:
608 *soli_ptr = ((*soli_ptr) * psi - x) * omega;
609 }
610 }
611 else
612 {
613 assert((*soli_ptr) == 0.);
614 coeff_ptr -= nvois;
615 tab2_ptr -= nvois;
616 }
617 }
618}
619
620void remontee(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur, const ArrOfInt& items_a_traiter)
621{
622 remontee_generique<remontee_enum::NORMAL>(omega,mat,vecteur,items_a_traiter);
623}
624
625void remontee_assert(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur, const ArrOfInt& items_a_traiter)
626{
627 remontee_generique<remontee_enum::NORMAL_ASSERT>(omega,mat,vecteur,items_a_traiter);
628}
629
630void remontee_diag_ok_assert(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur, const ArrOfInt& items_a_traiter)
631{
632 remontee_generique<remontee_enum::DIAG_OK_ASSERT>(omega,mat,vecteur,items_a_traiter);
633}
634
635void remontee_precond_diag(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur, const ArrOfInt& items_a_traiter)
636{
637 remontee_generique<remontee_enum::DIAG>(omega,mat,vecteur,items_a_traiter);
638}
639
640void remontee_assert_precond_diag(const double omega, const Matrice_Morse& mat, DoubleVect& vecteur, const ArrOfInt& items_a_traiter)
641{
642 remontee_generique<remontee_enum::DIAG_ASSERT>(omega,mat,vecteur,items_a_traiter);
643}
644
645// Remontee sur un bloc extradiagonal. Methode appelee par SSOR(const Matrice_bloc & ...)
646// vecteur: de taille "nombre de lignes de la matrice", vecteur2: "nombre de colonnes"
647void remontee_bloc_extradiag_assert(const Matrice_Morse& mat, DoubleVect& vecteur, const DoubleVect& vecteur2, const ArrOfInt& items_a_traiter)
648{
649 const auto& tab1 = mat.get_tab1();
650 const auto& tab2 = mat.get_tab2();
651 const auto& coeff = mat.get_coeff();
652 const int nb_lignes = vecteur.size_reelle_ok() ? vecteur.size_reelle() : vecteur.size_totale();
653 const int *flags_ptr = items_a_traiter.addr();
654 double *vecteur_ptr = vecteur.addr();
655 const double *vecteur2_fortran_ptr = vecteur2.addr() - 1;
656 const int *tab2_fortran_ptr = tab2.addr() - 1;
657 const double *coeff_fortran_ptr = coeff.addr() - 1;
658 assert(coeff.size_array() == tab2.size_array());
659 for (int i_ligne = 0; i_ligne < nb_lignes; i_ligne++, vecteur_ptr++)
660 {
661 if (*(flags_ptr++))
662 {
663 double x = *vecteur_ptr;
664 auto index = tab1[i_ligne];
665 const auto index_fin = tab1[i_ligne + 1];
666 // Il peut n'y avoir aucun coefficient sur la ligne => index_fin == index
667 assert(index > 0 && index_fin >= index && index_fin <= tab2.size_array() + 1);
668 const int *tab2_ptr = tab2_fortran_ptr + index;
669 const double *coeff_ptr = coeff_fortran_ptr + index;
670 for (; index < index_fin; index++, tab2_ptr++, coeff_ptr++)
671 {
672 const int i_colonne = *tab2_ptr;
673 assert(i_colonne >= 1 && i_colonne <= vecteur2.size_array());
674 const double c = *coeff_ptr;
675 const double x2 = vecteur2_fortran_ptr[i_colonne];
676 // pas de test item commun sur les colonnes, voir **Annulation items communs**
677 x -= c * x2;
678 }
679 *vecteur_ptr = x;
680 }
681 }
682}
683
684// On calcule solution = inverse(C)*b avec:
685// inverse(C) = inverse((1/w D - E)) * (2-w/w D) * inverse((1/wD -E)t)
686// D :partie diagonale de la matrice, E :partie triangulaire inferieure de la matrice
687void SSOR::ssor(const Matrice_Morse_Sym& matrice, DoubleVect& solution)
688{
689 const auto& tab2 = matrice.get_tab2();
690 if (tab2.size_array() > 0 && tab2[0] == 1)
691 {
692 // La diagonale est presente dans la matrice
693 if (avec_assert_)
694 {
696 {
697 descente_assert(omega_, matrice, solution, items_a_traiter_);
698 remontee_assert(omega_, matrice, solution, items_a_traiter_);
699 }
700 else
701 {
702 descente_assert(omega_, matrice, solution);
703 remontee_assert(omega_, matrice, solution);
704 }
705 }
706 else
707 {
709 {
710 descente(omega_, matrice, solution, items_a_traiter_);
711 remontee(omega_, matrice, solution, items_a_traiter_);
712 }
713 else
714 {
715 descente(omega_, matrice, solution);
716 remontee(omega_, matrice, solution);
717 }
718 }
719 }
720 else
721 {
722 // Pas de diagonale stockee, on suppose qu'on a que des 1 sur la diagonale (preconditionnement diagonal)
723 if (avec_assert_)
724 {
726 {
727 descente_assert_precond_diag(omega_, matrice, solution, items_a_traiter_);
728 remontee_assert_precond_diag(omega_, matrice, solution, items_a_traiter_);
729 }
730 else
731 {
732 descente_assert_precond_diag(omega_, matrice, solution);
733 remontee_assert_precond_diag(omega_, matrice, solution);
734 }
735 }
736 else
737 {
739 {
740 descente_precond_diag(omega_, matrice, solution, items_a_traiter_);
741 remontee_precond_diag(omega_, matrice, solution, items_a_traiter_);
742 }
743 else
744 {
745 descente_precond_diag(omega_, matrice, solution);
746 remontee_precond_diag(omega_, matrice, solution);
747 }
748 }
749 }
750 avec_assert_ = 0; // Ne pas reverifier au prochain preconditionnement...
751}
752
753void SSOR::ssor(const Matrice_Bloc_Sym& matrice, DoubleVect& solution)
754{
755 DoubleTab_parts s_parts(solution);
756 ConstIntTab_parts items_parts;
758
759 const int nb_parts = s_parts.size();
760 assert(s_parts.size() == nb_parts);
761 assert(matrice.nb_bloc_lignes() == nb_parts);
762
763 // Descente
764 int i_part;
765 for (i_part = 0; i_part < nb_parts; i_part++)
766 {
767 const Matrice_Bloc& matrice0 = ref_cast(Matrice_Bloc, matrice.get_bloc(i_part, i_part).valeur());
768 const Matrice_Morse_Sym& MB00 = ref_cast(Matrice_Morse_Sym, matrice0.get_bloc(0, 0).valeur());
769 DoubleVect& partie = s_parts[i_part];
770
771 if (algo_items_communs_) descente_diag_ok_assert(omega_, MB00, partie, items_parts[i_part]);
772 else descente_diag_ok_assert(omega_, MB00, partie);
773
774 // blocs extra-diagonaux
775 for (int j_part = i_part + 1; j_part < nb_parts; j_part++)
776 {
777 const Matrice_Bloc& Aij = ref_cast(Matrice_Bloc, matrice.get_bloc(i_part, j_part).valeur());
778 const Matrice_Morse& MB00bis = ref_cast(Matrice_Morse, Aij.get_bloc(0, 0).valeur());
779 DoubleVect& partie_j = s_parts[j_part];
780 // Attention: le test sur les items communs concerne les lignes de la matrice, pas les colonnes (on passe items_parts[i_part], pas j_part)
781 // (note BM: je crois que la version precedente etait buggee mais ca ne s'est pas vu parce que la matrice elem-elem arrive en premier et qu'il n'y a pas d'items communs sur les elements)
782 if (algo_items_communs_) descente_bloc_extradiag_assert(MB00bis, partie, partie_j, items_parts[i_part]);
783 else descente_bloc_extradiag_assert(MB00bis, partie, partie_j);
784 }
785 }
786 // Traitement de la diagonale
787 for (i_part = 0; i_part < nb_parts; i_part++)
788 {
789 const Matrice_Bloc& matrice0 = ref_cast(Matrice_Bloc, matrice.get_bloc(i_part, i_part).valeur());
790 const Matrice_Morse_Sym& MB00 = ref_cast(Matrice_Morse_Sym, matrice0.get_bloc(0, 0).valeur());
791 DoubleVect& partie = s_parts[i_part];
792 traite_diagonale(omega_, MB00, partie);
793 }
794
795 // Remontee
796 for (i_part = nb_parts - 1; i_part >= 0; i_part--)
797 {
798 const Matrice_Bloc& matrice0 = ref_cast(Matrice_Bloc, matrice.get_bloc(i_part, i_part).valeur());
799 const Matrice_Morse_Sym& MB00bis = ref_cast(Matrice_Morse_Sym, matrice0.get_bloc(0, 0).valeur());
800 DoubleVect& partie = s_parts[i_part];
801 if (algo_items_communs_) remontee_diag_ok_assert(omega_, MB00bis, partie, items_parts[i_part]);
802 else remontee_diag_ok_assert(omega_, MB00bis, partie);
803
804 // Blocs extra-diagonaux (parcours horizontal au lieu de vertical)
805 for (int j_part = 0; j_part < i_part; j_part++)
806 {
807 const Matrice_Bloc& Aij = ref_cast(Matrice_Bloc, matrice.get_bloc(j_part, i_part).valeur());
808 const Matrice_Morse& MB00 = ref_cast(Matrice_Morse, Aij.get_bloc(0, 0).valeur());
809 DoubleVect& partie_j = s_parts[j_part];
810 // Attention: le test sur les items communs concerne les lignes de la matrice, pas les colonnes (on passe items_parts[i_part], pas j_part)
811 if (algo_items_communs_) remontee_bloc_extradiag_assert(MB00, partie_j, partie, items_parts[j_part]);
812 else remontee_bloc_extradiag_assert(MB00, partie_j, partie);
813 }
814 }
815}
void initialize(const TRUSTVect< _TYPE_ > &)
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
Classe Matrice_Base Classe de base de la hierarchie des matrices.
const Matrice & get_bloc(int i, int j) const override
int nb_bloc_lignes() const
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
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
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
int echange_ev_solution_
virtual void prepare_(const Matrice_Base &, const DoubleVect &)
this method must be overloaded if some preparation is necessary.
Init_Status get_status()
static int nproc()
renvoie le nombre de processeurs dans le groupe courant Voir Comm_Group::nproc() et PE_Groups::curren...
Definition Process.cpp:104
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
Definition SSOR.h:26
SSOR()
Definition SSOR.cpp:28
void prepare_(const Matrice_Base &, const DoubleVect &secmem) override
this method must be overloaded if some preparation is necessary.
Definition SSOR.cpp:50
int algo_items_communs_
Definition SSOR.h:54
int line_size_
Definition SSOR.h:57
void ssor(const Matrice_Morse_Sym &, DoubleVect &)
Definition SSOR.cpp:687
int algo_fortran_
Definition SSOR.h:49
int avec_assert_
Definition SSOR.h:49
MD_Vector md_secmem_
Definition SSOR.h:56
double omega_
Definition SSOR.h:48
IntTab items_a_traiter_
Definition SSOR.h:52
int preconditionner_(const Matrice_Base &, const DoubleVect &secmem, DoubleVect &solution) override
Calcule la solution du systeme lineaire: A * solution = b avec la methode de relaxation SSOR.
Definition SSOR.cpp:92
Classe de base des flux de sortie.
Definition Sortie.h:52
_SIZE_ size_array() const
_TYPE_ * addr()
int size() const
_SIZE_ size_totale() const
Definition TRUSTVect.tpp:61
int line_size() const
Definition TRUSTVect.tpp:67
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")