TrioCFD 1.9.9_beta
TrioCFD documentation
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 // For the next preconditioning step, check the matrix
57 avec_assert_ = 1;
58
59 if (nproc() == 1 || !(md_secmem_)) algo_items_communs_ = 0;
60 else
61 {
62 // Number of sequential items on this 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() is invalid: real items are not grouped at the start!
72 else
73 {
74 assert(sz >= n);
75 if (mp_sum(sz) > mp_sum(n)) algo_items_communs_ = 1; // There are shared items among the real items
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 // for historical compatibility:
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 // Matrix corresponding to a multi-location vector (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 // Assume a real-real matrix and a real-virtual matrix
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 by Fortran index
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 // Diagonal coefficient of row 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 // "Fortran" pointer to the solution array (indexable with Fortran index); the pointer is constant, not the pointed data.
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); // otherwise the 2 lines below are wrong.
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 // This check must remain: without it, other rows of the solution vector would be polluted by values depending on shared and virtual items
176 {
177 double v_i;
178 if (NOT_DIAG)
179 {
180 // The first coefficient must be the diagonal coefficient and must be strictly positive
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 // No stored diagonal coefficient (neither in tab2 nor in coeff), the diagonal equals 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; // column index for the next coefficient
197 const double coeff_i_i2 = *coeff_ptr;
198 // the matrix only has upper diagonal coefficients and the diagonal has already been handled, so i2 > i. No virtual items allowed!
199 if (IS_NORMAL_ASSERT || IS_DIAG_ASSERT) assert(i2 > i && i2 <= nb_lignes_a_traiter);
200 // B.M.: ... however, the check on shared items is redundant here because the value will be zeroed out (see **Annulation items communs**);
201 // skipping the check gives a performance gain
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// Forward sweep on an off-diagonal block. Method called by SSOR(const Matrice_bloc & ...)
234// vecteur: size = "number of rows of the matrix", vecteur2: size = "number of columns"
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 // There may be no coefficient on the row => 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 // no shared-item check on columns, see **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 // "Fortran" pointer to the solution array (indexable with Fortran index); the pointer is constant, not the pointed data.
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); // otherwise the 2 lines below are wrong.
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 // This check must remain: without it, other rows of the solution vector would be polluted by values depending on shared and virtual items
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 // The first coefficient must be the diagonal coefficient and must be strictly positive
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 // No stored diagonal coefficient (neither in tab2 nor in coeff), the diagonal equals 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; // column index for the next coefficient
321 const double coeff_i_i2 = *coeff_ptr;
322 // the matrix only has upper diagonal coefficients and the diagonal has already been handled, so i2 > i.
323 if (IS_NORMAL_ASSERT || IS_DIAG_ASSERT) assert(i2 > i && i2 <= vecteur.size_totale());
324
325 // B.M.: ... however, the check on shared items is redundant here because
326 // the value will be zeroed out (see **Annulation items communs**); skipping the check gives a performance gain
327 sol_fortran[i2] -= coeff_i_i2 * v_i;
328 }
329 }
330 else
331 {
332 // **Annulation items communs**
333 // this is the last write to sol_fortran[i] because the matrix is upper triangular. To avoid the items_a_traiter_ check
334 // in the back-substitution, the solution is zeroed for shared and virtual items (sol_fortran[i] will not be modified again in the forward sweep)
335 sol_fortran[i] = 0.;
336 coeff_ptr += nvois;
337 tab2_ptr += nvois;
338 }
339 }
340 // **Annulation items communs** : For the back-substitution, values in virtual slots must be zeroed
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// Forward sweep on an off-diagonal block. Method called by SSOR(const Matrice_bloc & ...)
374// vecteur: size = "number of rows of the matrix", vecteur2: size = "number of columns"
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 // There may be no coefficient on the row => 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 // no shared-item check on columns, see **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 // "fortran" pointer to the solution array (indexable with Fortran index)
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 // We do not go to the end of tab2 because nb_lignes_a_traiter = tab1.size_array() is not guaranteed:
430 // -2 because last_tab1_de_i is the Fortran index of the first coefficient of the next row
431 // (-1 for Fortran->C conversion and -1 to move to the last coefficient of the previous row)
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 // This check must remain: sol[i] must not be modified for shared
444 // and virtual items (they are zero and must stay zero to avoid polluting other rows):
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 // Zero operation for shared and virtual items
454 // (their RHS contribution was zeroed during the forward sweep)
455 x += coeff_i_i2 * sol_fortran[i2];
456 }
457
458 if (NOT_DIAG)
459 {
460 // here coeff_ptr is the diagonal coefficient
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 // If IS_DIAG_OK_ASSERT: the diagonal has already been multiplied by 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 // Diagonal preconditioning, no diagonal coefficient stored:
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// Back-substitution on an off-diagonal block. Method called by SSOR(const Matrice_bloc & ...)
511// vecteur: size = "number of rows of the matrix", vecteur2: size = "number of columns"
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 // There may be no coefficient on the row => 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 // no shared-item check on columns, see **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 // "fortran" pointer to the solution array (indexable with Fortran index)
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 // We do not go to the end of tab2 because nb_lignes_a_traiter = tab1.size_array() is not guaranteed:
567 // -2 because last_tab1_de_i is the Fortran index of the first coefficient of the next row
568 // (-1 for Fortran->C conversion and -1 to move to the last coefficient of the previous row)
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 // This check must remain: sol[i] must not be modified for shared
580 // and virtual items (they are zero and must stay zero to avoid polluting other rows):
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 // Zero operation for shared and virtual items
590 // (their RHS contribution was zeroed during the forward sweep)
591 x += coeff_i_i2 * sol_fortran[i2];
592 }
593 if (NOT_DIAG)
594 {
595 // here coeff_ptr is the diagonal coefficient
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 // If IS_DIAG_OK_ASSERT: the diagonal has already been multiplied by 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 // Diagonal preconditioning, no diagonal coefficient stored:
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// Back-substitution on an off-diagonal block. Method called by SSOR(const Matrice_bloc & ...)
646// vecteur: size = "number of rows of the matrix", vecteur2: size = "number of columns"
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 // There may be no coefficient on the row => 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 // no shared-item check on columns, see **Annulation items communs**
677 x -= c * x2;
678 }
679 *vecteur_ptr = x;
680 }
681 }
682}
683
684// We compute solution = inverse(C)*b with:
685// inverse(C) = inverse((1/w D - E)) * (2-w/w D) * inverse((1/wD -E)t)
686// D : diagonal part of the matrix, E : lower triangular part of the matrix
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 // The diagonal is present in the matrix
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 // No stored diagonal: assuming all diagonal entries are 1 (diagonal preconditioning)
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; // Do not re-check at the next preconditioning step...
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 // Forward sweep
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 // off-diagonal blocks
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 // Warning: the shared-item check concerns matrix rows, not columns (we pass items_parts[i_part], not j_part)
781 // (note BM: I believe the previous version was buggy but it went unnoticed because the elem-elem matrix comes first and there are no shared items on 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 // Diagonal treatment
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 // Back-substitution
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 // Off-diagonal blocks (horizontal traversal instead of 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 // Warning: the shared-item check concerns matrix rows, not columns (we pass items_parts[i_part], not 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
Matrice_Base class - Base class of the matrix hierarchy.
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
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
const Nom & que_suis_je() const
Returns the string identifying the class.
Definition Objet_U.cpp:104
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
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()
Returns the number of processors in the current group. See Comm_Group::nproc() and PE_Groups::current...
Definition Process.cpp:102
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
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
Base class for output streams.
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")