TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Matrice_Morse.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.h>
17#include <Sparskit.h>
18#include <unordered_map>
19#include <Matrice_Morse_Sym.h>
20#include <Check_espace_virtuel.h>
21#include <SFichier.h>
22#include <Noms.h>
23#include <ArrOfBit.h>
24#include <Array_tools.h>
25#include <TRUSTTrav.h>
26#include <TRUSTTrav.h>
27
28
29Implemente_instanciable_sans_constructeur(Matrice_Morse,"Matrice_Morse",Matrice_Base);
30
31/*! @brief Writes the three arrays of the Morse storage structure to an output stream.
32 *
33 * @param (Sortie& s) an output stream
34 * @return (Sortie& s) the modified output stream
35 */
37{
38 s << tab1_;
39 s << tab2_;
40 s << coeff_;
41 s << m_ << finl;
42 return s;
43}
44
45/*! @brief NOT IMPLEMENTED
46 *
47 * @param (Entree& s) an input stream
48 * @return (Entree& s) the input stream
49 * @throws NOT IMPLEMENTED
50 */
52{
53 s >> tab1_;
54 s >> tab2_;
55 s >> coeff_;
56 s >> m_;
58 return s;
59}
60
62{
63 int n=nb_lignes();
64 for(int i=0; i<n; i++)
65 {
66 s <<i << ": " <<finl;
67 s << "--------------------------------" << finl;
68 for (auto k=tab1_(i)-1; k<tab1_(i+1)-1; k++)
69 {
70 s << "("<<(tab2_(k)-1) << "),(" <<coeff_(k)<< ") "
71 << " k= " << k << finl;
72 }
73 s <<finl;
74 }
75 return s;
76}
77
82
84{
85 int numerotation_fortran=(tab1_[0]==1);
86 for (int proc=0; proc<Process::nproc(); proc++)
87 {
88 if (proc==Process::me())
89 {
90 s << "Matrix morse on the processor " << proc << " : " << finl;
91 int n=nb_lignes();
92 Noms tab_imp;
93 tab_imp.dimensionner(nb_colonnes());
94 for(int i=0; i<n; i++)
95 {
96 for (int k=0; k<nb_colonnes(); k++)
97 tab_imp[k]=" . ";
98 if (i<10)
99 s <<i << " :" ;
100 else
101 s <<i << ":" ;
102
103 if (symetrie)
104 {
105 for (int j=0; j<i; j++)
106 {
107 for (auto k=tab1_(j)-numerotation_fortran; k<tab1_(j+1)-numerotation_fortran; k++)
108 if (tab2_(k)-numerotation_fortran==i)
109 tab_imp[j] = coeff_(k);
110 }
111 int ligne=tab2_(tab1_(i)-numerotation_fortran)-numerotation_fortran;
112 if (i!=ligne)
113 {
114 Cerr << "Problem detected on this Matrice_Morse_Sym." << finl;
115 Cerr << "The diagonal of the line " << ligne << " must be stored even if it is null." << finl;
116 exit();
117 }
118 }
119 for (auto k=tab1_(i)-numerotation_fortran; k<tab1_(i+1)-numerotation_fortran; k++)
120 if (tab2_(k)+!numerotation_fortran==0)
121 Cerr<<"Line " <<i<< " no coefficient "<<k<<finl;
122 else
123 {
124 if (coeff_(k)>=0)
125 tab_imp[tab2_(k)-numerotation_fortran]=" ";
126 else
127 tab_imp[tab2_(k)-numerotation_fortran]="";
128 tab_imp[tab2_(k)-numerotation_fortran] += (Nom)coeff_(k);
129 }
130 for(int k=0; k<nb_colonnes(); k++)
131 s<<tab_imp[k];
132 s<<finl;
133 }
134 }
136 }
137 return s;
138}
139
141{
142 return imprimer_image(s,0);
143}
144
146{
147 int numerotation_fortran=(tab1_[0]==1);
148 for (int proc=0; proc<Process::nproc(); proc++)
149 {
150 if (proc==Process::me())
151 {
152 s << "Matrix morse on the processor " << proc << " : " << finl;
153 int n=nb_lignes();
154 Noms tab_imp;
155 tab_imp.dimensionner(nb_colonnes());
156 for(int i=0; i<n; i++)
157 {
158 for (int k=0; k<nb_colonnes(); k++)
159 tab_imp[k]="\u2588\u2588";
160 if (i<10)
161 s <<i << " :" ;
162 else
163 s <<i << ":" ;
164
165 if (symetrie)
166 {
167 for (int j=0; j<i; j++)
168 {
169 for (auto k=tab1_(j)-numerotation_fortran; k<tab1_(j+1)-numerotation_fortran; k++)
170 if (tab2_(k)-numerotation_fortran==i)
171 tab_imp[j] = (std::abs(coeff_(k)) < 1e-20) ? " " : "\u2592\u2592";
172 }
173 int ligne=tab2_(tab1_(i)-numerotation_fortran)-numerotation_fortran;
174 if (i!=ligne)
175 {
176 Cerr << "Problem detected on this Matrice_Morse_Sym." << finl;
177 Cerr << "The diagonal of the line " << ligne << " must be stored even if it is null." << finl;
178 exit();
179 }
180 }
181 for (auto k=tab1_(i)-numerotation_fortran; k<tab1_(i+1)-numerotation_fortran; k++)
182 if (tab2_(k)+!numerotation_fortran==0)
183 Cerr<<"Line " <<i<< " no coefficient "<<k<<finl;
184 else
185 tab_imp[tab2_(k)-numerotation_fortran] = (std::abs(coeff_(k)) < 1e-20) ? " " : "\u2592\u2592";
186
187 for(int k=0; k<nb_colonnes(); k++)
188 s<<tab_imp[k];
189 s<<finl;
190 }
191 }
193 }
194 return s;
195}
196
197void Matrice_Morse::WriteFileMTX(const Nom& name) const
198{
200 {
201 Cerr << "Warning, matrix market format is not available yet in parallel." << finl;
202 return;
203 }
204 Nom filename(Objet_U::nom_du_cas());
205 filename += "_";
206 filename += name;
207 filename += ".mtx";
208 SFichier mtx(filename);
209 mtx.precision(14);
210 mtx.setf(ios::scientific);
211 int rows = nb_lignes();
212 Cerr << "Matrix (" << rows << " lines) written into file: " << filename << " ... " << finl;
213 mtx << "%%MatrixMarket matrix coordinate real " << (sub_type(Matrice_Morse_Sym, *this) ? "symmetric" : "general") << finl;
214 Cerr << "Matrix (" << rows << " lines) written into file: " << filename << finl;
215 mtx << "%%matrix" << finl;
216 mtx << rows << " " << rows << " " << get_tab1()[rows] << finl;
217 for (int row=0; row<rows; row++)
218 for (auto j=get_tab1()[row]; j<get_tab1()[row+1]; j++)
219 mtx << row+1 << " " << get_tab2()[j-1] << " " << get_coeff()[j-1] << finl;
220}
221
222/*! @brief Copy constructor of a Matrice_Morse.
223 *
224 * Copies each member of the given parameter.
225 *
226 * @param (Matrice_Morse& acopier) the Morse matrix to copy
227 */
229 tab1_(acopier.tab1_),
230 tab2_(acopier.tab2_),
231 coeff_(acopier.coeff_),
232 m_(acopier.m_),
233 symetrique_(0),
234 zero_(0)
235{
238}
239/*! @brief Constructor of a square Morse matrix of order n that can store at most nnz non-zero elements.
240 *
241 * Also the default constructor as both parameters have a default value.
242 *
243 * @param (int n) the order of the square matrix to construct
244 * @param (int nnz) the number of non-zero elements the matrix can store.
245 */
246template<typename _SIZE_>
249{
250 dimensionner(n,nnz), sorted_ = 0;
251 is_stencil_up_to_date_ = false ;
252}
253
255{
256 dimensionner(0,0);
258 symetrique_ = 0;
259 sorted_ = 0;
260 zero_ = 0;
261 is_stencil_up_to_date_ = false ;
262}
263
264
265/*! @brief Constructor of a Morse matrix with n rows and m columns that can store at most nnz non-zero elements.
266 *
267 * @param (int n) the number of rows of the matrix
268 * @param (int m) the number of columns of the matrix
269 * @param (int nnz) the number of non-zero elements the matrix can store.
270 */
271template<typename _SIZE_>
272Matrice_Morse::Matrice_Morse(int n, int m, _SIZE_ nnz):
274{
275 dimensionner(n,m,nnz);
276 is_stencil_up_to_date_ = false, sorted_ = 0 ;
277}
278
279
280Matrice_Morse::Matrice_Morse(int n, int nnz, const IntLists& voisins,
281 const DoubleLists& valeurs,
282 const DoubleVect& terme_diag)
284{
285 dimensionner(n,n,nnz);
286 remplir(voisins, valeurs, terme_diag);
287 is_stencil_up_to_date_ = false, sorted_ = 0;
288}
289
290void Matrice_Morse::set_nb_columns( const int nb_col )
291{
292 m_ = nb_col;
293}
294
295void Matrice_Morse::set_symmetric( const int symmetric )
296{
297 symetrique_ = symmetric ;
298}
299
300/*! @brief Size the matrix with n lines and n columns and nnz zero-values coefficients
301 *
302 */
303template<typename _SIZE_>
304void Matrice_Morse::dimensionner(int n, _SIZE_ nnz)
305{
306 dimensionner(n,n,nnz);
307 return ;
308}
309
310
311/*! @brief Resizes the sparse matrix, optionally adding new non-zero coefficients
312 *
313 *
314 * Parameter: const IntTab &Ind
315 * Meaning: array of size nc * 2
316 * where nc is the number of pairs (i,j)
317 * for the indices of the new coefficients
318 *
319 *
320 */
321void Matrice_Morse::dimensionner(const IntTab& Ind)
322{
323 if (Ind.size()==0) return; // Do nothing if the structure is empty
324 int n_ancien = nb_lignes(), m_ancien = nb_colonnes();
325
326 assert(Ind.nb_dim() == 2);
327 assert(Ind.dimension(1) == 2);
328
329 // Compute the new number of rows
330 // = max (old, row indices of new coefficients)
331 //
332 // and the new number of columns
333 // = max (old, column indices of new coefficients)
334
335 int nInd = Ind.dimension(0);
336 int n = 0;
337 int m = 0;
338 for (int i=0; i<nInd; i++)
339 {
340 if (n < Ind(i,0)) n = Ind(i,0);
341 if (m < Ind(i,1)) m = Ind(i,1);
342 }
343 n++;
344 m++;
345 if (n < n_ancien) n = n_ancien;
346 if (m < m_ancien) m = m_ancien;
347
348 // Copies of the old index arrays
349
350 auto tab1_temp(tab1_);
351
352 // Initialize to the number of coefficients already present at each row
353
354 tab1_.resize(n+1);
355 m_ = m;
356
357 for (int i=1; i<=n_ancien; i++)
358 tab1_[i] = tab1_temp[i] - tab1_temp[i-1];
359 for (int i=n_ancien+1; i<=n; i++)
360 tab1_[i] = 0;
361
362 // Iterate over the indices of new coefficients to check if they are
363 // already present
364
365 int i_nouveaux = 0;
366 for (int i=0; i<nInd; i++)
367 {
368 int i0 = Ind(i,0);
369 int i1 = Ind(i,1) + 1;
370
371 int test_present = 0;
372
373 if (i0 < n_ancien)
374 {
375 auto kmin = tab1_temp[i0]-1;
376 auto kmax = tab1_temp[i0+1]-1;
377 for (auto k=kmin; k<kmax; k++)
378 if (tab2_[k] == i1)
379 {
380 test_present = 1;
381 break;
382 }
383 }
384 if (!test_present)
385 {
386 i_nouveaux++;
387 tab1_[i0+1] += 1;
388 }
389 }
390 if (i_nouveaux == 0)
391 {
392 tab1_=tab1_temp;
393 return;
394 }
395
396 // New array of positions of the first coefficients of each row
397 tab1_[0] = 1;
398 for (int i=1; i<=n; i++)
399 tab1_[i] += tab1_[i-1];
400
401 auto nnz_ancien = tab2_.size_array();
402 auto nnz = nnz_ancien + i_nouveaux;
403
404 auto tab2_temp(tab2_);
405 auto coeff_temp(coeff_);
406 tab2_.resize(nnz);
407 coeff_.resize(nnz);
408
409 // Copy old coefficients and their column indices
410 // into the new arrays
411
412 tab2_ = -1;
413 for (int i=0; i<n_ancien; i++)
414 {
415 for (auto j1 = tab1_temp[i]-1, j2 = tab1_[i]-1;
416 j1 < tab1_temp[i+1]-1;
417 j1++, j2++)
418 {
419 tab2_[j2] = tab2_temp[j1];
420 coeff_[j2] = coeff_temp[j1];
421 }
422 }
423
424 for (int i=0; i<nInd; i++)
425 {
426 int j0 = Ind(i,0);
427 int j1 = Ind(i,1) + 1;
428 auto k(tab1_(0));
429 for (k=tab1_[j0]-1; tab2_[k] >= 0; k++)
430 if (tab2_[k] == j1)
431 {
432 break;
433 }
434 if (tab2_[k] < 0)
435 {
436 tab2_[k] = j1;
437 coeff_[k] = 0.0;
438 }
439 }
440 // reorder coefficients... not optimal but for checking..
441 coeff_=0;
442 //
443 {
444 int nbis=nb_lignes();
445 for(int i=0; i<nbis; i++)
446 {
447 for (auto k=tab1_(i)-1; k<tab1_(i+1)-1; k++)
448 {
449 for (auto k2=k; k2<tab1_(i+1)-1; k2++)
450 {
451 int j1=tab2_(k);
452 int j2=tab2_(k2);
453 if (j1>j2)
454 {
455 tab2_(k)=j2;
456 tab2_(k2)=j1;
457 }
458 }
459 }
460 }
461 }
463}
464
465/*! @brief Size the matrix with n lines, m columns with nnz zero-values coefficients
466 *
467 */
468template<typename _SIZE_>
469void Matrice_Morse::dimensionner(int n, int m, _SIZE_ nnz)
470{
471 tab2_.resize(nnz);
472 coeff_.resize(nnz);
473 m_=m;
474
475 // check if tab1 has the right size and if tab1[n1]==nnz.
476 if ( tab1_.size_array()!=(n+1) || (tab1_[n]-1)!=nnz )
477 {
478 tab1_.resize(n+1);
479 tab1_=1;
480 }
481 tab1_.resize(n+1);
482 tab1_[n]=nnz+1;
483
485}
486
487/*! @brief Initialize to the identity matrix (modif MT)
488 *
489 */
491{
492 coeff_ = 0.0;
493 int i,n = ordre();
494 for (i=0; i<n; i++)
495 operator()(i,i) = 1.0;
496}
497
498/*! @brief Returns the order of the matrix: - the number of rows if the matrix is square
499 *
500 * - 0 otherwise
501 *
502 * @return (int) the order of the matrix
503 */
505{
506 if(nb_lignes()==nb_colonnes())
507 return nb_lignes();
508 else
509 return 0;
510}
511
512/*! @brief Method to check/clean the Matrice_Morse matrix: -Suppress coefficient defined several times
513 *
514 * -elim_coeff_nul=0, zero coefficients are not removed from the matrix
515 * -elim_coeff_nul=1, zero coefficients are removed from the matrix
516 * -elim_coeff_nul=2, zero and near-zero coefficients are removed from the matrix
517 *
518 */
519void Matrice_Morse::compacte(int elim_coeff_nul)
520{
521 int n=nb_lignes();
522 int coeff_nuls=0;
523 int coeff_quasi_nuls=0;
524 auto tab_elim_coeff(tab2_); // Possibly BigArrOfInt
525 tab_elim_coeff = 0;
526 if (elim_coeff_nul)
527 {
528 ArrOfDouble tab_coeff_max(n);
529 tab_coeff_max = 0.;
530 // Search for off-diagonal zero coefficients to remove from the Morse matrix
531 {
532 ArrOfInt tab_cnt(1);
533 tab_cnt = 0;
534 auto tab1 = tab1_.view_ro();
535 CDoubleArrView coeff = coeff_.view_ro();
536 DoubleArrView coeff_max = tab_coeff_max.view_rw();
537 auto elim_coeff = tab_elim_coeff.view_rw();
538 IntArrView cnt = tab_cnt.view_rw();
539 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(0, n), KOKKOS_LAMBDA(const int i)
540 {
541 auto k1 = tab1(i)-1;
542 auto k2 = tab1(i+1)-1;
543 for (auto k = k1; k < k2; k++)
544 {
545 double abs_c = Kokkos::fabs(coeff(k));
546 if (abs_c > coeff_max(i)) coeff_max(i) = abs_c;
547 if (coeff(k) == 0)
548 {
549 Kokkos::atomic_add(&cnt(0), 1);
550 elim_coeff(k) = 1;
551 }
552 }
553 });
554 end_gpu_timer(__KERNEL_NAME__);
555 coeff_nuls = tab_cnt(0);
556 }
557
558 if (elim_coeff_nul==2)
559 {
560 // Search for near-zero off-diagonal coefficients (1.e-12 smaller than the largest coefficient in the row) to remove from the Morse matrix
561 const double eps = Objet_U::precision_geom;
562 ArrOfInt tab_cnt(1);
563 tab_cnt = 0;
564 auto tab1 = tab1_.view_ro();
565 CDoubleArrView coeff = coeff_.view_ro();
566 CDoubleArrView coeff_max = tab_coeff_max.view_ro();
567 IntArrView elim_coeff = tab_elim_coeff.view_rw();
568 IntArrView cnt = tab_cnt.view_rw();
569 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(0, n), KOKKOS_LAMBDA(const int i)
570 {
571 double cm = coeff_max(i);
572 if (!est_egal(cm, 0., eps) && cm < 1e10)
573 {
574 auto k1 = tab1(i) - 1;
575 auto k2 = tab1(i + 1) - 1;
576 for (auto k = k1; k < k2; k++)
577 if (coeff(k) != 0 && est_egal(Kokkos::fabs(coeff(k)) / cm, 0., eps))
578 {
579 Kokkos::atomic_add(&cnt(0), 1);
580 elim_coeff(k) = 1;
581 }
582 }
583 });
584 end_gpu_timer(__KERNEL_NAME__);
585 coeff_quasi_nuls = tab_cnt(0);
586 }
587 }
588 // Recherche des coefficients doublons
589 int nb_doublons=0;
590 {
591 auto tab1 = tab1_.view_ro();
592 CIntArrView tab2 = tab2_.view_ro();
593 CDoubleArrView coeff = coeff_.view_ro();
594 IntArrView elim_coeff = tab_elim_coeff.view_rw();
595 ArrOfInt tab_doublons(1);
596 tab_doublons = 0;
597 ArrOfInt tab_error(1);
598 tab_error = 0;
599 IntArrView doublons = tab_doublons.view_rw();
600 IntArrView error = tab_error.view_rw();
601 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(0, n), KOKKOS_LAMBDA(const int i)
602 {
603 auto k1 = tab1(i)-1;
604 auto k2 = tab1(i+1)-1;
605 int jmax = -1; // Highest column of a coefficient in the line i
606 for (auto k = k1; k < k2; k++)
607 {
608 int j = tab2(k)-1;
609 if (j > jmax)
610 jmax = j;
611 else
612 {
613 // Found a column j lower than jmax, check if not defined before:
614 for (auto kk = k-1; kk >= k1; kk--)
615 {
616 int jj = tab2(kk)-1;
617 if (jj == j)
618 {
619 // Already defined!
620 Kokkos::atomic_add(&doublons(0), 1);
621 elim_coeff(k) = 1;
622 // Check if same coefficients:
623 if (coeff(kk) != coeff(k))
624 Kokkos::atomic_add(&error(0), 1);
625 break;
626 }
627 }
628 }
629 }
630 });
631 end_gpu_timer(__KERNEL_NAME__);
632 nb_doublons = tab_doublons(0);
633 if (tab_error(0))
634 {
635 Cerr << "Error in a Matrix Morse: duplicate entries with different values!" << finl;
636 exit();
637 }
638 }
639
640 auto nnz(tab1_(0));
641 nnz=0;
642 if (nb_doublons || coeff_nuls || coeff_quasi_nuls)
643 {
644 // Step 1: Count kept entries per row (parallel_for over rows)
645 ArrOfInt tab_kept_per_row(n);
646 {
647 auto tab1 = tab1_.view_ro();
648 CIntArrView elim_coeff = tab_elim_coeff.view_ro();
649 IntArrView kept_per_row = tab_kept_per_row.view_wo();
650 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(0, n), KOKKOS_LAMBDA(const int i)
651 {
652 int count = 0;
653 auto k1 = tab1(i)-1;
654 auto k2 = tab1(i+1)-1;
655 for (auto k = k1; k < k2; k++)
656 if (!elim_coeff(k)) count++;
657 kept_per_row(i) = count;
658 });
659 end_gpu_timer(__KERNEL_NAME__);
660 }
661
662 // Step 2: Save old tab1_ (needed for source offsets in scatter step)
663 auto old_tab1(tab1_);
664
665 // Step 3: Update tab1_ via prefix scan (updates tab1_(1..n), tab1_(0)=1 unchanged)
666 using tab1_scan_t = decltype(nnz);
667 {
668 auto tab1 = tab1_.view_rw();
669 CIntArrView kept_per_row = tab_kept_per_row.view_ro();
670 Kokkos::parallel_scan(start_gpu_timer(__KERNEL_NAME__), range_1D(0, n), KOKKOS_LAMBDA(const int i, tab1_scan_t& update, const bool final)
671 {
672 update += kept_per_row(i);
673 if (final) tab1(i+1) = update + 1;
674 });
675 end_gpu_timer(__KERNEL_NAME__);
676 }
677
678 // Step 4: Out-of-place scatter of coeff_ and tab2_ to new positions (parallel_for over rows)
679 // Safe because new_pos(i) <= old_pos(i) always, and rows are processed independently
680 nnz = tab1_[n] - 1;
681 auto new_coeff(coeff_);
682 auto new_tab2(tab2_);
683 {
684 auto tab1 = tab1_.view_ro();
685 auto old_tab1_ro = old_tab1.view_ro();
686 CDoubleArrView coeff_src = coeff_.view_ro();
687 CIntArrView tab2_src = tab2_.view_ro();
688 DoubleArrView coeff_dst = new_coeff.view_wo();
689 IntArrView tab2_dst = new_tab2.view_wo();
690 CIntArrView elim_coeff = tab_elim_coeff.view_ro();
691 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(0, n), KOKKOS_LAMBDA(const int i)
692 {
693 auto new_pos = tab1(i) - 1;
694 auto k1 = old_tab1_ro(i)-1;
695 auto k2 = old_tab1_ro(i+1)-1;
696 for (auto k = k1; k < k2; k++)
697 if (!elim_coeff(k))
698 {
699 coeff_dst(new_pos) = coeff_src(k);
700 tab2_dst(new_pos) = tab2_src(k);
701 new_pos++;
702 }
703 });
704 end_gpu_timer(__KERNEL_NAME__);
705 }
706
707 // Step 5: Copy compacted data back
708 {
709 auto tab2 = tab2_.view_rw();
710 auto coeff = coeff_.view_rw();
711 CIntArrView new_tab2_ro = new_tab2.view_ro();
712 CDoubleArrView new_coeff_ro = new_coeff.view_ro();
713 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(0, nnz), KOKKOS_LAMBDA(const int i)
714 {
715 tab2(i) = new_tab2_ro(i);
716 coeff(i) = new_coeff_ro(i);
717 });
718 end_gpu_timer(__KERNEL_NAME__);
719 }
720 }
721 else
722 {
723 nnz = tab1_[n] - 1;
724 }
725
726 // Resize the arrays
727 tab2_.resize(nnz);
728 coeff_.resize(nnz);
729
732}
733
734/*! @brief Assignment operator from one Matrice_Morse to another.
735 *
736 * @param (Matrice_Morse& a) the right-hand side of the assignment
737 */
748
749/*! @brief *this = transpose of a.
750 *
751 * @param (Matrice_Morse& a) the matrix to transpose
752 */
754{
755 int n=a.nb_lignes();
756 int jk=nb_lignes();
757 int job=1;
758 int ipos=1;
759 int m=a.nb_colonnes();
760 int l=nb_lignes();
761 if(m!=jk)
762 {
763 Cerr << "Matrice_Morse::transpose bad dimensions" << finl;
764 exit();
765 }
766 m=a.nb_lignes();
767 l=nb_colonnes();
768 if(m!=l)
769 {
770 Cerr << "Matrice_Morse::transpose bad dimensions" << finl;
771 exit();
772 }
773
774 for(int i=0; i<=jk; i++ ) tab1_[i] = 0 ;
775 for(int i=0; i<n; i++)
776 {
777 for(auto k=a.tab1_[i]-1; k<a.tab1_[i+1]-1; k++)
778 {
779 int j = a.tab2_[k] ;
780 tab1_[j] = tab1_[j] +1 ;
781 }
782 }
783 tab1_[0] = ipos ;
784 for(int i=0; i<jk; i++) tab1_[i+1] = tab1_[i] + tab1_[i+1] ;
785 for(int i=0; i<n; i++)
786 {
787 for(auto k=a.tab1_[i]-1; k<a.tab1_[i+1]-1; k++)
788 {
789 int j = a.tab2_[k]-1 ;
790 auto next = tab1_[j] ;
791 if (job == 1) coeff_[next-1] = a.coeff_[k] ;
792 tab2_[next-1] = i+1 ;
793 tab1_[j] = next+1 ;
794 }
795 }
796 for(int i=jk-1; i>=0; i--) tab1_[i+1] = tab1_[i] ;
797 tab1_[0] = ipos ;
798
800 return(*this);
801}
802
803
804//A=x*A with x a diagonal matrix stored as a vector
805//the same method can be used to store the result in
806//a different matrix than the initial one
808{
809 int m=nb_lignes();
810 int l=0;
811 int n=x.size_array();
812 if(n!=m)
813 {
814 Cerr << "Matrice_Morse::diagmulmat bad dimensions" << finl;
815 exit();
816 }
817 F77NAME(DIAMUA)(&m ,&l,
818 coeff_.addr(),tab2_.addr(),reinterpret_cast<const int*>(tab1_.addr()),x.addr(),
819 coeff_.addr(),tab2_.addr(),reinterpret_cast<int*>(tab1_.addr()));
820 return(*this);
821}
822
823//extract the upper part of a Morse matrix
824//the result matrix is the calling one
826{
827 int m=nb_lignes();
828 int n=a.nb_lignes();
829 if(m!=n)
830 {
831 Cerr << "Matrice_Morse::partie_sup : bad dimensions m!=n." << finl;
832 exit();
833 }
834 double t;
835 auto ko(tab1_(0));
836 auto kfirst (ko);
837 auto kdiag(ko);
838 ko = -1;
839 for(int i=0; i< n; i++)
840 {
841 kfirst = ko + 1 ;
842 kdiag = -1 ;
843 for(auto k = a.tab1_[i]-1; k< a.tab1_[i+1]-1; k++)
844 {
845 if (a.tab2_[k]-1 >= i)
846 {
847 ko++ ;
848 coeff_[ko] = a.coeff_[k] ;
849 tab2_[ko] = a.tab2_[k] ;
850 if (a.tab2_[k] == i) kdiag = ko ;
851 }
852 }
853 if (kdiag != -1 && kdiag != kfirst)
854 {
855 t = coeff_[kdiag] ;
856 coeff_[kdiag] = coeff_[kfirst] ;
857 coeff_[kfirst] = t ;
858 { int ktmp = tab2_[kdiag] ; tab2_[kdiag] = tab2_[kfirst] ; tab2_[kfirst] = ktmp ; }
859 }
860 tab1_[i] = kfirst+1 ;
861 }
862 auto nnz = (ko + 1) ;
863
864 tab1_[n] = (nnz) + 1 ;
865 tab2_.resize( nnz );
866 coeff_.resize( nnz );
868 return(*this);
869}
870
871/*! @brief Operation de multiplication-accumulation (saxpy) matrice vecteur.
872 *
873 * Operation: resu = resu + A*x
874 *
875 */
876DoubleVect& Matrice_Morse::ajouter_multvect_(const DoubleVect& tab_x,DoubleVect& tab_resu) const
877{
879 const int n = tab1_.size_array() - 1;
880 assert(tab_x.size_array() == nb_colonnes());
881 // Test in this order as the size() attribute may be invalid:
882 assert(tab_resu.size_array() == n || tab_resu.size() == n);
883 // If matrix, x, resu are on device, we compute on the device to avoid expensive copy during TRUST GCP:
884 if (tab_x.isDataOnDevice() && tab_resu.isDataOnDevice() && coeff_.isDataOnDevice())
885 {
886 //if (tab_x.line_size()>1) Process::exit("line_size>1 pour x dans Matrice_Morse::ajouter_multvect_");
887 // Faster implementation on GPU (ToDo Kokkos: future, use Kokkos kernel?)
888 auto tab1 = tab1_.view_ro();
889 CIntArrView tab2 = tab2_.view_ro();
890 CDoubleArrView coeff = coeff_.view_ro();
891 CDoubleArrView x = tab_x.view_ro();
892 DoubleArrView resu = tab_resu.view_rw();
893 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
894 Kokkos::RangePolicy<>(0, n), KOKKOS_LAMBDA(
895 const int i)
896 {
897 auto start = tab1(i)-1;
898 auto end = tab1(i + 1)-1;
899 double tmp {};
900
901 for (auto k = start; k < end; k++)
902 {
903 int j = tab2(k) - 1;
904 tmp+= coeff(k) * x(j);
905 }
906 resu(i) += tmp;
907 });
908 end_gpu_timer(__KERNEL_NAME__);
909 }
910 else
911 {
912 tab_x.ensureDataOnHost();
913 tab_resu.ensureDataOnHost();
914 coeff_.ensureDataOnHost();
915 // Fast CPU (old) implementation with pointer:
916 const DoubleVect& x = tab_x;
917 DoubleVect& resu = tab_resu;
918 const auto *tab1_ptr = tab1_.addr() + 1;
919 const int *tab2_ptr = tab2_.addr();
920 const double *coeff_ptr = coeff_.addr();
921 const double *x_fortran = x.addr() - 1; // to index x with a Fortran index
922 auto k_fortran = 1; // Fortran index in tab2 and coeff
923 for (int i = 0; i < n; i++, tab1_ptr++)
924 {
925 const auto kmax = *tab1_ptr; // tab1_[i+1] = Fortran index in tab2_
926 assert(kmax >= k_fortran && kmax <= tab2_.size_array() + 1);
927 double t = resu[i];
928 assert(k_fortran == tab1_[i] && tab2_ptr == tab2_.addr() + (k_fortran - 1));
929 for (; k_fortran < kmax; k_fortran++, tab2_ptr++, coeff_ptr++)
930 {
931 int colonne = *tab2_ptr; // Fortran index
932 assert(colonne >= 1 && colonne <= nb_colonnes());
933 t += (*coeff_ptr) * x_fortran[colonne];
934 }
935 resu[i] = t;
936 }
937 }
938 return tab_resu;
939}
940
941// Multiplication of the matrix by a vector x, using only the non-shared real items for x
942ArrOfDouble& Matrice_Morse::ajouter_multvect_(const ArrOfDouble& x,ArrOfDouble& resu,ArrOfInt& est_reel_pas_com) const
943{
944 ToDo_Kokkos("critical ?");
946 int n = nb_lignes();
947
948 assert(nb_colonnes()==x.size_array());
949 assert(n==resu.size_array());
950 for(int i=0; i<n; i++)
951 {
952 double t = 0.0;
953 for (auto k=tab1_(i)-1; k<tab1_(i+1)-1; k++)
954 {
955 int j=tab2_(k)-1;
956 if (est_reel_pas_com[j]) t += coeff_(k)*x[j];
957 }
958 resu[i] += t ;
959 }
960 return resu;
961}
962
963/*! @brief Matrix-matrix multiply-accumulate operation (saxpy) (matrix X represented by an array)
964 *
965 * Operation: RESU = RESU + A*X
966 *
967 * @param (DoubleTab& x) the matrix to multiply
968 * @param (DoubleTab& resu) the result matrix of the operation
969 * @return (DoubleTab&) the result matrix of the operation
970 */
971DoubleTab& Matrice_Morse::ajouter_multTab_(const DoubleTab& x,DoubleTab& resu) const
972{
973
974 if ( (x.nb_dim() == 1) && (resu.nb_dim() == 1))
975 {
976 ajouter_multvect(x,resu);
977 return resu;
978 }
979
981 int nb_comp = x.dimension(1);
982
983 assert(resu.dimension(1) == nb_comp);
984 double* t= new double[nb_comp];
985 int ncomp;
986 int n=nb_lignes();
987 for(int i=0; i<n; i++)
988 {
989 for (ncomp=0; ncomp<nb_comp; ncomp++)
990 t[ncomp] = 0.0;
991 for (auto k=tab1_(i)-1; k<tab1_(i+1)-1; k++)
992 for (ncomp=0; ncomp<nb_comp; ncomp++)
993 t[ncomp] += coeff_(k)*x(tab2_(k)-1,ncomp);
994 for (ncomp=0; ncomp<nb_comp; ncomp++)
995 resu(i,ncomp) += t[ncomp] ;
996 }
997 delete [] t;
998 return resu;
999}
1000
1001
1002/*! @brief Matrix-vector multiply-accumulate operation (saxpy), by the transposed matrix.
1003 *
1004 * Operation: resu = resu + A^{T}*x
1005 *
1006 * @param (DoubleVect& x) the vector to multiply
1007 * @param (DoubleVect& resu) the result vector of the operation
1008 * @return (DoubleVect&) the result vector of the operation
1009 */
1010DoubleVect& Matrice_Morse::ajouter_multvectT_(const DoubleVect& x,DoubleVect& resu) const
1011{
1013
1014 int n=nb_lignes();
1015 for(int i=0; i<n; i++)
1016 {
1017 double xi = x(i);
1018 for (auto k=tab1_(i)-1; k<tab1_(i+1)-1; k++)
1019 resu(tab2_(k)-1) += coeff_(k) * xi;
1020 }
1021 return resu;
1022}
1023
1024// Multiplication of the transposed matrix by a vector x, using only the non-shared real items
1025ArrOfDouble& Matrice_Morse::ajouter_multvectT_(const ArrOfDouble& x,ArrOfDouble& resu,ArrOfInt& est_reel_pas_com) const
1026{
1028 int n=nb_lignes();
1029
1030 assert(n==x.size_array());
1031 assert(nb_colonnes()==resu.size_array());
1032 for(int i=0; i<n; i++)
1033 {
1034 if (est_reel_pas_com[i])
1035 {
1036 double xi = x[i];
1037 for (auto k=tab1_(i)-1; k<tab1_(i+1)-1; k++)
1038 resu[tab2_(k)-1] += coeff_(k) * xi;
1039 }
1040 }
1041 return resu;
1042}
1043
1044/*! @brief Friend function (outside the class) of the Matrice_Morse class. Addition of 2 Morse-format matrices.
1045 *
1046 * Operation: returns (A+B)
1047 *
1048 * @param (Matrice_Morse& A) a Morse-format matrix
1049 * @param (Matrice_Morse& B) a Morse-format matrix
1050 * @return (Matrice_Morse) the result of the operation
1051 */
1053{
1054 int nrow=A.nb_lignes();
1055 int ncol=A.nb_colonnes();
1056 Matrice_Morse C;
1057 // PL: before sizing to nzmax we check if A and B don't happen to have the same structure...
1058 // This avoids a memory spike caused by matrix addition in Equation_base::dimensionner_matrice
1059 auto nzmax = A.has_same_morse_matrix_structure(B) ? A.nb_coeff() : A.nb_coeff() + B.nb_coeff();
1060 C.dimensionner(nrow, ncol, nzmax);
1061#ifndef TRUST_USE_GPU
1062 // Fortran call cause faster on serail version on some Baltik:
1063 int job = 1;
1064 int ierr = -1;
1065 IntVect iw(ncol);
1066 F77NAME(APLB)(&nrow, &ncol, &job, A.get_coeff().addr(), A.get_tab2().addr(), A.get_tab1().addr(),
1067 B.get_coeff().addr(), B.get_tab2().addr(), B.get_tab1().addr(), C.get_set_coeff().addr(),
1068 C.get_set_tab2().addr(), C.get_set_tab1().addr(),
1069 &nzmax, iw.addr(), &ierr);
1070#else
1071 // Algorithm (per row i):
1072 // 1. Collect entries from row i of A and B into a small temporary buffer
1073 // 2. Sort by column index
1074 // 3. Merge duplicate columns (accumulate coefficients)
1075 // 4. Write result into C and advance c_tab1
1076 //
1077 // Time: O((nnz_A + nnz_B) * log(max_nnz_per_row)) [sort dominates]
1078 // Space: O(max_nnz_per_row_A + max_nnz_per_row_B) [reused buffer]
1079 //
1080 // ToDo: Kokkos parallel version for GPU once CPU version is validated
1081 const auto& a_tab1 = A.get_tab1();
1082 const auto& a_tab2 = A.get_tab2();
1083 const auto& a_coeff = A.get_coeff();
1084 const auto& b_tab1 = B.get_tab1();
1085 const auto& b_tab2 = B.get_tab2();
1086 const auto& b_coeff = B.get_coeff();
1087 auto& c_tab1 = C.get_set_tab1();
1088 auto& c_tab2 = C.get_set_tab2();
1089 auto& c_coeff = C.get_set_coeff();
1090
1091 using idx_t = std::remove_reference_t<decltype(c_tab1[0])>;
1092 idx_t nnz_c = 0; // running count of non-zeros written into C (0-based offset)
1093 c_tab1[0] = 1; // 1-based (Morse/Fortran convention)
1094
1095 std::unordered_map<int, idx_t> col_to_pos;
1096 col_to_pos.reserve(256);
1097 for (int i = 0; i < nrow; ++i)
1098 {
1099 col_to_pos.clear();
1100
1101 // Step 1: copy A row i into C, recording each column's position
1102 for (auto k = a_tab1[i] - 1; k < a_tab1[i + 1] - 1; ++k)
1103 {
1104 c_tab2[nnz_c] = (int) a_tab2[k];
1105 c_coeff[nnz_c] = a_coeff[k];
1106 col_to_pos[(int) a_tab2[k]] = nnz_c;
1107 ++nnz_c;
1108 }
1109
1110 // Step 2: merge B row i — accumulate if column already in C, else append
1111 for (auto k = b_tab1[i] - 1; k < b_tab1[i + 1] - 1; ++k)
1112 {
1113 const int col = (int) b_tab2[k];
1114 auto it = col_to_pos.find(col);
1115 if (it != col_to_pos.end())
1116 c_coeff[it->second] += b_coeff[k]; // column shared with A: accumulate
1117 else
1118 {
1119 c_tab2[nnz_c] = col;
1120 c_coeff[nnz_c] = b_coeff[k];
1121 col_to_pos[col] = nnz_c;
1122 ++nnz_c;
1123 }
1124 }
1125
1126 c_tab1[i + 1] = nnz_c + 1; // 1-based pointer to start of next row
1127 }
1128#endif
1129 const auto nnz = C.tab1_[nrow] - 1;
1130 C.get_set_tab2().resize(nnz);
1131 C.get_set_coeff().resize(nnz);
1133 return(C);
1134}
1135
1137{
1138 int nrow = A.nb_lignes();
1139 for (int i = 0; i < nrow; i++)
1140 if (tab1_(i) != A.tab1_(i))
1141 return false;
1142 auto ncoeff = tab2_.size_array(), ncoeff_A = A.tab2_.size_array();
1143 if (ncoeff != ncoeff_A) return false;
1144
1145 for (auto i = 0; i < ncoeff; i++)
1146 if (tab2_(i) != A.tab2_(i))
1147 return false;
1148 return true;
1149}
1150
1151/*! @brief Computes the solution of the linear system: A * solution = secmem.
1152 *
1153 * The method used is GMRES preconditioned with ILUT.
1154 * WARNING: this method has probably never been tested in parallel
1155 *
1156 * @param (DoubleVect& secmem) the right-hand side of the linear system
1157 * @param (DoubleVect& solution) the solution of the system
1158 * @param (double coeff_seuil)
1159 * @return (int) always returns 1
1160 * @throws Error in ilut 'matrix may be wrong' dixit SAAD
1161 * @throws Error in ilut: overflow in L
1162 * @throws Error in ilut: overflow in U
1163 * @throws Illegal value for lfil: probably a memory corruption
1164 * @throws Empty row encountered
1165 * @throws Null pivot encountered! at step
1166 * @throws Something abnormal has happened: it is preferable to stop.
1167 */
1168// Delegates to the 4-arg version with max_iter=-1 (retry-on-failure mode, maxits=ordre())
1169int Matrice_Morse::inverse(const DoubleVect& secmem, DoubleVect& solution,
1170 double coeff_seuil) const
1171{
1172 return inverse(secmem, solution, coeff_seuil, -1);
1173}
1174
1175// Solves A*solution=secmem using ILUT-preconditioned PGMRES.
1176// max_iter<0: use ordre() as iteration limit and retry with stronger preconditioner on failure (returns 1).
1177// max_iter>=0: use max_iter as iteration limit and return 0 on failure (used by hyperbolic implicit).
1178int Matrice_Morse::inverse(const DoubleVect& secmem, DoubleVect& solution,
1179 double coeff_seuil, int max_iter) const
1180{
1182 {
1183 Cerr << "Matrice_Morse::inverse has never been tested in parallel" << finl;
1184 Cerr << "Try 'Solveur Gmres { diag }' or 'Solveur Petsc Gmres { precond diag { } }'" << finl;
1185 Cerr << "instead of 'Solveur Gmres { }' which is not parallelized yet." << finl;
1186 exit();
1187 }
1188
1189 const bool retry_on_failure = (max_iter < 0);
1190
1191 DoubleVect toto(secmem);
1192 int prems=1; // recompute L and U only when prems=1
1193 int lf_min = 10;
1194 int lf = std::min(lf_min, ordre()/2); // fill level for ILUT
1195 int nn = ordre();
1196 int ima = std::min(lf_min, ordre()/2); // Krylov space dimension
1197 IntVect ju, jlu;
1198 DoubleVect alu, vv;
1199 DoubleVect Resini(toto);
1200
1201 int ie=1;
1202 auto n2 = nb_coeff()+(2*lf*nn); // number of non-zeros in LU
1203
1204 double r, coeff_seuilr;
1205
1206precond:
1207 if (prems)
1208 {
1209 int iw = (int)(n2 + 2);
1210 ju.resize(nn);
1211 jlu.resize(iw);
1212 alu.resize(iw);
1213 double to = 1.e-10; // drop tolerance for ILUT
1214 DoubleVect w(nn+1);
1215 IntVect jw(2*nn);
1217 F77NAME(ILUT)(&nn, coeff_.addr(), tab2_.addr(), get_tab1_int32().addr(), &lf,
1218 &to, alu.addr(), jlu.addr(), ju.addr(),
1219 &iw, w.addr(), jw.addr(), &ie);
1220 switch(ie)
1221 {
1222 case 0:
1223 break;
1224 case -1:
1225 Cerr << "Error in ilut 'matrix may be wrong' dixit SAAD" << finl;
1226 exit();
1227 break;
1228 case -2:
1229 Cerr << "Error in ilut : overflow in L" << finl;
1230 exit();
1231 break;
1232 case -3:
1233 Cerr << "Error in ilut : overflow in U" << finl;
1234 exit();
1235 break;
1236 case -4:
1237 Cerr << "Illegal value for lfil : it may be a memory trouble" << finl;
1238 exit();
1239 break;
1240 case -5:
1241 Cerr << "Empty line met" << finl;
1242 exit();
1243 break;
1244 default:
1245 Cerr << "Pivot null met ! at step " << ie << finl;
1246 exit();
1247 break;
1248 }
1249 prems=0;
1250 }
1251
1252 vv.resize(nn*(ima+1));
1253 assert_espace_virtuel_vect(solution);
1254 multvect(solution, Resini);
1255 Resini -= toto;
1256 r = mp_prodscal(Resini, Resini);
1257 r = sqrt(r);
1258 Cout << " Initial residu : " << r << finl;
1259 coeff_seuilr = (r == 0) ? DMAXFLOAT : coeff_seuil/r;
1260 Resini = toto;
1261 int minits = 10;
1262 int maxits = std::max(minits, retry_on_failure ? nn : max_iter);
1263 int io = 0;
1264 F77NAME(PGMRES)(&nn, &ima, toto.addr(), solution.addr(), vv.addr(), &coeff_seuilr,
1265 &maxits, &io, coeff_.addr(), tab2_.addr(), get_tab1_int32().addr(),
1266 alu.addr(), jlu.addr(), ju.addr(), &ie);
1267 switch(ie)
1268 {
1269 case 0:
1270 Cout << " ** PGMRES has converged **" << finl;
1271 break;
1272 case 1:
1273 Cout << " ** No convergence after " << maxits << " iterations **" << finl;
1274 if (retry_on_failure)
1275 {
1276 toto = Resini;
1277 if (lf < 50)
1278 {
1279 lf += 5;
1280 Cerr << " The degree of the preconditioning matrix LU is increased: " << lf << finl;
1281 n2 = (int)tab2_.size_array()+(2*lf*nn);
1282 prems = 1;
1283 goto precond;
1284 }
1285 }
1286 else
1287 return 0;
1288 break;
1289 case -1:
1290 Cerr << "Convergence after 0 iterations !! 'stationnary state may be obtained'" << finl;
1291 break;
1292 default:
1293 Cerr << "Something abnormal has happened : it is preferable to stop." << finl;
1294 exit();
1295 }
1296 return 1;
1297}
1298
1299
1300/*! @brief Matrix-vector multiplication operator: scales rows of the matrix by the corresponding
1301 *
1302 * coefficients of the vector passed as a parameter.
1303 * A *= x performs the following scalings:
1304 * A(i,:) = A(i,:) * x(i), for all rows i of A
1305 *
1306 * @param (DoubleVect& x) scaling vector
1307 * @return (Matrice_Morse&) the result of the operation (*this)
1308 */
1310{
1311 for(int i = 0; i<nb_lignes(); i++)
1312 for(auto k = tab1_(i)-1; k<tab1_(i+1)-1; k++)
1313 coeff_(k) *= x(i);
1314 return *this;
1315}
1316
1317
1318/*! @brief Assigns the product of 2 Morse matrices A and B to this object.
1319 *
1320 * Operation: this = A * B
1321 *
1322 * @param (Matrice_Morse& A) a Morse-format matrix
1323 * @param (Matrice_Morse& B) a Morse-format matrix
1324 * @return (Matrice_Morse&) the result of the operation (*this)
1325 */
1327{
1328 int nrow= a.nb_lignes(); // number of rows of A
1329 int ncol= b.nb_colonnes(); // number of columns of B
1330 //assert(nrow==ncol);
1331 // Jloi non?
1332 assert(a.nb_colonnes()==b.nb_lignes());
1333 tab1_.resize(nrow+1);
1334 m_ = ncol;
1335 int job = 1 ; // retrieve everything (tab1, tab2, coeff of matrice_resu)
1336 auto nzmax = nb_coeff(); // max number of values of the result matrix
1337 if(nzmax==0)
1338 {
1339 nzmax=a.nb_coeff();
1340 tab2_.resize(nzmax);
1341 coeff_.resize(nzmax);
1342 assert(nzmax==nb_coeff());
1343 }
1344 IntVect iw(ncol+1); // work array
1345 double scal=0. ;
1346 int ii, jj ;
1347 int values = 0;
1348 if (job != 0) values = 1 ;
1349 auto len = -1 ;
1350 tab1_[0] = 1 ;
1351 iw = -1 ;
1352 for(ii=0; ii< nrow; ii++)
1353 {
1354 for(auto ka=a.tab1_[ii]-1; ka < a.tab1_[ii+1]-1; ka++)
1355 {
1356 if (values == 1) scal = a.coeff_[ka] ;
1357 jj = a.tab2_[ka] - 1 ;
1358 for (auto kb=b.tab1_[jj]-1; kb < b.tab1_[jj+1]-1; kb++)
1359 {
1360 int jcol = b.tab2_[kb] -1 ;
1361 int jpos = iw[jcol] ;
1362 if (jpos == -1)
1363 {
1364 len++ ;
1365 if (len > nzmax-1)
1366 {
1367 // Cerr << "Matrice_Morse::affect_prod len > nzmax -1 " << nzmax << finl;
1368 nzmax *= 2;
1369 coeff_.resize(nzmax);
1370 tab2_.resize(nzmax);
1371 }
1372 tab2_[len] = jcol + 1 ;
1373 iw[jcol]= (int)len ;
1374 if (values == 1) coeff_[len] = scal*b.coeff_[kb] ;
1375 }
1376 else
1377 {
1378 if (values == 1) coeff_[jpos] += scal*b.coeff_[kb] ;
1379 }
1380 }
1381 }
1382
1383 for (auto k=tab1_[ii]-1; k < len+1 ; k++) iw[tab2_[k]-1] = -1 ;
1384 tab1_[ii+1] = (len+1) + 1 ;
1385 }
1386
1387 coeff_.resize(tab1_[nrow]-1);
1388 tab2_.resize(tab1_[nrow]-1);
1390 return *this;
1391}
1392
1393
1394
1395/*! @brief Friend function (outside the class) of the Matrice_Morse class. Scaling of the matrix by a scalar: multiplies all
1396 *
1397 * elements of the matrix by a scalar.
1398 * Operation: returns x*A
1399 *
1400 * @param (double x) scaling value
1401 * @param (Matrice_Morse& B) a Morse-format matrix
1402 * @return (Matrice_Morse) the result of the operation
1403 */
1404Matrice_Morse operator *(double x , const Matrice_Morse& A)
1405{
1406 Matrice_Morse mat_res(A);
1407 mat_res.coeff_*=x;
1408 return(mat_res);
1409}
1410
1411/*! @brief Unary negation operator, returns the opposite of the matrix: - A. Calls operator*(double,const Matrice_Morse&)
1412 *
1413 * @return (Matrice_Morse) the result of the call to operator*(double,const Matrice_Morse&)
1414 */
1416{
1417 return((-1)*(*this));
1418}
1419
1420
1421/*! @brief DOES NOTHING
1422 *
1423 * @param (Matrice_Morse&) a Morse matrix
1424 * @return (Matrice_Morse&) always returns *this
1425 */
1427{
1428 // PL: Before doing expensive RAM operations, we check
1429 // if it is not the same structure:
1431 {
1432 auto size = A.nb_coeff();
1433 const auto& coeff = A.get_coeff();
1434 for (auto i=0; i<size; i++)
1435 coeff_(i)+=coeff(i);
1436 }
1437 else
1438 {
1439 *this = *this + A;
1441 }
1442 return *this;
1443}
1444
1445
1446/*! @brief Operator multiplying all elements of a matrix by a scalar.
1447 *
1448 * Operation: A = x * A
1449 *
1450 * @param (double x) the scaling parameter
1451 * @return (Matrice_Morse&) the result of the operation (*this)
1452 */
1454{
1455 scale( x );
1456 return(*this);
1457}
1458
1459void Matrice_Morse::scale( const double x )
1460{
1461 coeff_ *= x;
1462}
1463
1464void Matrice_Morse::get_stencil( Stencil& stencil ) const
1465{
1467
1469 {
1470 stencil = stencil_;
1471 return;
1472 }
1473
1474
1475 stencil.resize( 0, 2 );
1476 auto nnz = tab2_.size_array();
1477 stencil.resize(nnz, 2);
1478
1479
1480 ArrOfInt tmp;
1481
1482
1483 decltype(nnz) compteur = 0;
1484
1485 const int nb_lines = nb_lignes( );
1486 for ( int i=0; i<nb_lines; ++i )
1487 {
1488 auto k0 = tab1_( i ) - 1;
1489 auto k1 = tab1_( i + 1 ) - 1;
1490 const auto size = k1 - k0;
1491 const int size_int = (int)size;
1492
1493 tmp.resize_array( 0 );
1494 tmp.resize_array( size_int );
1495
1496 for ( int k=0; k<size_int; ++k )
1497 {
1498 tmp[ k ] = tab2_( k + k0 ) - 1;
1499 }
1500
1501 tmp.ordonne_array( );
1502
1503 for ( int k=0; k<size_int; ++k )
1504 {
1505 stencil( k+compteur , 0 ) = i;
1506 stencil( k+compteur , 1 ) = tmp[ k ];
1507 }
1508 compteur += size;
1509 }
1510
1511
1512}
1513
1514// Local template method : copy either value or ptr to value!
1515namespace
1516{
1517template<typename _T_> static inline void _fill_slot(_T_& dest, const double& src);
1518template<> inline void _fill_slot<double>(double& dest, const double& src)
1519{
1520 dest = src;
1521}
1522template<> inline void _fill_slot<const double *>(const double*& dest, const double& src)
1523{
1524 dest = &src;
1525}
1526}
1527
1528
1529template<typename _TAB_T_, typename _VALUE_T_>
1530inline void Matrice_Morse::get_stencil_coeff_templ( Stencil& stencil, _TAB_T_& coeffs_span) const
1531{
1532 auto nnz = tab2_.size_array();
1533 coeffs_span.resize(nnz);
1534 stencil.resize(nnz, 2);
1535 decltype(nnz) compteur = 0;
1536 const int nb_lines = nb_lignes( );
1537 for ( int i=0; i<nb_lines; ++i )
1538 {
1539 const auto k0 = tab1_( i ) - 1;
1540 const auto k1 = tab1_( i + 1 ) - 1;
1541 const int size_int = (int)(k1 - k0);
1542 for ( int k=0; k<size_int; ++k )
1543 {
1544 stencil( compteur + k , 0 ) = i;
1545 stencil( compteur + k , 1 ) = tab2_( k + k0 ) - 1;
1546 ::_fill_slot<_VALUE_T_>(coeffs_span[ compteur + k ], coeff_(k+k0));
1547 }
1548 compteur += size_int;
1549 }
1550
1551
1552}
1553
1554
1556 std::vector<const double *>& coeff_ptr) const
1557{
1559
1561 {
1562 Cerr << "Error in Matrice_Morse::get_symmetric_stencil_and_coeff_ptrs( )"<<finl;
1563 Cerr << " stencil up to date - function not impl. in this case."<<finl;
1564 Cerr << " Aborting..." << finl;
1565 Process::abort( );
1566 return;
1567 }
1568
1569 get_stencil_coeff_templ< std::vector<const double *>, const double *>(stencil, coeff_ptr);
1570 assert( (trustIdType)coeff_ptr.size( ) == stencil.dimension( 0 ));
1571}
1572
1573
1575 StencilCoeffs& coefficients ) const
1576{
1578 {
1579 if( coeff_.size( ) == 0 )
1580 {
1581 Cerr << "Error in Matrice_Morse::get_stencil_and_coefficients( )"<<finl;
1582 Cerr << " The coefficients are not filled."<<finl;
1583 Cerr << " Aborting..." << finl;
1584 Process::abort( );
1585 }
1586 stencil = stencil_ ;
1587 { const auto sz = coeff_.size_array(); coefficients.resize(sz); for (auto k=sz-sz; k<sz; k++) coefficients[k] = coeff_[k]; }
1588 return;
1589 }
1590
1591
1592
1594 assert( coefficients.size_array( ) == stencil.dimension( 0 ));
1595}
1596
1597
1598/*! @brief Operator dividing all elements of a matrix by a scalar.
1599 *
1600 * Operation: A = A / x
1601 *
1602 * @param (double x) the scaling parameter
1603 * @return (Matrice_Morse&) the result of the operation (*this)
1604 * @throws division by zero not possible
1605 */
1607{
1608 coeff_/=x;
1609 return(*this);
1610}
1611
1612void Matrice_Morse::remplir(const IntLists& voisins,
1613 const DoubleLists& valeurs,
1614 const DoubleVect& terme_diag)
1615{
1616
1617 int num_elem;
1618 int compteur,rang =0;
1619
1620 // Fill arrays tab1, tab2 and coeff_:
1621 auto* p_tab1 = tab1_.addr();
1622 int* p_tab2 = tab2_.addr();
1623 double* p_coeff = coeff_.addr();
1624
1625 int* tab2_ptr = p_tab2;
1626 int n=nb_lignes();
1627
1628 for (num_elem=0; num_elem<n; num_elem++)
1629 {
1630
1631 IntList_Curseur liste_vois(voisins[num_elem]);
1632 DoubleList_Curseur liste_val(valeurs[num_elem]);
1633 compteur =0;
1634 *p_tab1++ = rang;
1635
1636 *tab2_ptr++=num_elem;
1637 *p_coeff++ = terme_diag[num_elem];
1638
1639 while (liste_vois)
1640 {
1641 *tab2_ptr++ = liste_vois.valeur();
1642 *p_coeff++ = liste_val.valeur();
1643 ++liste_vois;
1644 ++liste_val;
1645 compteur++;
1646 }
1647 // tab2[rang] = compteur;
1648 rang += (compteur + 1);
1649 }
1650 tab1_(num_elem)=rang;
1651 formeF();
1654}
1655
1656void Matrice_Morse::remplir(const IntLists& voisins,
1657 const DoubleLists& valeurs)
1658{
1659
1660 int num_elem;
1661 int compteur,rang =0;
1662
1663 // Fill arrays tab1, tab2 and coeff_:
1664 auto* p_tab1 = tab1_.addr();
1665 int* p_tab2 = tab2_.addr();
1666 double* p_coeff = coeff_.addr();
1667
1668 int* tab2_ptr = p_tab2;
1669 int n=nb_lignes();
1670
1671 for (num_elem=0; num_elem<n; num_elem++)
1672 {
1673
1674 IntList_Curseur liste_vois(voisins[num_elem]);
1675 DoubleList_Curseur liste_val(valeurs[num_elem]);
1676 compteur =0;
1677 *p_tab1++ = rang;
1678
1679 while (liste_vois)
1680 {
1681 *tab2_ptr++ = liste_vois.valeur();
1682 *p_coeff++ = liste_val.valeur();
1683 ++liste_vois;
1684 ++liste_val;
1685 compteur++;
1686 }
1687 // tab2[rang] = compteur;
1688 rang += (compteur);
1689 }
1690 tab1_(num_elem)=rang;
1691 formeF();
1694}
1695
1696/*! @brief Fill a Morse matrix from a smaller Morse matrix
1697 *
1698 */
1699void Matrice_Morse::remplir(const int ideb, const int jdeb, const int n, const int m, const Matrice_Morse& mat)
1700{
1701 // Verification
1702 assert(ideb<=n);
1703 assert(jdeb<=m);
1704
1705 // Build a local matrix
1706 Matrice_Morse matrice_locale(mat);
1707 // Case where the local matrix is symmetric
1708 if (sub_type(Matrice_Morse_Sym,mat))
1709 {
1710 // Create the lower part L
1711 Matrice_Morse L(matrice_locale);
1712 L.transpose(matrice_locale);
1713 int lordre = L.ordre();
1714 for (int i=0; i<lordre; i++)
1715 L(i, i) = 0.;
1716 // Add M=U+L
1717 matrice_locale += L;
1718 }
1719
1720 // Size the global matrix
1721 auto nnz=matrice_locale.nb_coeff();
1722 dimensionner(n,m,(int)nnz);
1723
1724 // Fill the global matrix from the local matrix:
1725 // Fill tab1_ with offset ideb:
1726 int mon_nb_lignes=matrice_locale.nb_lignes();
1727 assert(mon_nb_lignes+ideb<=n);
1728 for (int i=0; i<ideb; i++)
1729 tab1_(i)=1;
1730 for (int i=0; i<mon_nb_lignes; i++)
1731 tab1_(i+ideb)=matrice_locale.tab1_(i);
1732 for (int i=mon_nb_lignes+ideb; i<n+1; i++)
1733 tab1_(i)=matrice_locale.tab1_(mon_nb_lignes);
1734
1735 // Fill tab2_ with offset jdeb:
1736 for (auto i=0; i<nnz; i++)
1737 tab2_(i)=matrice_locale.tab2_(i)+jdeb;
1738
1739 // Fill coeff_:
1740 for (auto i=0; i<nnz; i++)
1741 coeff_(i)=matrice_locale.coeff_(i);
1742
1745}
1746
1748{
1749 int n=nb_lignes();
1750 for(int ii=0; ii<=n; ii++)
1751 tab1_(ii)--;
1752 for(int ii=0; ii<n; ii++)
1753 tab2_(tab1_(ii))=nb_vois(ii);
1754 for(auto k=0; k<nb_coeff(); k++)
1755 tab2_(k)--;
1758}
1759
1761{
1762 int n=nb_lignes();
1763 for(int ii=0; ii<=n; ii++)
1764 tab1_(ii)++;
1765 for(auto k=0; k<nb_coeff(); k++)
1766 tab2_(k)++;
1769}
1770
1771
1772
1773
1774/*! @brief DOES NOTHING
1775 *
1776 * @return (int) always returns 1
1777 */
1778int Matrice_Morse_test()
1779{
1780 return 1;
1781}
1782
1783/*! @brief Remplit la matrice avec des zeros.
1784 *
1785 */
1786
1788{
1789 coeff_ = 0;
1790}
1791
1792/*! @brief Computes the bandwidth of a Morse matrix
1793 *
1794 */
1796{
1797 int ldist,min = 0;
1798 const auto* p_tab1_ = get_tab1().addr();
1799 const int* p_tab2_ = get_tab2().addr();
1800 int N=ordre();
1801
1802 for(int i=0; i<N; i++)
1803 for(auto k = p_tab1_[i]; k < p_tab1_[i+1]; k++)
1804 {
1805 if (p_tab2_[k-1]-1<N)
1806 {
1807 ldist = p_tab2_[k-1] - i;
1808 if( min < ldist ) min = ldist;
1809 }
1810 };
1811 return min;
1812}
1813
1815{
1816 const int nb_lines = nb_lignes( );
1817 const int nb_columns = nb_colonnes( );
1818 const auto nb_coefficients = tab1_( nb_lines ) - 1;
1819
1820 if ( tab2_.size_array( ) != nb_coefficients )
1821 {
1822 Cerr << "invalid tab2 size" << finl;
1823 return false;
1824 }
1825
1826 if ( coeff_.size_array( ) != nb_coefficients )
1827 {
1828 Cerr << "invalid coeff size" << finl;
1829 return false;
1830 }
1831
1832 ArrOfBit flags( nb_columns );
1833
1834 for ( int i=0; i<nb_lines; ++i )
1835 {
1836 flags = 0;
1837
1838 auto k0 = tab1_( i ) - 1;
1839 auto k1 = tab1_( i + 1 ) - 1;
1840
1841 for ( auto k=k0; k<k1; ++k )
1842 {
1843 int j = tab2_( k ) - 1;
1844
1845 if ( j < 0 )
1846 {
1847 Cerr << "invalid column index (<0): " << j << finl;
1848 return false;
1849 }
1850
1851 if ( j >= nb_columns )
1852 {
1853 Cerr << "invalid column index (>nb_cols): " << j << " > " << nb_columns << finl;
1854 return false;
1855 }
1856
1857 if ( flags[ j ] )
1858 {
1859 Cerr << "invalid coefficient ( " << i << ", " << j << " ): already defined ( " << k << " )" << finl;
1860 return false;
1861 }
1862
1863 flags.setbit( j );
1864 }
1865 }
1866
1867 return true;
1868}
1869
1871{
1872 const int nb_lines = nb_lignes( );
1873 const int nb_columns = nb_colonnes( );
1874 const auto nb_coefficients = tab1_( nb_lines ) - 1;
1875
1876 if ( tab2_.size_array( ) != nb_coefficients )
1877 {
1878 Cerr << "invalid tab2 size" << finl;
1879 return false;
1880 }
1881
1882 if ( coeff_.size_array( ) != nb_coefficients )
1883 {
1884 Cerr << "invalid coeff size" << finl;
1885 return false;
1886 }
1887
1888 ArrOfBit flags( nb_columns );
1889
1890 for ( int i=0; i<nb_lines; ++i )
1891 {
1892 flags = 0;
1893
1894 auto k0 = tab1_( i ) - 1;
1895 auto k1 = tab1_( i + 1 ) - 1;
1896
1897 int j0 = tab2_( k0 ) - 1 - 1;
1898
1899 for ( auto k=k0; k<k1; ++k )
1900 {
1901 int j = tab2_( k ) - 1;
1902
1903 if ( j < 0 )
1904 {
1905 Cerr << "invalid column index (<0): " << j << finl;
1906 return false;
1907 }
1908
1909 if ( j >= nb_columns )
1910 {
1911 Cerr << "invalid column index (>nb_cols): " << j << " > " << nb_columns << finl;
1912 return false;
1913 }
1914
1915 if ( flags[ j ] )
1916 {
1917 Cerr << "invalid coefficient ( " << i << ", " << j << " ): already defined ( " << k << " )" << finl;
1918 return false;
1919 }
1920
1921 if ( j <= j0 )
1922 {
1923 Cerr << "unsorted coefficient: ( " << i << ", " << j << " ) after ( " << i << ", " << j0 << " ) " << finl;;
1924 return false;
1925 }
1926
1927 j0 = j;
1928 flags.setbit( j );
1929 }
1930 }
1931
1932 return true;
1933}
1934
1935
1937{
1939#ifndef NDEBUG
1940 if ( ! ( check_morse_matrix_structure( ) ) )
1941 {
1942 Cerr << "Error in 'Matrice_Morse::assert_check_morse_matrix_structure( )':" << finl;
1943 Cerr << " Exiting..." << finl;
1944 Process::exit( );
1945 }
1946 else
1948#endif
1949}
1950
1952{
1954#ifndef NDEBUG
1956 {
1957 Cerr << "Error in 'Matrice_Morse::assert_check_sorted_morse_matrix_structure( )':" << finl;
1958 Cerr << " Exiting..." << finl;
1959 Process::exit( );
1960 }
1961 else
1963#endif
1964}
1965
1966// Build a new Morse matrix spanning the rectangular area defined by the two points (nl0, nc0) and (nl1, nc1)
1967// in the original matrix.
1968// Indices are provided in C mode (0-based indexing).
1969void Matrice_Morse::construire_sous_bloc(int nl0, int nc0, int nl1, int nc1, Matrice_Morse& result) const
1970{
1971 // count non-zero entries:
1972 assert(nl0 >= 0);
1973 assert(nc0 >= 0);
1974 assert(nl0 <= nl1);
1975 assert(nc0 <= nc1);
1976
1977 auto max_nnz = tab1_(nl1+1) - tab1_(nl0); // maximum number of zeros that we will find
1978 int tot=0;
1979 IntTab loca((int)max_nnz, 2);
1980 DoubleTab sub_coeffs((int)max_nnz);
1981 for (int li=nl0; li <= nl1; li++)
1982 {
1983 auto idx_coeff = tab1_(li)-1;
1984 int nb_coeff_on_line = (int)(tab1_(li+1)-tab1_(li));
1985 for (int j=0; j < nb_coeff_on_line; j++)
1986 {
1987 int col_idx = tab2_(j+idx_coeff)-1;
1988 if (col_idx >= nc0 && col_idx <= nc1) // is the coeff in the window?
1989 {
1990 loca(tot, 0) = li - nl0;
1991 loca(tot, 1) = col_idx - nc0;
1992 sub_coeffs(tot) = coeff_(j+idx_coeff);
1993 tot++;
1994 }
1995 }
1996 }
1997 loca.resize(tot,2);
1998 sub_coeffs.resize(tot);
1999
2000 result.dimensionner(loca);
2001 // Set coefficient values:
2002 for (int i =0 ; i < tot; i++)
2003 {
2004 int il = loca(i, 0);
2005 int ic = loca(i, 1);
2006 result.coef(il, ic) = sub_coeffs(i);
2007 }
2008}
2009
2011{
2012 if (sorted_) return; //already done
2013 for (int i = 0; i + 1 < tab1_.size_array(); i++) //indice de ligne
2014 std::sort(tab2_.addr() + tab1_(i) - 1, tab2_.addr() + tab1_(i + 1) - 1);
2016}
2017
2018// Check if the matrix is sorted based on a stencil condition
2020{
2021 if (!sorted_)
2022 {
2023 const int n = nb_lignes();
2024 for (int i = 0; i < n; i++)
2025 {
2026 const auto k0 = tab1_( i ) - 1;
2027 const auto k1 = tab1_( i + 1 ) - 1;
2028 for (auto k=k0; k<k1-1; k++)
2029 if (tab2_(k)>tab2_(k+1))
2030 return sorted_; // not sorted
2031 }
2032 sorted_ = true;
2033 }
2034 return sorted_;
2035}
2036
2037// Check the matrix is diagonal:
2038// Faster than using:
2039// Stencil stencil;
2040// A.get_stencil(stencil);
2041// Matrix_tools::is_diagonal_stencil(A.nb_lignes(), A.nb_colonnes(), stencil);
2043{
2044 bool is_diagonal = true;
2045 const int n = nb_lignes();
2046 for (int i = 0; i < n; i++)
2047 {
2048 const auto k1 = get_tab1()(i) - 1;
2049 const auto k2 = get_tab1()(i + 1) - 1;
2050 for (auto k = k1; k < k2; k++)
2051 {
2052 if (k2-k1>1 || get_tab2()(k)-1!=i)
2053 {
2054 is_diagonal = false;
2055 break;
2056 }
2057 }
2058 }
2059 return is_diagonal;
2060}
2061
2062// Explicit instantiations for 'auto nnz' abbreviated function templates
2063template Matrice_Morse::Matrice_Morse(int, int);
2064template Matrice_Morse::Matrice_Morse(int, int, int);
2065template void Matrice_Morse::dimensionner(int, int);
2066template void Matrice_Morse::dimensionner(int, int, int);
2067#ifdef TRUST_USE_GPU
2068template Matrice_Morse::Matrice_Morse(int, trustIdType);
2069template Matrice_Morse::Matrice_Morse(int, int, trustIdType);
2070template void Matrice_Morse::dimensionner(int, trustIdType);
2071template void Matrice_Morse::dimensionner(int, int, trustIdType);
2072#endif
void setbit(int_t i) const
Set bit e to 1.
Definition ArrOfBit.h:73
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.
bool is_stencil_up_to_date_
virtual DoubleVect & multvect(const DoubleVect &, DoubleVect &) const
Multiplication of a vector by the matrix.
Stencil stencil_
virtual DoubleVect & ajouter_multvect(const DoubleVect &x, DoubleVect &r) const
Matrix-vector multiply-accumulate operation (saxpy).
bool is_stencil_up_to_date() 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,.
void clean() override
Remplit la matrice avec des zeros.
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
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
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.
double coef(int i, int j) const
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
An array of character strings (VECT(Nom)).
Definition Noms.h:26
friend class Sortie
Definition Objet_U.h:70
virtual Entree & readOn(Entree &)
Reads an Objet_U from an input stream. Virtual method to override.
Definition Objet_U.cpp:289
static double precision_geom
Definition Objet_U.h:81
static const Nom & nom_du_cas()
Returns a constant reference to the case name. This method is static.
Definition Objet_U.cpp:145
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
static bool is_parallel()
Definition Process.cpp:108
static void abort()
Abort routine for TRUST on a fatal error.
Definition Process.cpp:573
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 void barrier()
Synchronizes all processors in the current group (waits until all processors have reached the barrier...
Definition Process.cpp:133
static int me()
Returns the rank of the local processor in the current communication group. See Comm_Group::rank() an...
Definition Process.cpp:122
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
SFichier is to the C++ ofstream class what Sortie is to the C++ ostream class.
Definition SFichier.h:29
void precision(int pre) override
void setf(IOS_FORMAT code) override
Base class for output streams.
Definition Sortie.h:52
_SIZE_ size_array() const
_TYPE_ * addr()
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
void ordonne_array()
void resize(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTArray.h:156
bool isDataOnDevice() const
_TYPE_ valeur() const
Definition TRUSTList.h:115
int nb_dim() const
Definition TRUSTTab.h:199
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size() const
Definition TRUSTVect.tpp:45
void resize(_SIZE_, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTVect.tpp:91