TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Matrice_Morse.h
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 Matrice_Morse_included
17#define Matrice_Morse_included
18
19#include <TRUSTTabs_forward.h>
20#include <Matrice_Base.h>
21#include <TRUSTLists.h>
22#include <TRUSTTab.h>
23#include <algorithm>
24#include <kokkos++.h>
25#include <TRUSTArray_kokkos.tpp>
26
27/*! @brief Matrice_Morse class - Represents a (sparse) matrix M, not necessarily square,
28 *
29 * stored in Morse format.
30 * -----------------------------------------------------------------------
31 * Uses 3 arrays tab1(n+1), tab2(nnz) and coeff_(nnz):
32 * Let Vi = { j different from i / M(i,j) is non-zero }
33 * tab1[i] = position in tab2 of the i-th row
34 * for tab1[i] <= j < tab1[i+1], tab2[j] describes Vi
35 * and coeff_[j] = M(i,tab2[j])
36 * tab1 and tab2 are Fortran-style ranks:
37 * 1 <= tab2[i] <= n
38 * tab1[n+1] = nnz+1
39 * Note: in this comment [] is used in the Fortran sense:
40 * tab1[1] refers to the first value of tab1
41 *
42 * This is also the format described on the Wikipedia page:
43 * https://fr.wikipedia.org/wiki/Matrice_creuse
44 * by adding +1 to all elements of the index arrays (IA and JA on the page)
45 * -----------------------------------------------------------------------
46 *
47 * @sa Matrice_Base Matrice_Morse_Sym
48 */
50{
51
52 Declare_instanciable_sans_constructeur(Matrice_Morse);
53
54public :
55
56 //constructeurs :
57
58 // default: scalar 0:
60 template<typename _SIZE_> Matrice_Morse(int n, _SIZE_ nnz) ;
61
62 // A matrix with n rows and m columns and nnz non-zero coefficients:
63 template<typename _SIZE_> Matrice_Morse(int n, int m, _SIZE_ nnz) ;
64
65 // copy:
67 Matrice_Morse(int , int , const IntLists& ,const DoubleLists& ,const DoubleVect& );
68
69 Sortie& imprimer(Sortie& s) const override;
70 Sortie& imprimer_formatte(Sortie& s) const override;
71 Sortie& imprimer_formatte(Sortie& s, int symetrie) const;
72 Sortie& imprimer_image(Sortie& s) const;
73 Sortie& imprimer_image(Sortie& s, int symetrie) const;
74 void WriteFileMTX(const Nom&) const;
75 int largeur_de_bande() const; // Returns the bandwidth
76 void remplir(const IntLists& ,const DoubleLists& ,const DoubleVect& );
77 void remplir(const IntLists& ,const DoubleLists&);
78 void remplir(const int, const int, const int, const int, const Matrice_Morse& ) ;
79 //dimensionner
80 template<typename _SIZE_> void dimensionner(int n, _SIZE_ nnz);
81 template<typename _SIZE_> void dimensionner(int n, int m, _SIZE_ nnz);
82
83 // space for potential new non-zero coefficients
84 // (modif MT)
85 void dimensionner(const IntTab&);
86
87 // ordre returns n if n==m
88 int ordre() const override;
89
90 int nb_lignes() const override { return tab1_.size_array()-1; } // nb_lignes returns n
91 int nb_colonnes() const override { return m_; } // nb_colonnes returns m
92 auto nb_coeff() const { return coeff_.size(); } // nb_coeff returns nnz
93
94 void set_nb_columns( const int );
95 void set_symmetric( const int );
96 int get_symmetric( ) const { return symetrique_; }
97
99 {
100 is_stencil_up_to_date_ = false ;
101 return tab1_ ;
102 }
104 {
105 is_stencil_up_to_date_ = false ;
106 return tab2_ ;
107 }
108 auto& get_set_coeff() { return coeff_ ; }
109
110 const auto& get_tab1() const { return tab1_ ; }
111 const auto& get_tab2() const { return tab2_ ; }
112 const auto& get_coeff() const { return coeff_ ; }
113
114 int nb_vois(int i) const
115 {
116 return (int)(get_tab1()(i+1)-get_tab1()(i)); // nb_vois(i): number of non-zero elements in row i
117 }
118
119 //method to clean the matrix.
120 void clean() override;
121
122 // operators:
123 // 0<=i,j<=n-1
124 inline double& operator()(int i, int j);
125 inline double operator()(int i, int j) const;
126 // Do not remove these two coef(i,j) methods which, although they do the same thing as
127 // the two above, are used very often by OVAP:
128 // Access to coefficients do not modify the stencil so we can leave these two access functions
129 inline double coef(int i, int j) const { return operator()(i,j); }
130 inline double& coef(int i,int j) { return operator()(i,j); }
131
133 friend Matrice_Morse operator +(const Matrice_Morse&, const Matrice_Morse& );
135 Matrice_Morse& operator *=(double );
136 void scale( const double x ) override;
137
138 void get_stencil( Stencil& stencil ) const override;
139
140 void get_stencil_and_coefficients(Stencil& stencil, StencilCoeffs& coefficients) const override;
141 void get_stencil_and_coeff_ptrs(Stencil& stencil, std::vector<const double *>& coeff_ptr) const override;
142
143 Matrice_Morse& operator /=(double );
144 Matrice_Morse& operator *=(const DoubleVect& );
145 friend Matrice_Morse operator *(double, const Matrice_Morse& );
147 virtual int inverse(const DoubleVect&, DoubleVect&, double ) const ;
148 virtual int inverse(const DoubleVect&, DoubleVect&, double, int ) const ;
150
151 void compacte(int elim_coeff_nul=0);
152
153 // y += Ax
154 DoubleVect& ajouter_multvect_(const DoubleVect& ,DoubleVect& ) const override;
155 ArrOfDouble& ajouter_multvect_(const ArrOfDouble& ,ArrOfDouble&, ArrOfInt& ) const;
156
157 // Y += AX where X and Y are 2-dimensional DoubleTabs
158 DoubleTab& ajouter_multTab_(const DoubleTab& ,DoubleTab& ) const override;
159
160 // y += transposee(A) x
161 DoubleVect& ajouter_multvectT_(const DoubleVect& ,DoubleVect& ) const override;
162 ArrOfDouble& ajouter_multvectT_(const ArrOfDouble& ,ArrOfDouble&, ArrOfInt& ) const;
163
164 // A= creat_transposee(B)
165 virtual Matrice_Morse& transpose(const Matrice_Morse& a);
166
167 // A=x*A (x vecteur diag)
168 virtual Matrice_Morse& diagmulmat(const DoubleVect& x);
169
170 //retrieve the upper part of the matrix and store it in this one
171 virtual Matrice_Morse& partie_sup(const Matrice_Morse& a);
172
173 // initialize to the identity matrix
174 void unite();
175
176 // extraction d'un sous-bloc
177 void construire_sous_bloc(int nl0, int nc0, int nl1, int nc1, Matrice_Morse& result) const;
178
179 void formeC() ;
180 void formeF() ;
181
183 bool check_morse_matrix_structure() const;
187 void sort_stencil();
188 bool& constant_stencil() const { return constant_stencil_; };
189 bool is_sorted_stencil() const;
190 bool is_diagonal();
191
192 mutable int sorted_; //1 if the stencil is sorted: obtained by calling sort_stencil()
193 void set_tab1_int32() const
194 {
195#ifdef TRUST_USE_GPU
196 if (tab1_.size_array()>std::numeric_limits<int>::max()) Process::exit("Can't convert this huge matrix to int32 indices !");
197 int size = tab1_.size_array();
198 if (tab1_int32_.size_array()!=size) tab1_int32_.resize(size);
199 for (int i=0; i<size; i++) tab1_int32_(i) = (int)tab1_(i);
200#endif
201 }
202 const IntVect& get_tab1_int32() const
203 {
204#ifdef TRUST_USE_GPU
205 return tab1_int32_;
206#else
207 return tab1_;
208#endif
209 }
210 void set_tab1(const IntVect& tab1_int32)
211 {
212#ifdef TRUST_USE_GPU
213 int size = tab1_int32.size_array();
214 for (int i = 0; i < size; i++) tab1_(i) = (trustIdType)tab1_int32(i);
215#endif
216 }
217protected :
218 // We need trustIdType indices on GPU (large memory available)
219#ifdef TRUST_USE_GPU
220 ArrOfTID tab1_;
221 BigArrOfInt tab2_;
222 BigDoubleVect coeff_;
223 mutable IntVect tab1_int32_; // Useful for conversion during Fortran calls (soon deprecated)
224#else
225 IntVect tab1_;
226 IntVect tab2_;
227 DoubleVect coeff_;
228#endif
229
230 mutable int morse_matrix_structure_has_changed_=-1; // Flag if matrix structure changes
231 int m_; // Number of columns
232 int symetrique_; // For inlining operator()(i,j) to optimize
233
234 template<typename _TAB_T_, typename _VALUE_T_>
235 inline void get_stencil_coeff_templ( Stencil& stencil, _TAB_T_& coeffs_span) const;
236
237private :
238 double zero_;
239 mutable bool constant_stencil_=false; // Flag set by equation that the stencil matrix will NOT change
240};
241
242int Matrice_Morse_test();
243
244inline double Matrice_Morse::operator()(int i, int j) const
245{
246 assert( (symetrique_==0 && que_suis_je()=="Matrice_Morse")
247 || (symetrique_==1 && que_suis_je()=="Matrice_Morse_Sym")
248 || (symetrique_==2 && que_suis_je()=="Matrice_Morse_Diag") );
249 if ((symetrique_==1) && ((j-i)<0)) std::swap(i,j);
250 auto k1=tab1_[i]-1;
251 auto k2=tab1_[i+1]-1;
252 if (sorted_)
253 {
254#ifdef TRUST_USE_GPU
255 auto k = std::lower_bound(tab2_.addr() + k1, tab2_.addr() + k2, j + 1) - tab2_.addr();
256#else
257 auto k = (int)(std::lower_bound(tab2_.addr() + k1, tab2_.addr() + k2, j + 1) - tab2_.addr());
258#endif
259 if (k < k2 && tab2_[k] == j + 1)
260 return coeff_[k];
261 }
262 else
263 for (auto k=k1; k<k2; k++)
264 if (tab2_[k]-1 == j) return(coeff_[k]);
265 // If coefficient not found it is zero:
266 return(0);
267}
268
269inline double& Matrice_Morse::operator()(int i, int j)
270{
271 assert( (symetrique_==0 && que_suis_je()=="Matrice_Morse")
272 || (symetrique_==1 && que_suis_je()=="Matrice_Morse_Sym")
273 || (symetrique_==2 && que_suis_je()=="Matrice_Morse_Diag") );
274 //if (symetrique_==1 && j<i) std::swap(i,j); // Do not use, possible error during compile: "signed overflow does not occur when assuming that (X + c) < X is always false"
275 if ((symetrique_==1) && ((j-i)<0)) std::swap(i,j);
276 auto k1=tab1_[i]-1;
277 auto k2=tab1_[i+1]-1;
278 if (sorted_)
279 {
280#ifdef TRUST_USE_GPU
281 auto k = std::lower_bound(tab2_.addr() + k1, tab2_.addr() + k2, j + 1) - tab2_.addr();
282#else
283 auto k = (int)(std::lower_bound(tab2_.addr() + k1, tab2_.addr() + k2, j + 1) - tab2_.addr());
284#endif
285 if (k < k2 && tab2_[k] == j + 1)
286 return coeff_[k];
287 }
288 else
289 for (auto k=k1; k<k2; k++)
290 if (tab2_[k]-1 == j) return(coeff_[k]);
291 if (symetrique_==2) return zero_; // For Matrice_Morse_Diag, we do not check if the slot is defined and return 0
292#ifndef NDEBUG
293 // Only in debug mode to allow inlining in optimized builds
294 Cerr << "i or j are not suitable " << finl;
295 Cerr << "i=" << i << finl;
296 Cerr << "j=" << j << finl;
297 Cerr << "n_lignes=" << nb_lignes() << finl;
298 Cerr << "n_colonnes=" << nb_colonnes() << finl;
299#endif
300 // This message happens when you try to fill a coefficient in a matrix whereas is was not scheduled
301 // If it is a symmetric matrix, it -may- be a parallelism default. Check it by running a PETSc solver
302 // in debug mode: there is a test to check the parallelism of the symmetric matrix...
303 Cerr << "Error Matrice_Morse::operator("<< i << "," << j << ") not defined!" << finl;
304 exit();
305 return coeff_[0]; // Never reached
306}
307
308// Kokkos: First (and quick) implementation of a Matrix view. Future: Kokkos kernels ?
309// ToDo: rename tab1_, comment + factorize algorithm in each method, +implement sorted
310#ifdef KOKKOS
311struct Matrice_Morse_View
312{
313private:
314#ifdef TRUST_USE_GPU
315 CTIDArrView tab1_;
316#else
317 CIntArrView tab1_;
318#endif
319 CIntArrView tab2_;
320 mutable DoubleArrView coeff_;
321 int symetrique_ = 0;
322 int sorted_ = 0;
323public:
324 void set(Matrice_Morse& matrice)
325 {
326 tab1_ = matrice.get_tab1().view_ro();
327 tab2_ = matrice.get_tab2().view_ro();
328 coeff_ = matrice.get_set_coeff().view_rw();
329 symetrique_ = matrice.get_symmetric();
330 sorted_ = matrice.sorted_;
331 }
332 /*
333 KOKKOS_INLINE_FUNCTION int tab1(int i) const { return tab1_(i); }
334 KOKKOS_INLINE_FUNCTION int tab2(int i) const { return tab2_(i); }
335 KOKKOS_INLINE_FUNCTION double& coeff(int i) { return coeff_(i); }
336 */
337
338 KOKKOS_INLINE_FUNCTION
339 double& diag(int i) const
340 {
341 if (symetrique_!=2) Process::Kokkos_exit("You are not using a Matrice_Morse_Diag !");
342 return coeff_(tab1_(i)-1);
343 }
344
345 KOKKOS_INLINE_FUNCTION
346 const double& operator()(int i, int j) const
347 {
348 if (symetrique_==2) Process::Kokkos_exit("Error, use Matrice_Morse_View::diag(int i)");
349 if ((symetrique_==1) && ((j-i)<0))
350 {
351 // std::swap(i,j) refused by HIP: reference to __host__ function 'swap<int>' in __host__ __device__ function
352 // Kokkos::kokkos_swap(i,j); refused by old Kokkos 3.7 (C++14)
353 int k = j;
354 j = i;
355 i = k;
356 }
357 auto k1=tab1_(i)-1;
358 auto k2=tab1_(i+1)-1;
359 /* ToDo Kokkos for faster access:
360 if (sorted_)
361 {
362 XXX
363 }
364 else */
365 for (auto k=k1; k<k2; k++)
366 if (tab2_(k)-1 == j)
367 return coeff_(k);
368 printf("Error Matrice_Morse_View(%d, %d) not defined!\n", (int)i, (int)j);
369 Process::Kokkos_exit("Error");
370 return coeff_(0);
371 }
372
373 KOKKOS_INLINE_FUNCTION
374 void store(int i, int j, double coeff, bool atomic=false) const
375 {
376 if ((symetrique_==1) && ((j-i)<0))
377 {
378 // std::swap(i,j) refused by HIP: reference to __host__ function 'swap<int>' in __host__ __device__ function
379 // Kokkos::kokkos_swap(i,j); refused by old Kokkos 3.7 (C++14)
380 int k = j;
381 j = i;
382 i = k;
383 }
384 auto k1=tab1_(i)-1;
385 auto k2=tab1_(i+1)-1;
386 /* ToDo Kokkos for faster access:
387 if (sorted_)
388 {
389 XXX
390 }
391 else */
392 for (auto k=k1; k<k2; k++)
393 if (tab2_(k)-1 == j)
394 {
395 if (atomic) Kokkos::atomic_store(&coeff_(k), coeff);
396 else coeff_(k) = coeff;
397 return;
398 }
399 printf("Error Matrice_Morse_View::store(%d, %d, value) not defined!\n", (int)i, (int)j);
400 Process::Kokkos_exit("Error");
401 }
402
403 KOKKOS_INLINE_FUNCTION
404 void atomic_store(int i, int j, double coeff) const { store(i,j,coeff,true); }
405
406 KOKKOS_INLINE_FUNCTION
407 void atomic_add(int i, int j, double coeff) const { add(i,j,coeff,true); }
408
409 KOKKOS_INLINE_FUNCTION
410 void add(int i, int j, double coeff, bool atomic=false) const
411 {
412 if (symetrique_==2 && i!=j)
413 return; // For Matrice_Morse_Diag: we do not check whether the entry is defined and we return 0
414 else if ((symetrique_==1) && ((j-i)<0))
415 {
416 // std::swap(i,j) refused by HIP: reference to __host__ function 'swap<int>' in __host__ __device__ function
417 // Kokkos::kokkos_swap(i,j); refused by old Kokkos 3.7 (C++14)
418 int k = j;
419 j = i;
420 i = k;
421 }
422 auto k1=tab1_(i)-1;
423 auto k2=tab1_(i+1)-1;
424 /* ToDo Kokkos for faster access:
425 if (sorted_)
426 {
427 auto k = std::lower_bound(tab2_.addr() + k1, tab2_.addr() + k2, j + 1) - tab2_.addr();
428 if (k < k2 && tab2_[k] == j + 1)
429 return coeff_[k];
430 }
431 else */
432 for (auto k=k1; k<k2; k++)
433 if (tab2_(k)-1 == j)
434 {
435 if (atomic) Kokkos::atomic_add(&coeff_(k), coeff);
436 else coeff_(k) += coeff;
437 return;
438 }
439 printf("Error Matrice_Morse_View::add(%d, %d, value) not defined!\n", (int)i, (int)j);
440 Process::Kokkos_exit("Error");
441 }
442};
443#endif
444#endif
445
Matrice_Base class - Base class of the matrix hierarchy.
bool is_stencil_up_to_date_
Matrice_Morse class - Represents a (sparse) matrix M, not necessarily square,.
void clean() override
Remplit la matrice avec des zeros.
friend Matrice_Morse operator*(double, const Matrice_Morse &)
Friend function (outside the class) of the Matrice_Morse class. Scaling of the matrix by a scalar: mu...
friend Matrice_Morse operator+(const Matrice_Morse &, const Matrice_Morse &)
Friend function (outside the class) of the Matrice_Morse class. Addition of 2 Morse-format matrices.
int largeur_de_bande() const
Computes the bandwidth of a Morse matrix.
int morse_matrix_structure_has_changed_
Matrice_Morse & affecte_prod(const Matrice_Morse &A, const Matrice_Morse &B)
Assigns the product of 2 Morse matrices A and B to this object.
void get_stencil_and_coeff_ptrs(Stencil &stencil, std::vector< const double * > &coeff_ptr) const override
void get_stencil(Stencil &stencil) const override
bool check_morse_matrix_structure() const
Sortie & imprimer_image(Sortie &s) const
auto nb_coeff() const
Matrice_Morse & operator*=(double)
Operator multiplying all elements of a matrix by a scalar.
void WriteFileMTX(const Nom &) const
bool check_sorted_morse_matrix_structure() const
Matrice_Morse & operator=(const Matrice_Morse &)
Assignment operator from one Matrice_Morse to another.
void assert_check_morse_matrix_structure() const
void scale(const double x) override
virtual Matrice_Morse & diagmulmat(const DoubleVect &x)
int nb_vois(int i) const
auto & get_set_tab2()
Matrice_Morse & operator/=(double)
Operator dividing all elements of a matrix by a scalar.
void get_stencil_and_coefficients(Stencil &stencil, StencilCoeffs &coefficients) const override
DoubleVect coeff_
const auto & get_tab2() const
int ordre() const override
Returns the order of the matrix: - the number of rows if the matrix is square.
bool is_sorted_stencil() const
void set_tab1(const IntVect &tab1_int32)
Sortie & imprimer_formatte(Sortie &s) const override
virtual int inverse(const DoubleVect &, DoubleVect &, double) const
Computes the solution of the linear system: A * solution = secmem.
virtual Matrice_Morse & transpose(const Matrice_Morse &a)
*this = transpose of a.
const IntVect & get_tab1_int32() const
Sortie & imprimer(Sortie &s) const override
bool & constant_stencil() const
void dimensionner(int n, _SIZE_ nnz)
Size the matrix with n lines and n columns and nnz zero-values coefficients.
const auto & get_tab1() const
void set_nb_columns(const int)
DoubleVect & ajouter_multvect_(const DoubleVect &, DoubleVect &) const override
Operation de multiplication-accumulation (saxpy) matrice vecteur.
DoubleVect & ajouter_multvectT_(const DoubleVect &, DoubleVect &) const override
Matrix-vector multiply-accumulate operation (saxpy), by the transposed matrix.
void get_stencil_coeff_templ(Stencil &stencil, _TAB_T_ &coeffs_span) const
void assert_check_sorted_morse_matrix_structure() const
auto & get_set_coeff()
Matrice_Morse & operator+=(const Matrice_Morse &)
DOES NOTHING.
int get_symmetric() const
double coef(int i, int j) const
double & operator()(int i, int j)
double & coef(int i, int j)
int nb_colonnes() const override
Return local number of columns (=size on the current proc).
bool has_same_morse_matrix_structure(const Matrice_Morse &) const
auto & get_set_tab1()
Matrice_Morse operator-() const
Unary negation operator, returns the opposite of the matrix: - A. Calls operator*(double,...
const auto & get_coeff() const
void set_symmetric(const int)
void remplir(const IntLists &, const DoubleLists &, const DoubleVect &)
virtual Matrice_Morse & partie_sup(const Matrice_Morse &a)
int nb_lignes() const override
Return local number of lines (=size on the current proc).
void compacte(int elim_coeff_nul=0)
Method to check/clean the Matrice_Morse matrix: -Suppress coefficient defined several times.
void construire_sous_bloc(int nl0, int nc0, int nl1, int nc1, Matrice_Morse &result) const
void unite()
Initialize to the identity matrix (modif MT).
void set_tab1_int32() const
DoubleTab & ajouter_multTab_(const DoubleTab &, DoubleTab &) const override
Matrix-matrix multiply-accumulate operation (saxpy) (matrix X represented by an array).
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
friend class Sortie
Definition Objet_U.h:70
const Nom & que_suis_je() const
Returns the string identifying the class.
Definition Objet_U.cpp:104
static KOKKOS_INLINE_FUNCTION void Kokkos_exit(const char *)
Exit routine for TRUST within a Kokkos region.
Definition Process.h:172
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
_SIZE_ size_array() const