Quinoa all test code coverage report
Current view: top level - LinearSolver - BiCG.cpp (source / functions) Hit Total Coverage
Commit: -128-NOTFOUND Lines: 0 315 0.0 %
Date: 2025-12-15 14:04:59 Functions: 0 30 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 328 0.0 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/LinearSolver/BiCG.cpp
       4                 :            :   created 2025, Christopher Long
       5                 :            :   \copyright 2012-2015 J. Bakosi,
       6                 :            :              2016-2018 Los Alamos National Security, LLC.,
       7                 :            :              2019-2021 Triad National Security, LLC.
       8                 :            :              All rights reserved. See the LICENSE file for details.
       9                 :            :   \brief     Charm++ chare array for distributed conjugate gradients.
      10                 :            :   \details   Charm++ chare array for asynchronous distributed
      11                 :            :     conjugate gradients linear solver.
      12                 :            :   \see Y. Saad, Iterative Methods for Sparse Linear Systems: Second Edition,
      13                 :            :     ISBN 9780898718003, 2003, Algorithm 6.18, conjugate gradients to solve the
      14                 :            :     linear system A * x = b, reproduced here:
      15                 :            : 
      16                 :            :     Compute r0:=b-A*x0, p0:=r0
      17                 :            :     Pick rhat0 = r0
      18                 :            :     Let rho0 = rhat0^T \dot r0
      19                 :            :     For j=0,1,..., until convergence, do
      20                 :            :       alpha := rho_j / (rhat0, Ap_j)
      21                 :            :       h := x_j + alpha p_j
      22                 :            :       s := r_j - alpha A p_j
      23                 :            :       Exit if s is sufficient
      24                 :            :       t = As
      25                 :            :       w = (t,s)/(t,t)   //replaces beta
      26                 :            : 
      27                 :            :       x_{j+1} := h + ws
      28                 :            :       r_{j+1} := s - wt
      29                 :            :       Exit if r_{j+1} is sufficient
      30                 :            :       rho_{j+1} := (rhat0, r_{j+1})
      31                 :            :       beta := (rho_{j+1}/rho_{j})*(alpha/w)
      32                 :            :       p_{j+1} := r_{j+1} + beta(p_j - wAp_j)
      33                 :            :     end
      34                 :            : 
      35                 :            :   Usage notes and interfaces into BiCG:
      36                 :            :   (1) BiCG::converged() is an accessor used to query for convergence
      37                 :            :   (2) BiCG::init() is a charm entry method that initializes the solver, and
      38                 :            :       returns execution to client code using CkCallback input arg
      39                 :            :   (3) BiCG::solve() actually solves the linear system, and returns execution
      40                 :            :       to client code using CkCallback input arg
      41                 :            :   (4) BiCG::solution() is an accessor to the solution of linear solver
      42                 :            :       CAUTION! solution() is not a ref, so it creates a copy of the entire
      43                 :            :       solution vector
      44                 :            : */
      45                 :            : // *****************************************************************************
      46                 :            : 
      47                 :            : #include <numeric>
      48                 :            : #include <iostream>
      49                 :            : 
      50                 :            : #include "Exception.hpp"
      51                 :            : #include "BiCG.hpp"
      52                 :            : #include "Vector.hpp"
      53                 :            : 
      54                 :            : using tk::BiCG;
      55                 :            : 
      56                 :          0 : BiCG::BiCG(
      57                 :            :   const CSR& A,
      58                 :            :   const std::vector< tk::real >& x,
      59                 :            :   const std::vector< tk::real >& b,
      60                 :            :   const std::vector< std::size_t >& gid,
      61                 :            :   const std::unordered_map< std::size_t, std::size_t >& lid,
      62                 :          0 :   const NodeCommMap& nodecommmap ) :
      63         [ -  - ]:          0 :   m_A( A ),
      64         [ -  - ]:          0 :   m_x( x ),
      65         [ -  - ]:          0 :   m_b( b ),
      66         [ -  - ]:          0 :   m_gid( gid ),
      67                 :            :   m_lid( lid ),
      68                 :            :   m_nodeCommMap( nodecommmap ),
      69         [ -  - ]:          0 :   m_r( m_A.rsize(), 0.0 ),
      70 [ -  - ][ -  - ]:          0 :   m_r0( m_A.rsize(), 0.0 ),
      71         [ -  - ]:          0 :   m_rc(),
      72                 :          0 :   m_nr( 0 ),
      73                 :          0 :   m_bc(),
      74                 :          0 :   m_bcc(),
      75         [ -  - ]:          0 :   m_bcmask( m_A.rsize(), 1.0 ),
      76                 :          0 :   m_nb( 0 ),
      77 [ -  - ][ -  - ]:          0 :   m_p( m_A.rsize(), 0.0 ),
      78 [ -  - ][ -  - ]:          0 :   m_q( m_A.rsize(), 0.0 ),
      79 [ -  - ][ -  - ]:          0 :   m_t( m_A.rsize(), 0.0 ),
      80         [ -  - ]:          0 :   m_qc(),
      81                 :          0 :   m_tc(), //can I reuse this?
      82                 :          0 :   m_nt( 0 ),
      83                 :          0 :   m_nq( 0 ),
      84         [ -  - ]:          0 :   m_initres(),
      85                 :          0 :   m_solved(),
      86                 :          0 :   m_normb( 0.0 ),
      87                 :          0 :   m_it( 0 ),
      88                 :          0 :   m_maxit( 0 ),
      89                 :          0 :   m_rho( 0.0 ),
      90                 :          0 :   m_rho0( 0.0 ),
      91                 :          0 :   m_alpha( 0.0 ),
      92                 :          0 :   m_omega( 0.0 ),
      93                 :          0 :   m_converged( false ),
      94                 :          0 :   m_xc(),
      95                 :          0 :   m_x2c(),
      96                 :          0 :   m_nx( 0 ),
      97 [ -  - ][ -  - ]:          0 :   m_nx2( 0 )
      98                 :            : // *****************************************************************************
      99                 :            : //  Constructor
     100                 :            : //! \param[in] A Left hand side matrix of the linear system to solve in Ax=b
     101                 :            : //! \param[in] x Solution (initial guess) of the linear system to solve in Ax=b
     102                 :            : //! \param[in] b Right hand side of the linear system to solve in Ax=b
     103                 :            : //! \param[in] gid Global node ids
     104                 :            : //! \param[in] lid Local node ids associated to global ones
     105                 :            : //! \param[in] nodecommmap Global mesh node IDs shared with other chares
     106                 :            : //!   associated to their chare IDs
     107                 :            : // *****************************************************************************
     108                 :            : {
     109                 :            :   // Fill in gid and lid for serial solve
     110 [ -  - ][ -  - ]:          0 :   if (gid.empty() || lid.empty() || nodecommmap.empty()) {
                 [ -  - ]
     111         [ -  - ]:          0 :     m_gid.resize( m_A.rsize()/m_A.Ncomp() );
     112                 :            :     std::iota( begin(m_gid), end(m_gid), 0 );
     113 [ -  - ][ -  - ]:          0 :     for (auto g : m_gid) m_lid[g] = g;
     114                 :            :   }
     115                 :            : 
     116                 :            :   Assert( m_A.rsize() == m_gid.size()*A.Ncomp(), "Size mismatch" );
     117                 :            :   Assert( m_x.size() == m_gid.size()*A.Ncomp(), "Size mismatch" );
     118                 :            :   Assert( m_b.size() == m_gid.size()*A.Ncomp(), "Size mismatch" );
     119                 :          0 : }
     120                 :            : 
     121                 :            : void
     122                 :          0 : BiCG::setup( CkCallback c )
     123                 :            : // *****************************************************************************
     124                 :            : //  Setup solver
     125                 :            : //! \param[in] c Call to continue with after initialization is complete
     126                 :            : //! \details This function initiates computing the residual (r=b-A*x), its dot
     127                 :            : //!   product, and the rhs norm.
     128                 :            : // *****************************************************************************
     129                 :            : {
     130                 :          0 :   m_initres = c;
     131                 :            : 
     132                 :            :   // initiate computing A * x (for the initial residual)
     133         [ -  - ]:          0 :   thisProxy[ thisIndex ].wait4res();
     134                 :          0 :   residual();
     135                 :            : 
     136                 :            :   // initiate computing norm of right hand side
     137         [ -  - ]:          0 :   dot( m_b, m_b,
     138                 :          0 :        CkCallback( CkReductionTarget(BiCG,normb), thisProxy ) );
     139                 :          0 : }
     140                 :            : 
     141                 :            : void
     142                 :          0 : BiCG::dot( const std::vector< tk::real >& a,
     143                 :            :                          const std::vector< tk::real >& b,
     144                 :            :                          CkCallback c )
     145                 :            : // *****************************************************************************
     146                 :            : //  Initiate computation of dot product of two vectors
     147                 :            : //! \param[in] a 1st vector of dot product
     148                 :            : //! \param[in] b 2nd vector of dot product
     149                 :            : //! \param[in] c Callback to target with the final result
     150                 :            : // *****************************************************************************
     151                 :            : {
     152                 :            :   Assert( a.size() == b.size(), "Size mismatch" );
     153                 :            : 
     154                 :          0 :   tk::real D = 0.0;
     155                 :            :   auto ncomp = m_A.Ncomp();
     156         [ -  - ]:          0 :   for (std::size_t i=0; i<a.size()/ncomp; ++i) {
     157                 :          0 :     auto incomp = i*ncomp;
     158         [ -  - ]:          0 :     if (not slave(m_nodeCommMap,m_gid[i],thisIndex))
     159         [ -  - ]:          0 :       for (std::size_t d=0; d<ncomp; ++d)
     160                 :          0 :         D += a[incomp+d] * b[incomp+d];
     161                 :            :   }
     162                 :            : 
     163                 :          0 :   contribute( sizeof(tk::real), &D, CkReduction::sum_double, c );
     164                 :          0 : }
     165                 :            : 
     166                 :            : void
     167                 :          0 : BiCG::normb( tk::real n )
     168                 :            : // *****************************************************************************
     169                 :            : // Compute the norm of the right hand side
     170                 :            : //! \param[in] n Norm of right hand side (aggregated across all chares)
     171                 :            : // *****************************************************************************
     172                 :            : {
     173                 :          0 :   m_normb = std::sqrt(n);
     174                 :          0 :   normb_complete();
     175                 :          0 : }
     176                 :            : 
     177                 :            : void
     178                 :          0 : BiCG::residual()
     179                 :            : // *****************************************************************************
     180                 :            : //  Initiate A * x for computing the initial residual, r = b - A * x
     181                 :            : // *****************************************************************************
     182                 :            : {
     183                 :            :   // Compute own contribution to r = A * x
     184                 :          0 :   m_A.mult( m_x, m_r, m_bcmask );
     185                 :            : 
     186                 :            :   // Send partial product on chare-boundary nodes to fellow chares
     187         [ -  - ]:          0 :   if (m_nodeCommMap.empty()) {
     188                 :          0 :     comres_complete();
     189                 :            :   } else {
     190                 :            :     auto ncomp = m_A.Ncomp();
     191         [ -  - ]:          0 :     for (const auto& [c,n] : m_nodeCommMap) {
     192                 :          0 :       std::vector< std::vector< tk::real > > rc( n.size() );
     193                 :            :       std::size_t j = 0;
     194         [ -  - ]:          0 :       for (auto g : n) {
     195         [ -  - ]:          0 :         std::vector< tk::real > nr( ncomp );
     196                 :          0 :         auto i = tk::cref_find( m_lid, g );
     197         [ -  - ]:          0 :         for (std::size_t d=0; d<ncomp; ++d) nr[d] = m_r[ i*ncomp+d ];
     198                 :          0 :         rc[j++] = std::move(nr);
     199                 :            :       }
     200 [ -  - ][ -  - ]:          0 :       thisProxy[c].comres( std::vector<std::size_t>(begin(n),end(n)), rc );
         [ -  - ][ -  - ]
                 [ -  - ]
     201                 :          0 :     }
     202                 :            :   }
     203                 :            : 
     204                 :          0 :   ownres_complete();
     205                 :          0 : }
     206                 :            : 
     207                 :            : void
     208                 :          0 : BiCG::comres( const std::vector< std::size_t >& gid,
     209                 :            :                             const std::vector< std::vector< tk::real > >& rc )
     210                 :            : // *****************************************************************************
     211                 :            : //  Receive contributions to A * x on chare-boundaries
     212                 :            : //! \param[in] gid Global mesh node IDs at which we receive contributions
     213                 :            : //! \param[in] rc Partial contributions at chare-boundary nodes
     214                 :            : // *****************************************************************************
     215                 :            : {
     216                 :            :   Assert( rc.size() == gid.size(), "Size mismatch" );
     217                 :            : 
     218                 :            :   using tk::operator+=;
     219                 :            : 
     220         [ -  - ]:          0 :   for (std::size_t i=0; i<gid.size(); ++i)
     221                 :          0 :     m_rc[ gid[i] ] += rc[i];
     222                 :            : 
     223         [ -  - ]:          0 :   if (++m_nr == m_nodeCommMap.size()) {
     224                 :          0 :     m_nr = 0;
     225                 :          0 :     comres_complete();
     226                 :            :   }
     227                 :          0 : }
     228                 :            : 
     229                 :            : void
     230                 :          0 : BiCG::initres()
     231                 :            : // *****************************************************************************
     232                 :            : // Finish computing the initial residual, r = b - A * x
     233                 :            : // *****************************************************************************
     234                 :            : {
     235                 :            :   // Combine own and communicated contributions to r = A * x
     236                 :            :   auto ncomp = m_A.Ncomp();
     237         [ -  - ]:          0 :   for (const auto& [gid,r] : m_rc) {
     238                 :          0 :     auto i = tk::cref_find( m_lid, gid );
     239         [ -  - ]:          0 :     for (std::size_t c=0; c<ncomp; ++c) m_r[i*ncomp+c] += r[c];
     240                 :            :   }
     241                 :          0 :   tk::destroy( m_rc );
     242                 :            : 
     243                 :            :   // Finish computing the initial residual, r = b - A * x
     244         [ -  - ]:          0 :   for (auto& r : m_r) r *= -1.0;
     245                 :          0 :   m_r += m_b;
     246                 :            : 
     247                 :            :   // Initialize p
     248                 :          0 :   m_p = m_r;
     249                 :            :   //Initialize r0
     250                 :          0 :   m_r0 = m_r;
     251                 :            :   // initiate computing the dot product of the initial residual, rho = (r,r)
     252         [ -  - ]:          0 :   dot( m_r0, m_r,
     253                 :          0 :        CkCallback( CkReductionTarget(BiCG,rho), thisProxy ) );
     254                 :          0 : }
     255                 :            : 
     256                 :            : void
     257                 :          0 : BiCG::rho( tk::real r )
     258                 :            : // *****************************************************************************
     259                 :            : // Compute rho = (r,r)
     260                 :            : //! \param[in] r Dot product, rho = (r,r) (aggregated across all chares)
     261                 :            : // *****************************************************************************
     262                 :            : {
     263                 :            :   // store dot product of residual
     264                 :          0 :   m_rho = r;
     265                 :            : 
     266                 :            :   // send back rhs norm to caller
     267                 :          0 :   m_initres.send( CkDataMsg::buildNew( sizeof(tk::real), &m_normb ) );
     268                 :          0 : }
     269                 :            : 
     270                 :            : void
     271         [ -  - ]:          0 : BiCG::init(
     272                 :            :   const std::vector< tk::real >& x,
     273                 :            :   const std::vector< tk::real >& b,
     274                 :            :   const std::unordered_map< std::size_t,
     275                 :            :           std::vector< std::pair< bool, tk::real > > >& bc,
     276                 :            :   std::size_t ignorebc,
     277                 :            :   CkCallback cb )
     278                 :            : // *****************************************************************************
     279                 :            : //  Initialize linear solve: set initial guess and boundary conditions
     280                 :            : //! \param[in] x Initial guess
     281                 :            : //! \param[in] b Right hand side vector
     282                 :            : //! \param[in] bc Local node ids and associated Dirichlet BCs
     283                 :            : //! \param[in] ignorebc True if applyin BCs should be skipped
     284                 :            : //! \param[in] cb Call to continue with when initialized and ready for a solve
     285                 :            : //! \details This function allows setting the initial guess and boundary
     286                 :            : //!   conditions, followed by computing the initial residual and the rhs norm.
     287                 :            : // *****************************************************************************
     288                 :            : {
     289                 :            :   // Optionally set initial guess
     290         [ -  - ]:          0 :   if (not x.empty()) m_x = x;
     291                 :            : 
     292                 :            :   // Optionally update rhs
     293         [ -  - ]:          0 :   if (not b.empty()) m_b = b;
     294                 :            : 
     295         [ -  - ]:          0 :   if (ignorebc) {
     296                 :            : 
     297         [ -  - ]:          0 :     setup( cb );
     298                 :            : 
     299                 :            :   } else {
     300                 :            : 
     301                 :            :     // Store incoming BCs
     302                 :            :     m_bc = bc;
     303                 :            : 
     304                 :            :     // Get ready to communicate boundary conditions. This is necessary because
     305                 :            :     // there can be nodes a chare contributes to but does not apply BCs on. This
     306                 :            :     // happens if a node is in the node communication map but not on the list of
     307                 :            :     // incoming BCs on this chare. To have all chares share the same view on all
     308                 :            :     // BC nodes, we send the global node ids together with the Dirichlet BCs at
     309                 :            :     // which BCs are set to those fellow chares that also contribute to those BC
     310                 :            :     // nodes. Only after this communication step we apply the BCs on the matrix,
     311                 :            :     // which then will correctly setup the BC rows that exist on multiple chares
     312                 :            :     // (which now will be the same as the results of making the BCs consistent
     313                 :            :     // across all chares that contribute.
     314 [ -  - ][ -  - ]:          0 :     thisProxy[ thisIndex ].wait4bc();
     315                 :            : 
     316                 :            :     // Send boundary conditions to those who contribute to those rows
     317         [ -  - ]:          0 :     if (m_nodeCommMap.empty()) {
     318                 :          0 :       combc_complete();
     319                 :            :     } else {
     320         [ -  - ]:          0 :       for (const auto& [c,n] : m_nodeCommMap) {
     321                 :            :         std::unordered_map< std::size_t,
     322                 :            :           std::vector< std::pair< bool, tk::real > > > expbc;
     323 [ -  - ][ -  - ]:          0 :         for (auto g : n) {
     324                 :          0 :           auto i = tk::cref_find( m_lid, g );
     325                 :            :           auto j = bc.find(i);
     326 [ -  - ][ -  - ]:          0 :           if (j != end(bc)) expbc[g] = j->second;
                 [ -  - ]
     327                 :            :         }
     328 [ -  - ][ -  - ]:          0 :         thisProxy[c].combc( expbc );
     329                 :            :       }
     330                 :            :     }
     331                 :            : 
     332         [ -  - ]:          0 :     ownbc_complete( cb );
     333                 :            : 
     334                 :            :   }
     335                 :          0 : }
     336                 :            : 
     337                 :            : void
     338                 :          0 : BiCG::combc(
     339                 :            :   const std::unordered_map< std::size_t,
     340                 :            :      std::vector< std::pair< bool, tk::real > > >& bc )
     341                 :            : // *****************************************************************************
     342                 :            : //  Receive contributions to boundary conditions on chare-boundaries
     343                 :            : //! \param[in] bc Contributions to boundary conditions
     344                 :            : // *****************************************************************************
     345                 :            : {
     346         [ -  - ]:          0 :   for (const auto& [g,dirbc] : bc) m_bcc[ tk::cref_find(m_lid,g) ] = dirbc;
     347                 :            : 
     348         [ -  - ]:          0 :   if (++m_nb == m_nodeCommMap.size()) {
     349                 :          0 :     m_nb = 0;
     350                 :          0 :     combc_complete();
     351                 :            :   }
     352                 :          0 : }
     353                 :            : 
     354                 :            : void
     355                 :          0 : BiCG::apply( CkCallback cb )
     356                 :            : // *****************************************************************************
     357                 :            : //  Apply boundary conditions
     358                 :            : //! \param[in] cb Call to continue with after applying the BCs is complete
     359                 :            : // *****************************************************************************
     360                 :            : {
     361                 :            :   // Merge own and received contributions to boundary conditions
     362         [ -  - ]:          0 :   for (const auto& [i,dirbc] : m_bcc) m_bc[i] = dirbc;
     363                 :          0 :   tk::destroy( m_bcc );
     364                 :            : 
     365                 :            :   auto ncomp = m_A.Ncomp();
     366                 :            : 
     367                 :            :   // Setup Dirichlet BC map as contiguous mask
     368         [ -  - ]:          0 :   for (const auto& [i,bc] : m_bc)
     369         [ -  - ]:          0 :     for (std::size_t j=0; j<ncomp; ++j)
     370                 :          0 :       m_bcmask[i*ncomp+j] = 0.0;
     371                 :            : 
     372                 :            :   // Apply Dirichlet BCs on matrix and rhs
     373         [ -  - ]:          0 :   for (const auto& [i,dirbc] : m_bc) {
     374         [ -  - ]:          0 :     for (std::size_t j=0; j<ncomp; ++j) {
     375         [ -  - ]:          0 :       if (dirbc[j].first) {
     376                 :          0 :         m_A.dirichlet( i, m_gid, m_nodeCommMap, j );
     377                 :          0 :         m_b[i*ncomp+j] = dirbc[j].second;
     378                 :            :       }
     379                 :            :     }
     380                 :            :   }
     381                 :            : 
     382                 :            :   // Recompute initial residual (r=b-A*x), its dot product, and the rhs norm
     383         [ -  - ]:          0 :   setup( cb );
     384                 :          0 : }
     385                 :            : 
     386                 :            : void
     387                 :          0 : BiCG::solve( std::size_t maxit, tk::real tol, CkCallback c )
     388                 :            : // *****************************************************************************
     389                 :            : //  Solve linear system
     390                 :            : //! \param[in] maxit Max iteration count
     391                 :            : //! \param[in] tol Stop tolerance
     392                 :            : //! \param[in] c Call to continue with after solve is complete
     393                 :            : // *****************************************************************************
     394                 :            : {
     395                 :          0 :   m_maxit = maxit;
     396                 :          0 :   m_tol = tol;
     397                 :          0 :   m_solved = c;
     398                 :          0 :   m_it = 0;
     399                 :            : 
     400                 :          0 :   next();
     401                 :          0 : }
     402                 :            : 
     403                 :            : void
     404                 :          0 : BiCG::next()
     405                 :            : // *****************************************************************************
     406                 :            : //  Start next linear solver iteration
     407                 :            : // *****************************************************************************
     408                 :            : {
     409         [ -  - ]:          0 :   if (m_it == 0) {
     410                 :          0 :      m_alpha = 0.0;
     411                 :          0 :      m_omega=0.0;
     412                 :            : 
     413                 :            :   }else{
     414                 :          0 :      m_alpha =( m_rho/m_rho0 ) * ( m_alpha/m_omega ) ; //alpha functions as Beta??
     415                 :            :   }
     416                 :          0 :   m_rho0 = m_rho;
     417                 :            : 
     418                 :            :   // compute p = r + alpha * p
     419         [ -  - ]:          0 :   for (std::size_t i=0; i<m_p.size(); ++i) m_p[i] = m_r[i] + m_alpha * ( m_p[i] - m_omega * m_q[i] );
     420                 :            : 
     421                 :            :   // initiate computing q = A * p
     422         [ -  - ]:          0 :   thisProxy[ thisIndex ].wait4q();
     423                 :          0 :   qAp();
     424                 :          0 : }
     425                 :            : 
     426                 :            : void
     427                 :          0 : BiCG::qAp()
     428                 :            : // *****************************************************************************
     429                 :            : //  Initiate computing q = A * p
     430                 :            : // *****************************************************************************
     431                 :            : {
     432                 :            :   // Compute own contribution to q = A * p
     433                 :          0 :   m_A.mult( m_p, m_q, m_bcmask );
     434                 :            : 
     435                 :            :   // Send partial product on chare-boundary nodes to fellow chares
     436         [ -  - ]:          0 :   if (m_nodeCommMap.empty()) {
     437                 :          0 :     comq_complete();
     438                 :            :   } else {
     439                 :            :     auto ncomp = m_A.Ncomp();
     440         [ -  - ]:          0 :     for (const auto& [c,n] : m_nodeCommMap) {
     441                 :          0 :       std::vector< std::vector< tk::real > > qc( n.size() );
     442                 :            :       std::size_t j = 0;
     443         [ -  - ]:          0 :       for (auto g : n) {
     444         [ -  - ]:          0 :         std::vector< tk::real > nq( ncomp );
     445                 :          0 :         auto i = tk::cref_find( m_lid, g );
     446         [ -  - ]:          0 :         for (std::size_t d=0; d<ncomp; ++d) nq[d] = m_q[ i*ncomp+d ];
     447                 :          0 :         qc[j++] = std::move(nq);
     448                 :            :       }
     449 [ -  - ][ -  - ]:          0 :       thisProxy[c].comq( std::vector<std::size_t>(begin(n),end(n)), qc );
         [ -  - ][ -  - ]
                 [ -  - ]
     450                 :          0 :     }
     451                 :            :   }
     452                 :            : 
     453                 :          0 :   ownq_complete();
     454                 :          0 : }
     455                 :            : 
     456                 :            : void
     457                 :          0 : BiCG::comq( const std::vector< std::size_t >& gid,
     458                 :            :                           const std::vector< std::vector< tk::real > >& qc )
     459                 :            : // *****************************************************************************
     460                 :            : //  Receive contributions to q = A * p on chare-boundaries
     461                 :            : //! \param[in] gid Global mesh node IDs at which we receive contributions
     462                 :            : //! \param[in] qc Partial contributions at chare-boundary nodes
     463                 :            : // *****************************************************************************
     464                 :            : {
     465                 :            :   Assert( qc.size() == gid.size(), "Size mismatch" );
     466                 :            : 
     467                 :            :   using tk::operator+=;
     468                 :            : 
     469         [ -  - ]:          0 :   for (std::size_t i=0; i<gid.size(); ++i)
     470                 :          0 :     m_qc[ gid[i] ] += qc[i];
     471                 :            : 
     472         [ -  - ]:          0 :   if (++m_nq == m_nodeCommMap.size()) {
     473                 :          0 :     m_nq = 0;
     474                 :          0 :     comq_complete();
     475                 :            :   }
     476                 :          0 : }
     477                 :            : 
     478                 :            : void
     479                 :          0 : BiCG::q()
     480                 :            : // *****************************************************************************
     481                 :            : // Finish computing q = A * p
     482                 :            : // *****************************************************************************
     483                 :            : {
     484                 :            :   // Combine own and communicated contributions to q = A * p
     485                 :            :   auto ncomp = m_A.Ncomp();
     486         [ -  - ]:          0 :   for (const auto& [gid,q] : m_qc) {
     487                 :          0 :     auto i = tk::cref_find( m_lid, gid );
     488         [ -  - ]:          0 :     for (std::size_t c=0; c<ncomp; ++c)
     489                 :          0 :       m_q[i*ncomp+c] += q[c];
     490                 :            :   }
     491                 :          0 :   tk::destroy( m_qc );
     492                 :            : 
     493                 :            :   //BiCGStab uses (rhat_0,q), initiate here
     494         [ -  - ]:          0 :   dot( m_r0, m_q,
     495                 :          0 :        CkCallback( CkReductionTarget(BiCG,pq), thisProxy ) );
     496                 :          0 : }
     497                 :            : 
     498                 :            : void
     499         [ -  - ]:          0 : BiCG::pq( tk::real d )
     500                 :            : // *****************************************************************************
     501                 :            : // Compute the dot product (p,q)
     502                 :            : //! \param[in] d Dot product of (p,q) (aggregated across all chares)
     503                 :            : // *****************************************************************************
     504                 :            : {
     505                 :            :   // If (p,q)=0, then p and q are orthogonal and the system either has a trivial
     506                 :            :   // solution, x=x0, or the BCs are incomplete or wrong, in either case the
     507                 :            :   // solve cannot continue.
     508                 :            :   // sod_pe4 DOES have a trivial solution, yet we are using it for a test case...
     509                 :            :   // we have to tolerate small eps values and rely on the numerator also being small.
     510                 :            :   // We should generally allow for the mesh to stay still though, so need to think about this some.
     511                 :            :   const auto eps = std::numeric_limits< tk::real >::epsilon();
     512         [ -  - ]:          0 :   if (std::abs(d) < eps) {
     513         [ -  - ]:          0 :     if ( m_it > 0) {
     514                 :          0 :       m_alpha = m_rho / d;
     515                 :            :     } else {
     516                 :          0 :       m_it = m_maxit;
     517                 :          0 :       m_alpha = 0.0;
     518                 :            :     }
     519                 :            :   } else {
     520                 :          0 :     m_alpha = m_rho / d;
     521                 :            :   }
     522                 :            : 
     523                 :            :   // compute s = r - alpha * q
     524         [ -  - ]:          0 :   for (std::size_t i=0; i<m_r.size(); ++i) m_r[i] -= m_alpha * m_q[i];
     525                 :            : 
     526                 :            :   // initiate computing norm of residual: (r,r)
     527         [ -  - ]:          0 :   dot( m_r, m_r,
     528                 :          0 :        CkCallback( CkReductionTarget(BiCG,normres), thisProxy ) );
     529                 :          0 : }
     530                 :            : 
     531                 :            : void
     532                 :          0 : BiCG::normres( tk::real r )
     533                 :            : // *****************************************************************************
     534                 :            : // Compute norm of residual: (r,r)
     535                 :            : //! \param[in] r Dot product, (r,r) (aggregated across all chares)
     536                 :            : // *****************************************************************************
     537                 :            : {
     538                 :          0 :   m_rho = r;
     539                 :            : 
     540                 :            :   // Advance solution: h = x + alpha * p
     541         [ -  - ]:          0 :   for (std::size_t i=0; i<m_x.size(); ++i) m_x[i] += m_alpha * m_p[i];
     542                 :            : 
     543                 :            :   // Communicate solution
     544 [ -  - ][ -  - ]:          0 :   thisProxy[ thisIndex ].wait4x();
     545                 :            : 
     546                 :            :   // Send solution on chare-boundary nodes to fellow chares
     547         [ -  - ]:          0 :   if (m_nodeCommMap.empty()) {
     548                 :          0 :     comx_complete();
     549                 :            :   } else {
     550                 :            :     auto ncomp = m_A.Ncomp();
     551         [ -  - ]:          0 :     for (const auto& [c,n] : m_nodeCommMap) {
     552                 :          0 :       std::vector< std::vector< tk::real > > xc( n.size() );
     553                 :            :       std::size_t j = 0;
     554         [ -  - ]:          0 :       for (auto g : n) {
     555         [ -  - ]:          0 :         std::vector< tk::real > nx( ncomp );
     556                 :          0 :         auto i = tk::cref_find( m_lid, g );
     557         [ -  - ]:          0 :         for (std::size_t d=0; d<ncomp; ++d) nx[d] = m_x[ i*ncomp+d ];
     558                 :          0 :         xc[j++] = std::move(nx);
     559                 :            :       }
     560 [ -  - ][ -  - ]:          0 :       thisProxy[c].comx( std::vector<std::size_t>(begin(n),end(n)), xc );
         [ -  - ][ -  - ]
                 [ -  - ]
     561                 :          0 :     }
     562                 :            :   }
     563                 :            : 
     564                 :          0 :   ownx_complete();
     565                 :          0 : }
     566                 :            : 
     567                 :            : void
     568                 :          0 : BiCG::comx( const std::vector< std::size_t >& gid,
     569                 :            :                           const std::vector< std::vector< tk::real > >& xc )
     570                 :            : // *****************************************************************************
     571                 :            : //  Receive contributions to final solution on chare-boundaries
     572                 :            : //! \param[in] gid Global mesh node IDs at which we receive contributions
     573                 :            : //! \param[in] xc Partial contributions at chare-boundary nodes
     574                 :            : // *****************************************************************************
     575                 :            : {
     576                 :            :   Assert( xc.size() == gid.size(), "Size mismatch" );
     577                 :            : 
     578         [ -  - ]:          0 :   for (std::size_t i=0; i<gid.size(); ++i) m_xc[ gid[i] ] += xc[i];
     579                 :            : 
     580         [ -  - ]:          0 :   if (++m_nx == m_nodeCommMap.size()) {
     581                 :          0 :     m_nx = 0;
     582                 :          0 :     comx_complete();
     583                 :            :   }
     584                 :          0 : }
     585                 :            : 
     586                 :            : void
     587                 :          0 : BiCG::x()
     588                 :            : // *****************************************************************************
     589                 :            : // Assemble solution on chare boundaries
     590                 :            : // *****************************************************************************
     591                 :            : {
     592                 :            :   // Assemble solution on chare boundaries by averaging
     593                 :            :   auto ncomp = m_A.Ncomp();
     594         [ -  - ]:          0 :   for (const auto& [g,x] : m_xc) {
     595                 :          0 :     auto i = tk::cref_find(m_lid,g);
     596         [ -  - ]:          0 :     for (std::size_t d=0; d<ncomp; ++d) m_x[i*ncomp+d] += x[d];
     597                 :          0 :     auto c = tk::count(m_nodeCommMap,g);
     598         [ -  - ]:          0 :     for (std::size_t d=0; d<ncomp; ++d) m_x[i*ncomp+d] /= c;
     599                 :            :   }
     600                 :          0 :   tk::destroy( m_xc );
     601                 :            : 
     602                 :            :   //Don't iterate counter yet!
     603         [ -  - ]:          0 :   auto normb = m_normb > 1.0e-14 ? m_normb : 1.0;
     604                 :          0 :   auto normr = std::sqrt( m_rho );
     605 [ -  - ][ -  - ]:          0 :   if ( m_it < m_maxit && normr > m_tol*normb ) { //If we are not solved, continue, else exit
     606                 :            :                                                  //Here is where we significantly diverge from regular CG as we dont' go to "next()" yet
     607                 :            :   // initiate computing t = A * s  ;
     608                 :            : 
     609         [ -  - ]:          0 :     thisProxy[ thisIndex ].wait4t();
     610                 :          0 :     tAs();
     611                 :            : 
     612                 :            :   } else {
     613                 :            : 
     614 [ -  - ][ -  - ]:          0 :     m_converged = m_it == m_maxit && normr > m_tol*normb ? false : true;
     615                 :          0 :     m_solved.send( CkDataMsg::buildNew( sizeof(tk::real), &normr ) );
     616                 :            : 
     617                 :            :   }
     618                 :          0 : }
     619                 :            : 
     620                 :            : void
     621                 :          0 : BiCG::tAs()
     622                 :            : // *****************************************************************************
     623                 :            : //  Initiate computing t = A * s
     624                 :            : // *****************************************************************************
     625                 :            : {
     626                 :            :   // Compute own contribution to t = A * s
     627                 :          0 :   m_A.mult( m_r, m_t, m_bcmask );
     628                 :            : 
     629                 :            :   // Send partial product on chare-boundary nodes to fellow chares
     630         [ -  - ]:          0 :   if (m_nodeCommMap.empty()) {
     631                 :          0 :     comt_complete();
     632                 :            :   } else {
     633                 :            :     auto ncomp = m_A.Ncomp();
     634         [ -  - ]:          0 :     for (const auto& [c,n] : m_nodeCommMap) {
     635                 :          0 :       std::vector< std::vector< tk::real > > tc( n.size() );
     636                 :            :       std::size_t j = 0;
     637         [ -  - ]:          0 :       for (auto g : n) {
     638         [ -  - ]:          0 :         std::vector< tk::real > nt( ncomp );
     639                 :          0 :         auto i = tk::cref_find( m_lid, g );
     640         [ -  - ]:          0 :         for (std::size_t d=0; d<ncomp; ++d) nt[d] = m_t[ i*ncomp+d ];
     641                 :          0 :         tc[j++] = std::move(nt);
     642                 :            :       }
     643 [ -  - ][ -  - ]:          0 :       thisProxy[c].comt( std::vector<std::size_t>(begin(n),end(n)), tc );
         [ -  - ][ -  - ]
                 [ -  - ]
     644                 :          0 :     }
     645                 :            :   }
     646                 :            : 
     647                 :          0 :   ownt_complete();
     648                 :          0 : }
     649                 :            : 
     650                 :            : void
     651                 :          0 : BiCG::comt( const std::vector< std::size_t >& gid,
     652                 :            :                           const std::vector< std::vector< tk::real > >& tc )
     653                 :            : // *****************************************************************************
     654                 :            : //  Receive contributions to t = A * s on chare-boundaries
     655                 :            : //! \param[in] gid Global mesh node IDs at which we receive contributions
     656                 :            : //! \param[in] tc Partial contributions at chare-boundary nodes
     657                 :            : // *****************************************************************************
     658                 :            : {
     659                 :            :   Assert( tc.size() == gid.size(), "Size mismatch" );
     660                 :            : 
     661                 :            :   using tk::operator+=;
     662                 :            : 
     663         [ -  - ]:          0 :   for (std::size_t i=0; i<gid.size(); ++i)
     664                 :          0 :     m_tc[ gid[i] ] += tc[i];
     665                 :            : 
     666         [ -  - ]:          0 :   if (++m_nt == m_nodeCommMap.size()) {
     667                 :          0 :     m_nt = 0;
     668                 :          0 :     comt_complete();
     669                 :            :   }
     670                 :          0 : }
     671                 :            : 
     672                 :            : 
     673                 :            : void
     674                 :          0 : BiCG::t()
     675                 :            : // *****************************************************************************
     676                 :            : // Finish computing t = A * s
     677                 :            : // *****************************************************************************
     678                 :            : {
     679                 :            :   // Combine own and communicated contributions to t = A * s
     680                 :            :   auto ncomp = m_A.Ncomp();
     681         [ -  - ]:          0 :   for (const auto& [gid,t] : m_tc) {
     682                 :          0 :     auto i = tk::cref_find( m_lid, gid );
     683         [ -  - ]:          0 :     for (std::size_t c=0; c<ncomp; ++c)
     684                 :          0 :       m_t[i*ncomp+c] += t[c];
     685                 :            :   }
     686                 :          0 :   tk::destroy( m_tc );
     687                 :            : 
     688                 :            :   //omega = (t,s)/(t,t).  Compute numerator
     689         [ -  - ]:          0 :   dot( m_t, m_r,
     690                 :          0 :        CkCallback( CkReductionTarget(BiCG,ts), thisProxy ) );
     691                 :          0 : }
     692                 :            : void
     693                 :          0 : BiCG::ts( tk::real d )
     694                 :            : // *****************************************************************************
     695                 :            : // Compute the dot product (t,s)
     696                 :            : //! \param[in] d Dot product of (t,s) (aggregated across all chares)
     697                 :            : // *****************************************************************************
     698                 :            : {
     699                 :            : 
     700                 :          0 :   m_omega = d; //numerator set
     701                 :            : 
     702         [ -  - ]:          0 :   dot( m_t, m_t, //compute denominator
     703                 :          0 :        CkCallback( CkReductionTarget(BiCG,tt), thisProxy ) );
     704                 :            : 
     705                 :          0 : }
     706                 :            : void
     707         [ -  - ]:          0 : BiCG::tt( tk::real d )
     708                 :            : // *****************************************************************************
     709                 :            : // Compute the dot product (t,t)
     710                 :            : //! \param[in] d Dot product of (t,t) (aggregated across all chares)
     711                 :            : // *****************************************************************************
     712                 :            : {
     713                 :            :   // If (t,t)=0, then p and q are orthogonal and the system either has a trivial
     714                 :            :   // solution, x=x0, or the BCs are incomplete or wrong, in either case the
     715                 :            :   // solve cannot continue.
     716                 :            :   const auto eps = std::numeric_limits< tk::real >::epsilon();
     717 [ -  - ][ -  - ]:          0 :   if (std::abs(d) < eps && std::abs(m_omega) > 1000*eps) { //Unsure how to check for smallness here since m_omega may also be very small
     718                 :            :     //m_it = m_maxit;
     719                 :          0 :     m_omega = m_omega/d; //d is denominator
     720                 :            :     //m_omega = 0.0;
     721                 :            :   }
     722                 :            :   else {
     723                 :          0 :     m_omega = m_omega/d; //d is denominator
     724                 :            :   }
     725                 :            :   //compute x = h + omega * s
     726         [ -  - ]:          0 :   for (std::size_t i=0; i<m_x.size(); ++i) m_x[i] += m_omega * m_r[i];
     727                 :            :   // Now update r:  compute r = s - omega * t
     728         [ -  - ]:          0 :   for (std::size_t i=0; i<m_r.size(); ++i) m_r[i] -= m_omega * m_t[i];
     729                 :            :   // initiate computing norm of residual: (r,r) for exit criteria
     730         [ -  - ]:          0 :   dot( m_r, m_r,
     731                 :          0 :        CkCallback( CkReductionTarget(BiCG,normresomega), thisProxy ) );
     732                 :          0 : }
     733                 :            : void
     734                 :          0 : BiCG::normresomega( tk::real r )
     735                 :            : // *****************************************************************************
     736                 :            : // Compute norm of residual: (r,r) for second half of bicgstab
     737                 :            : //! \param[in] r Dot product, (r,r) (aggregated across all chares)
     738                 :            : // *****************************************************************************
     739                 :            : {
     740                 :          0 :   m_rho = r;
     741                 :            : 
     742                 :            :   // Communicate solution
     743 [ -  - ][ -  - ]:          0 :   thisProxy[ thisIndex ].wait4x2();
     744                 :            : 
     745                 :            :   // Send solution on chare-boundary nodes to fellow chares
     746         [ -  - ]:          0 :   if (m_nodeCommMap.empty()) {
     747                 :          0 :     comx2_complete();  //Does this need to be unique?
     748                 :            :   } else {
     749                 :            :     auto ncomp = m_A.Ncomp();
     750         [ -  - ]:          0 :     for (const auto& [c,n] : m_nodeCommMap) {
     751                 :          0 :       std::vector< std::vector< tk::real > > x2c( n.size() );
     752                 :            :       std::size_t j = 0;
     753         [ -  - ]:          0 :       for (auto g : n) {
     754         [ -  - ]:          0 :         std::vector< tk::real > nx2( ncomp );
     755                 :          0 :         auto i = tk::cref_find( m_lid, g );
     756         [ -  - ]:          0 :         for (std::size_t d=0; d<ncomp; ++d) nx2[d] = m_x[ i*ncomp+d ];
     757                 :          0 :         x2c[j++] = std::move(nx2);
     758                 :            :       }
     759 [ -  - ][ -  - ]:          0 :       thisProxy[c].comx2( std::vector<std::size_t>(begin(n),end(n)), x2c );
         [ -  - ][ -  - ]
                 [ -  - ]
     760                 :          0 :     }
     761                 :            :   }
     762                 :            : 
     763                 :          0 :   ownx2_complete();
     764                 :          0 : }
     765                 :            : void
     766                 :          0 : BiCG::x2()
     767                 :            : // *****************************************************************************
     768                 :            : // Assemble solution on chare boundaries
     769                 :            : // *****************************************************************************
     770                 :            : {
     771                 :            :   // Assemble solution on chare boundaries by averaging
     772                 :            :   auto ncomp = m_A.Ncomp();
     773         [ -  - ]:          0 :   for (const auto& [g,x] : m_x2c) {
     774                 :          0 :     auto i = tk::cref_find(m_lid,g);
     775         [ -  - ]:          0 :     for (std::size_t d=0; d<ncomp; ++d) m_x[i*ncomp+d] += x[d];
     776                 :          0 :     auto c = tk::count(m_nodeCommMap,g);
     777         [ -  - ]:          0 :     for (std::size_t d=0; d<ncomp; ++d) m_x[i*ncomp+d] /= c;
     778                 :            :   }
     779                 :          0 :   tk::destroy( m_x2c );
     780                 :            : 
     781                 :          0 :   ++m_it;
     782         [ -  - ]:          0 :   auto normb = m_normb > 1.0e-14 ? m_normb : 1.0;
     783                 :          0 :   auto normr = std::sqrt( m_rho );
     784                 :            : 
     785 [ -  - ][ -  - ]:          0 :   if ( m_it < m_maxit && normr > m_tol*normb ) { //If we are not solved, continue, else exit
     786                 :            :     //get next rho value
     787         [ -  - ]:          0 :     dot( m_r0, m_r,
     788                 :          0 :        CkCallback( CkReductionTarget(BiCG,comprho), thisProxy ) );
     789                 :            : 
     790                 :            :   } else {
     791                 :            : 
     792 [ -  - ][ -  - ]:          0 :     m_converged = m_it == m_maxit && normr > m_tol*normb ? false : true;
     793                 :          0 :     m_solved.send( CkDataMsg::buildNew( sizeof(tk::real), &normr ) );
     794                 :            : 
     795                 :            :   }
     796                 :          0 : }
     797                 :            : 
     798                 :            : void
     799                 :          0 : BiCG::comprho( tk::real r )
     800                 :            : {
     801                 :          0 :   m_rho = r;
     802                 :          0 :   next();
     803                 :          0 : }
     804                 :            : 
     805                 :            : void
     806                 :          0 : BiCG::comx2( const std::vector< std::size_t >& gid,
     807                 :            :                           const std::vector< std::vector< tk::real > >& x2c )
     808                 :            : // *****************************************************************************
     809                 :            : //  Receive contributions to final solution on chare-boundaries
     810                 :            : //! \param[in] gid Global mesh node IDs at which we receive contributions
     811                 :            : //! \param[in] xc Partial contributions at chare-boundary nodes
     812                 :            : // *****************************************************************************
     813                 :            : {
     814                 :            :   Assert( x2c.size() == gid.size(), "Size mismatch" );
     815                 :            : 
     816         [ -  - ]:          0 :   for (std::size_t i=0; i<gid.size(); ++i) m_x2c[ gid[i] ] += x2c[i];
     817                 :            : 
     818         [ -  - ]:          0 :   if (++m_nx2 == m_nodeCommMap.size()) {
     819                 :          0 :     m_nx2 = 0;
     820                 :          0 :     comx2_complete();
     821                 :            :   }
     822                 :          0 : }
     823                 :            : 
     824                 :            : #include "NoWarning/bicg.def.h"

Generated by: LCOV version 1.16