Xyst test code coverage report
Current view: top level - LinearSolver - CSR.cpp (source / functions) Hit Total Coverage
Commit: e489e3468f2b950872163df1285c13fa7a355e8c Lines: 108 109 99.1 %
Date: 2024-11-20 18:31:06 Functions: 9 9 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 105 132 79.5 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/LinearSolver/CSR.cpp
       4                 :            :   \copyright 2012-2015 J. Bakosi,
       5                 :            :              2016-2018 Los Alamos National Security, LLC.,
       6                 :            :              2019-2021 Triad National Security, LLC.,
       7                 :            :              2022-2024 J. Bakosi
       8                 :            :              All rights reserved. See the LICENSE file for details.
       9                 :            :   \brief     Compressed sparse row (CSR) storage for a sparse matrix
      10                 :            : */
      11                 :            : // *****************************************************************************
      12                 :            : 
      13                 :            : #include "Exception.hpp"
      14                 :            : #include "CSR.hpp"
      15                 :            : #include "Reorder.hpp"
      16                 :            : 
      17                 :            : using tk::CSR;
      18                 :            : 
      19                 :        708 : CSR::CSR( std::size_t nc,
      20                 :            :           const std::pair< std::vector< std::size_t >,
      21                 :        708 :                            std::vector< std::size_t > >& psup )
      22                 :            : try :
      23                 :        708 :   ncomp( nc ),
      24         [ +  + ]:        709 :   rnz( psup.second.size()-1 ),
      25         [ +  - ]:        707 :   ia( rnz.size()*ncomp+1 )
      26                 :            : // *****************************************************************************
      27                 :            : //  Constructor: Create a CSR symmetric matrix with ncomp scalar components per
      28                 :            : //  non-zero matrix entry, storing only the upper triangular part
      29                 :            : //! \param[in] nc Number of scalar components (degrees of freedom)
      30                 :            : //! \param[in] psup Points surrounding points of mesh graph, see tk::genPsup
      31                 :            : // *****************************************************************************
      32                 :            : {
      33 [ +  + ][ +  - ]:        707 :   Assert( ncomp > 0, "Sparse matrix ncomp must be positive" );
         [ +  - ][ +  - ]
      34 [ -  + ][ -  - ]:        706 :   Assert( rnz.size() > 0, "Sparse matrix size must be positive" );
         [ -  - ][ -  - ]
      35                 :            : 
      36                 :        706 :   const auto& psup1 = psup.first;
      37                 :        706 :   const auto& psup2 = psup.second;
      38                 :            : 
      39                 :            :   // Calculate number of nonzeros in each block row (rnz), total number of
      40                 :            :   // nonzeros (nnz), and fill in row indices (ia)
      41                 :            :   std::size_t nnz, i;
      42         [ +  + ]:      43690 :   for (ia[0]=1, nnz=i=0; i<psup2.size()-1; ++i) {
      43                 :            :     // add up and store nonzeros of row i (only upper triangular part)
      44                 :            :     std::size_t j;
      45         [ +  + ]:     400970 :     for (rnz[i]=1, j=psup2[i]+1; j<=psup2[i+1]; ++j)
      46                 :     357986 :       ++rnz[i];
      47                 :            : 
      48                 :            :     // add up total number of nonzeros
      49                 :      42984 :     nnz += rnz[i] * ncomp;
      50                 :            : 
      51                 :            :     // fill up row index
      52         [ +  + ]:      88518 :     for (std::size_t k=0; k<ncomp; ++k)
      53                 :      45534 :       ia[i*ncomp+k+1] = ia[i*ncomp+k] + rnz[i];
      54                 :            :   }
      55                 :            : 
      56                 :            :   // Allocate storage for matrix values and column indices
      57         [ +  - ]:        706 :   a.resize( nnz, 0.0 );
      58         [ +  - ]:        706 :   ja.resize( nnz );
      59                 :            : 
      60                 :            :   // fill column indices
      61         [ +  + ]:      43690 :   for (i=0; i<rnz.size(); ++i)
      62         [ +  + ]:      88518 :     for (std::size_t k=0; k<ncomp; ++k) {
      63                 :      45534 :       auto itmp = i*ncomp+k;
      64                 :      45534 :       ja[ia[itmp]-1] = itmp+1;  // put in column index of diagonal
      65         [ +  + ]:     425940 :       for (std::size_t n=1, j=psup2[i]+1; j<=psup2[i+1]; ++j) {
      66                 :            :         // put in column index of an off-diagonal
      67                 :     380406 :         ja[ia[itmp]-1+(n++)] = psup1[j]*ncomp+k+1;
      68                 :            :       }
      69                 :            :     }
      70                 :            : 
      71                 :            :   // (bubble-)sort column indices
      72         [ +  + ]:      43690 :   for (i=0; i<rnz.size(); ++i)
      73         [ +  + ]:      88518 :     for (std::size_t k=0; k<ncomp; ++k)
      74         [ +  + ]:     425940 :       for (std::size_t j=psup2[i]+1; j<=psup2[i+1]; ++j)
      75         [ +  + ]:    3962004 :          for (std::size_t l=1; l<rnz[i]; ++l)   // sort column indices of row i
      76         [ +  + ]:   24227346 :             for (std::size_t e=0; e<rnz[i]-l; ++e)
      77         [ +  + ]:   20645748 :               if (ja[ia[i*ncomp+k]-1+e] > ja[ia[i*ncomp+k]+e])
      78                 :     190203 :                 std::swap( ja[ia[i*ncomp+k]-1+e], ja[ia[i*ncomp+k]+e] );
      79                 :            : 
      80                 :          4 : } // Catch std::exception
      81         [ -  + ]:          2 :   catch (std::exception& se) {
      82                 :            :     // (re-)throw tk::Excpetion
      83 [ +  - ][ +  - ]:          2 :     Throw( std::string("RUNTIME ERROR in CSR constructor: ") + se.what() );
         [ +  - ][ +  - ]
      84                 :        708 :   }
      85                 :            : 
      86                 :            : const tk::real&
      87                 :    4778354 : CSR::operator()( std::size_t row, std::size_t col, std::size_t pos ) const
      88                 :            : // *****************************************************************************
      89                 :            : //  Return const reference to sparse matrix entry at a position specified
      90                 :            : //  using relative addressing
      91                 :            : //! \param[in] row Block row
      92                 :            : //! \param[in] col Block column
      93                 :            : //! \param[in] pos Position in block
      94                 :            : //! \return Const reference to matrix entry at position specified
      95                 :            : // *****************************************************************************
      96                 :            : {
      97                 :    4778354 :   auto rncomp = row * ncomp;
      98                 :            : 
      99         [ +  - ]:   27722163 :   for (std::size_t n=0, j=ia[rncomp+pos]-1; j<ia[rncomp+pos+1]-1; ++j, ++n)
     100         [ +  + ]:   27722163 :     if (col*ncomp+pos+1 == ja[j])
     101                 :    4778354 :       return a[ia[rncomp+pos]-1+n];
     102                 :            : 
     103 [ -  - ][ -  - ]:          0 :   Throw("Sparse matrix index not found");
                 [ -  - ]
     104                 :            : }
     105                 :            : 
     106                 :            : void
     107                 :      65528 : CSR::dirichlet(
     108                 :            :   std::size_t i,
     109                 :            :   tk::real val,
     110                 :            :   std::vector< tk::real >& b,
     111                 :            :   const std::vector< std::size_t >& gid,
     112                 :            :   const std::unordered_map< int, std::unordered_set<std::size_t> >& nodecommap,
     113                 :            :   std::size_t pos )
     114                 :            : // *****************************************************************************
     115                 :            : //  Set Dirichlet boundary condition at a node
     116                 :            : //! \param[in] i Local id at which to set Dirichlet BC
     117                 :            : //! \param[in] val Value of Dirichlet BC
     118                 :            : //! \param[in,out] b RHS to modify as a result of setting the Dirichlet BC
     119                 :            : //! \param[in] gid Local->global node id map
     120                 :            : //! \param[in] nodecommap Node communication map with global node ids
     121                 :            : //! \param[in] pos Position in block
     122                 :            : //! \details In parallel there can be multiple contributions to a single node
     123                 :            : //!   on the mesh, and correspondingly, a single matrix row can be partially
     124                 :            : //!   represented on multiple partitions. Setting a Dirichlet BC entails
     125                 :            : //!   zeroing out the row of the matrix and putting 1/N into the diagonal entry,
     126                 :            : //!   where N is the number of partitions that contribute to the mesh node
     127                 :            : //!   (matrix row). As a result, when the matrix participates in a matrix-vector
     128                 :            : //!   product, where the partial contributions across all partitions are
     129                 :            : //!   aggregated, the diagonal will contain 1 after the sum across partitions.
     130                 :            : //! \note Both gid and nodecommap are optional - unused in serial. If nodecommap
     131                 :            : //!   is empty, serial is assumed and gid is unused.
     132                 :            : // *****************************************************************************
     133                 :            : {
     134                 :      65528 :   auto incomp = i * ncomp;
     135                 :            : 
     136                 :            :   // apply Dirichlet BC on rhs, zero column
     137         [ +  + ]:  110703256 :   for (std::size_t r=0; r<rnz.size()*ncomp; ++r) {
     138         [ +  + ]: 1203583419 :     for (std::size_t j=ia[r]-1; j<ia[r+1]-1; ++j) {
     139         [ +  + ]: 1093559879 :       if (incomp+pos+1 == ja[j]) {
     140                 :     614188 :         b[r] += a[j] * val;
     141                 :     614188 :         a[j] = 0.0;
     142                 :     614188 :         break;
     143                 :            :       }
     144                 :            :     }
     145                 :            :   }
     146                 :            : 
     147                 :            :   // zero row and put in diagonal
     148         [ +  + ]:      65528 :   auto diag = nodecommap.empty() ? 1.0 : 1.0/tk::count(nodecommap,gid[i]);
     149         [ +  + ]:     679716 :   for (std::size_t j=ia[incomp+pos]-1; j<ia[incomp+pos+1]-1; ++j) {
     150         [ +  + ]:     614188 :     if (incomp+pos+1 == ja[j]) a[j] = diag; else a[j] = 0.0;
     151                 :            :   }
     152                 :      65528 : }
     153                 :            : 
     154                 :            : void
     155                 :     103307 : CSR::mult( const std::vector< real >& x, std::vector< real >& r ) const
     156                 :            : // *****************************************************************************
     157                 :            : //  Multiply CSR matrix with vector from the right: r = A * x
     158                 :            : //! \param[in] x Vector to multiply matrix with from the right
     159                 :            : //! \param[in] r Result vector of product r = A * x
     160                 :            : //! \note This is only complete in serial. In parallel, this computes the own
     161                 :            : //!   contributions to the product, so it must be followed by communication
     162                 :            : //!   summing the products of rows stored on multiple partitions.
     163                 :            : // *****************************************************************************
     164                 :            : {
     165         [ +  - ]:     103307 :   std::fill( begin(r), end(r), 0.0 );
     166                 :            : 
     167         [ +  + ]:   37625056 :   for (std::size_t i=0; i<rnz.size()*ncomp; ++i) {
     168         [ +  + ]:  408220046 :     for (std::size_t j=ia[i]-1; j<ia[i+1]-1; ++j) {
     169                 :  370698297 :       r[i] += a[j] * x[ja[j]-1];
     170                 :            :     }
     171                 :            :   }
     172                 :     103307 : }
     173                 :            : 
     174                 :            : void
     175                 :         40 : CSR::zero()
     176                 :            : // *****************************************************************************
     177                 :            : //  Zero matrix values
     178                 :            : // *****************************************************************************
     179                 :            : {
     180         [ +  - ]:         40 :   std::fill( begin(a), end(a), 0.0 );
     181                 :         40 : }
     182                 :            : 
     183                 :            : std::ostream&
     184                 :          1 : CSR::write_stored( std::ostream& os ) const
     185                 :            : // *****************************************************************************
     186                 :            : //  Write out CSR as stored
     187                 :            : //! \param[in,out] os Output stream to write to
     188                 :            : //! \return Updated output stream
     189                 :            : // *****************************************************************************
     190                 :            : {
     191                 :          1 :   os << "size (npoin) = " << rnz.size() << '\n';
     192                 :          1 :   os << "ncomp = " << ncomp << '\n';
     193                 :          1 :   os << "rsize (size*ncomp) = " << rnz.size() * ncomp << '\n';
     194                 :          1 :   os << "nnz = " << a.size() << '\n';
     195                 :            : 
     196                 :            :   std::size_t i;
     197                 :            : 
     198                 :          1 :   os << "rnz[npoin=" << rnz.size() << "] = { ";
     199         [ +  + ]:         14 :   for (i=0; i<rnz.size()-1; ++i) os << rnz[i] << ", ";
     200                 :          1 :   os << rnz[i] << " }\n";
     201                 :            : 
     202                 :          1 :   os << "ia[rsize+1=" << rnz.size()*ncomp+1 << "] = { ";
     203         [ +  + ]:         15 :   for (i=0; i<ia.size()-1; ++i) os << ia[i] << ", ";
     204                 :          1 :   os << ia[i] << " }\n";
     205                 :            : 
     206                 :          1 :   os << "ja[nnz=" << ja.size() << "] = { ";
     207         [ +  + ]:        112 :   for (i=0; i<ja.size()-1; ++i) os << ja[i] << ", ";
     208                 :          1 :   os << ja[i] << " }\n";
     209                 :            : 
     210                 :          1 :   os << "a[nnz=" << a.size() << "] = { ";
     211         [ +  + ]:        112 :   for (i=0; i<a.size()-1; ++i) os << a[i] << ", ";
     212                 :          1 :   os << a[i] << " }\n";
     213                 :            : 
     214                 :          1 :   return os;
     215                 :            : }
     216                 :            : 
     217                 :            : std::ostream&
     218                 :          1 : CSR::write_structure( std::ostream& os ) const
     219                 :            : // *****************************************************************************
     220                 :            : //  Write out CSR nonzero structure
     221                 :            : //! \param[in,out] os Output stream to write to
     222                 :            : //! \return Updated output stream
     223                 :            : // *****************************************************************************
     224                 :            : {
     225         [ +  + ]:         15 :   for (std::size_t i=0; i<rnz.size()*ncomp; ++i) {
     226                 :            :     // leading zeros
     227         [ +  + ]:         28 :     for (std::size_t j=1; j<ja[ia[i]-1]; ++j) os << ". ";
     228         [ +  + ]:        126 :     for (std::size_t n=ia[i]-1; n<ia[i+1]-1; ++n) {
     229                 :            :       // zeros between nonzeros
     230 [ +  + ][ +  + ]:        176 :       if (n>ia[i]-1) for (std::size_t j=ja[n-1]; j<ja[n]-1; ++j) os << ". ";
     231                 :            :       // nonzero
     232                 :        112 :       os << "o ";
     233                 :            :     }
     234                 :            :     // trailing zeros
     235         [ +  + ]:         20 :     for (std::size_t j=ja[ia[i+1]-2]; j<rnz.size()*ncomp; ++j) os << ". ";
     236                 :         14 :     os << '\n';
     237                 :            :   }
     238                 :            : 
     239                 :          1 :   return os;
     240                 :            : }
     241                 :            : 
     242                 :            : std::ostream&
     243                 :          1 : CSR::write_matrix( std::ostream& os ) const
     244                 :            : // *****************************************************************************
     245                 :            : //  Write out CSR as a real matrix
     246                 :            : //! \param[in,out] os Output stream to write to
     247                 :            : //! \return Updated output stream
     248                 :            : // *****************************************************************************
     249                 :            : {
     250         [ +  + ]:         15 :   for (std::size_t i=0; i<rnz.size()*ncomp; ++i) {
     251         [ +  + ]:         28 :     for (std::size_t j=1; j<ja[ia[i]-1]; ++j) os << "0\t";
     252         [ +  + ]:        126 :     for (std::size_t n=ia[i]-1; n<ia[i+1]-1; ++n) {
     253 [ +  + ][ +  + ]:        176 :       if (n>ia[i]-1) for (std::size_t j=ja[n-1]; j<ja[n]-1; ++j ) os << "0\t";
     254                 :        112 :       os << a[n] << '\t';
     255                 :            :     }
     256         [ +  + ]:         20 :     for (std::size_t j=ja[ia[i+1]-2]; j<rnz.size()*ncomp; ++j) os << "0\t";
     257                 :         14 :     os << '\n';
     258                 :            :   }
     259                 :            : 
     260                 :          1 :   return os;
     261                 :            : }
     262                 :            : 
     263                 :            : std::ostream&
     264                 :          1 : CSR::write_matlab( std::ostream& os ) const
     265                 :            : // *****************************************************************************
     266                 :            : //  Write out CSR in Matlab/Octave format
     267                 :            : //! \param[in,out] os Output stream to write to
     268                 :            : //! \return Updated output stream
     269                 :            : // *****************************************************************************
     270                 :            : {
     271                 :          1 :   os << "A = [ ";
     272         [ +  + ]:         15 :   for (std::size_t i=0; i<rnz.size()*ncomp; ++i) {
     273         [ +  + ]:         28 :     for (std::size_t j=1; j<ja[ia[i]-1]; ++j) os << "0 ";
     274         [ +  + ]:        126 :     for ( std::size_t n=ia[i]-1; n<ia[i+1]-1; ++n) {
     275         [ +  + ]:        112 :       if (n > ia[i]-1)
     276         [ +  + ]:        162 :         for (std::size_t j=ja[n-1]; j<ja[n]-1; ++j) os << "0 ";
     277                 :        112 :       os << a[n] << ' ';
     278                 :            :     }
     279         [ +  + ]:         20 :     for (std::size_t j=ja[ia[i+1]-2]; j<rnz.size()*ncomp; ++j) os << "0 ";
     280                 :         14 :     os << ";\n";
     281                 :            :   }
     282                 :          1 :   os << "]\n";
     283                 :            : 
     284                 :          1 :   return os;
     285                 :            : }

Generated by: LCOV version 1.16