Quinoa regression test code coverage report
Current view: top level - PDE/Transport - CGTransport.hpp (source / functions) Hit Total Coverage
Commit: Quinoa_v0.3-957-gb4f0efae0 Lines: 348 354 98.3 %
Date: 2021-11-11 13:17:06 Functions: 59 270 21.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 235 426 55.2 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/PDE/Transport/CGTransport.hpp
       4                 :            :   \copyright 2012-2015 J. Bakosi,
       5                 :            :              2016-2018 Los Alamos National Security, LLC.,
       6                 :            :              2019-2021 Triad National Security, LLC.
       7                 :            :              All rights reserved. See the LICENSE file for details.
       8                 :            :   \brief     Scalar transport using continous Galerkin discretization
       9                 :            :   \details   This file implements the physics operators governing transported
      10                 :            :      scalars using continuous Galerkin discretization.
      11                 :            : */
      12                 :            : // *****************************************************************************
      13                 :            : #ifndef CGTransport_h
      14                 :            : #define CGTransport_h
      15                 :            : 
      16                 :            : #include <vector>
      17                 :            : #include <array>
      18                 :            : #include <limits>
      19                 :            : #include <cmath>
      20                 :            : #include <unordered_set>
      21                 :            : #include <unordered_map>
      22                 :            : 
      23                 :            : #include "Exception.hpp"
      24                 :            : #include "Vector.hpp"
      25                 :            : #include "DerivedData.hpp"
      26                 :            : #include "Around.hpp"
      27                 :            : #include "Reconstruction.hpp"
      28                 :            : #include "Inciter/InputDeck/InputDeck.hpp"
      29                 :            : #include "CGPDE.hpp"
      30                 :            : #include "History.hpp"
      31                 :            : 
      32                 :            : namespace inciter {
      33                 :            : 
      34                 :            : extern ctr::InputDeck g_inputdeck;
      35                 :            : 
      36                 :            : namespace cg {
      37                 :            : 
      38                 :            : //! \brief Transport equation used polymorphically with tk::CGPDE
      39                 :            : //! \details The template argument(s) specify policies and are used to configure
      40                 :            : //!   the behavior of the class. The policies are:
      41                 :            : //!   - Physics - physics configuration, see PDE/Transport/Physics/CG.h
      42                 :            : //!   - Problem - problem configuration, see PDE/Transport/Problem.h
      43                 :            : //! \note The default physics is CGAdvection, set in
      44                 :            : //!    inciter::deck::check_transport()
      45                 :            : template< class Physics, class Problem >
      46                 :            : class Transport {
      47                 :            : 
      48                 :            :   private:
      49                 :            :     using ncomp_t = kw::ncomp::info::expect::type;
      50                 :            :     using real = tk::real;
      51                 :            :     using eq = tag::transport;
      52                 :            : 
      53                 :            :     static constexpr real muscl_eps = 1.0e-9;
      54                 :            :     static constexpr real muscl_const = 1.0/3.0;
      55                 :            :     static constexpr real muscl_m1 = 1.0 - muscl_const;
      56                 :            :     static constexpr real muscl_p1 = 1.0 + muscl_const;
      57                 :            : 
      58                 :            :   public:
      59                 :            :     //! Constructor
      60                 :            :     //! \param[in] c Equation system index (among multiple systems configured)
      61                 :        232 :     explicit Transport( ncomp_t c ) :
      62                 :            :       m_physics( Physics() ),
      63                 :            :       m_problem( Problem() ),
      64                 :            :       m_system( c ),
      65                 :            :       m_ncomp(
      66                 :        232 :         g_inputdeck.get< tag::component >().get< tag::transport >().at(c) ),
      67                 :            :       m_offset(
      68                 :        464 :         g_inputdeck.get< tag::component >().offset< tag::transport >(c) )
      69                 :            :     {
      70                 :        232 :       m_problem.errchk( m_system, m_ncomp );
      71                 :        232 :     }
      72                 :            : 
      73                 :            :     //! Determine nodes that lie inside the user-defined IC box
      74                 :            :     void
      75                 :        857 :     IcBoxNodes( const tk::UnsMesh::Coords&,
      76                 :        857 :                 std::vector< std::unordered_set< std::size_t > >& ) const {}
      77                 :            : 
      78                 :            :     //! Initalize the transport equations using problem policy
      79                 :            :     //! \param[in] coord Mesh node coordinates
      80                 :            :     //! \param[in,out] unk Array of unknowns
      81                 :            :     //! \param[in] t Physical time
      82                 :            :     void
      83                 :       1642 :     initialize( const std::array< std::vector< real >, 3 >& coord,
      84                 :            :                 tk::Fields& unk,
      85                 :            :                 real t,
      86                 :            :                 real,
      87                 :            :                 const std::vector< std::unordered_set< std::size_t > >& ) const
      88                 :            :     {
      89 [ -  + ][ -  - ]:       1642 :       Assert( coord[0].size() == unk.nunk(), "Size mismatch" );
         [ -  - ][ -  - ]
      90                 :       1642 :       const auto& x = coord[0];
      91                 :       1642 :       const auto& y = coord[1];
      92                 :       1642 :       const auto& z = coord[2];
      93         [ +  + ]:     866029 :       for (ncomp_t i=0; i<x.size(); ++i) {
      94         [ +  - ]:    1728774 :         auto s = Problem::initialize( m_system, m_ncomp, x[i], y[i], z[i], t );
      95         [ +  + ]:    1740486 :         for (ncomp_t c=0; c<m_ncomp; ++c)
      96         [ +  - ]:     876099 :           unk( i, c, m_offset ) = s[c];
      97                 :            :       }
      98                 :       1642 :     }
      99                 :            : 
     100                 :            :     //! Query a velocity
     101                 :            :     //! \note Since this function does not touch its output argument, that
     102                 :            :     //!   means this system does not define a "velocity".
     103                 :      22259 :     void velocity( const tk::Fields&, tk::UnsMesh::Coords& ) const {}
     104                 :            : 
     105                 :            :     //! Query the sound speed
     106                 :            :     //! \note Since this function does not touch its output argument, that
     107                 :            :     //!   means this system does not define a "sound speed".
     108                 :      22259 :     void soundspeed( const tk::Fields&, std::vector< tk::real >& ) const {}
     109                 :            : 
     110                 :            :     //! Return analytic solution (if defined by Problem) at xi, yi, zi, t
     111                 :            :     //! \param[in] xi X-coordinate
     112                 :            :     //! \param[in] yi Y-coordinate
     113                 :            :     //! \param[in] zi Z-coordinate
     114                 :            :     //! \param[in] t Physical time
     115                 :            :     //! \return Vector of analytic solution at given location and time
     116                 :            :     std::vector< real >
     117                 :     386224 :     analyticSolution( real xi, real yi, real zi, real t ) const
     118                 :     386224 :     { return Problem::analyticSolution( m_system, m_ncomp, xi, yi, zi, t ); }
     119                 :            : 
     120                 :            :     //! Return analytic solution for conserved variables
     121                 :            :     //! \param[in] xi X-coordinate at which to evaluate the analytic solution
     122                 :            :     //! \param[in] yi Y-coordinate at which to evaluate the analytic solution
     123                 :            :     //! \param[in] zi Z-coordinate at which to evaluate the analytic solution
     124                 :            :     //! \param[in] t Physical time at which to evaluate the analytic solution
     125                 :            :     //! \return Vector of analytic solution at given location and time
     126                 :            :     std::vector< tk::real >
     127                 :    4113811 :     solution( tk::real xi, tk::real yi, tk::real zi, tk::real t ) const
     128                 :    4113811 :     { return Problem::initialize( m_system, m_ncomp, xi, yi, zi, t ); }
     129                 :            : 
     130                 :            :     //! Compute nodal gradients of primitive variables for ALECG
     131                 :            :     //! \param[in] coord Mesh node coordinates
     132                 :            :     //! \param[in] inpoel Mesh element connectivity
     133                 :            :     //! \param[in] bndel List of elements contributing to chare-boundary nodes
     134                 :            :     //! \param[in] gid Local->global node id map
     135                 :            :     //! \param[in] bid Local chare-boundary node ids (value) associated to
     136                 :            :     //!    global node ids (key)
     137                 :            :     //! \param[in] U Solution vector at recent time step
     138                 :            :     //! \param[in,out] G Nodal gradients of primitive variables
     139                 :      21870 :     void chBndGrad( const std::array< std::vector< real >, 3 >& coord,
     140                 :            :       const std::vector< std::size_t >& inpoel,
     141                 :            :       const std::vector< std::size_t >& bndel,
     142                 :            :       const std::vector< std::size_t >& gid,
     143                 :            :       const std::unordered_map< std::size_t, std::size_t >& bid,
     144                 :            :       const tk::Fields& U,
     145                 :            :       tk::Fields& G ) const
     146                 :            :     {
     147 [ -  + ][ -  - ]:      21870 :       Assert( U.nunk() == coord[0].size(), "Number of unknowns in solution "
         [ -  - ][ -  - ]
     148                 :            :               "vector at recent time step incorrect" );
     149                 :            : 
     150                 :            :       // compute gradients of primitive variables in points
     151                 :      21870 :       G.fill( 0.0 );
     152                 :            : 
     153                 :            :       // access node cooordinates
     154                 :      21870 :       const auto& x = coord[0];
     155                 :      21870 :       const auto& y = coord[1];
     156                 :      21870 :       const auto& z = coord[2];
     157                 :            : 
     158         [ +  + ]:    7804290 :       for (auto e : bndel) {  // elements contributing to chare boundary nodes
     159                 :            :         // access node IDs
     160                 :    7782420 :         std::size_t N[4] =
     161                 :    7782420 :           { inpoel[e*4+0], inpoel[e*4+1], inpoel[e*4+2], inpoel[e*4+3] };
     162                 :            :         // compute element Jacobi determinant, J = 6V
     163                 :    7782420 :         real bax = x[N[1]]-x[N[0]];
     164                 :    7782420 :         real bay = y[N[1]]-y[N[0]];
     165                 :    7782420 :         real baz = z[N[1]]-z[N[0]];
     166                 :    7782420 :         real cax = x[N[2]]-x[N[0]];
     167                 :    7782420 :         real cay = y[N[2]]-y[N[0]];
     168                 :    7782420 :         real caz = z[N[2]]-z[N[0]];
     169                 :    7782420 :         real dax = x[N[3]]-x[N[0]];
     170                 :    7782420 :         real day = y[N[3]]-y[N[0]];
     171                 :    7782420 :         real daz = z[N[3]]-z[N[0]];
     172                 :    7782420 :         auto J = tk::triple( bax, bay, baz, cax, cay, caz, dax, day, daz );
     173                 :    7782420 :         auto J24 = J/24.0;
     174                 :            :         // shape function derivatives, nnode*ndim [4][3]
     175                 :            :         real g[4][3];
     176                 :    7782420 :         tk::crossdiv( cax, cay, caz, dax, day, daz, J,
     177                 :            :                       g[1][0], g[1][1], g[1][2] );
     178                 :    7782420 :         tk::crossdiv( dax, day, daz, bax, bay, baz, J,
     179                 :            :                       g[2][0], g[2][1], g[2][2] );
     180                 :    7782420 :         tk::crossdiv( bax, bay, baz, cax, cay, caz, J,
     181                 :            :                       g[3][0], g[3][1], g[3][2] );
     182         [ +  + ]:   31129680 :         for (std::size_t i=0; i<3; ++i)
     183                 :   23347260 :           g[0][i] = -g[1][i] - g[2][i] - g[3][i];
     184                 :            :         // scatter-add gradient contributions to boundary nodes
     185         [ +  + ]:   38912100 :         for (std::size_t a=0; a<4; ++a) {
     186         [ +  - ]:   31129680 :           auto i = bid.find( gid[N[a]] );
     187         [ +  + ]:   31129680 :           if (i != end(bid))
     188         [ +  + ]:   42002820 :             for (std::size_t c=0; c<m_ncomp; ++c)
     189         [ +  + ]:  105007050 :               for (std::size_t b=0; b<4; ++b)
     190         [ +  + ]:  336022560 :                 for (std::size_t j=0; j<3; ++j)
     191 [ +  - ][ +  - ]:  252016920 :                   G(i->second,c*3+j,0) += J24 * g[b][j] * U(N[b],c,m_offset);
     192                 :            :         }
     193                 :            :       }
     194                 :      21870 :     }
     195                 :            : 
     196                 :            :     //! Compute right hand side for ALECG
     197                 :            :     //! \param[in] coord Mesh node coordinates
     198                 :            :     //! \param[in] inpoel Mesh element connectivity
     199                 :            :     //! \param[in] triinpoel Boundary triangle face connecitivity
     200                 :            :     //! \param[in] bid Local chare-boundary node ids (value) associated to
     201                 :            :     //!    global node ids (key)
     202                 :            :     //! \param[in] lid Global->local node ids
     203                 :            :     //! \param[in] dfn Dual-face normals
     204                 :            :     //! \param[in] psup Points surrounding points
     205                 :            :     //! \param[in] esup Elements surrounding points
     206                 :            :     //! \param[in] symbctri Vector with 1 at symmetry BC nodes
     207                 :            :     //! \param[in] vol Nodal volumes
     208                 :            :     //! \param[in] edgeid Local node id pair -> edge id map
     209                 :            :     //! \param[in] G Nodal gradients in chare-boundary nodes
     210                 :            :     //! \param[in] U Solution vector at recent time step
     211                 :            :     //! \param[in] W Mesh velocity
     212                 :            :     //! \param[in,out] R Right-hand side vector computed
     213                 :      21870 :     void rhs(
     214                 :            :       real,
     215                 :            :       const std::array< std::vector< real >, 3 >&  coord,
     216                 :            :       const std::vector< std::size_t >& inpoel,
     217                 :            :       const std::vector< std::size_t >& triinpoel,
     218                 :            :       const std::vector< std::size_t >&,
     219                 :            :       const std::unordered_map< std::size_t, std::size_t >& bid,
     220                 :            :       const std::unordered_map< std::size_t, std::size_t >& lid,
     221                 :            :       const std::vector< real >& dfn,
     222                 :            :       const std::pair< std::vector< std::size_t >,
     223                 :            :                        std::vector< std::size_t > >& psup,
     224                 :            :       const std::pair< std::vector< std::size_t >,
     225                 :            :                        std::vector< std::size_t > >& esup,
     226                 :            :       const std::vector< int >& symbctri,
     227                 :            :       const std::unordered_set< std::size_t >&,
     228                 :            :       const std::vector< real >& vol,
     229                 :            :       const std::vector< std::size_t >&,
     230                 :            :       const std::vector< std::size_t >& edgeid,
     231                 :            :       const std::vector< std::unordered_set< std::size_t > >&,
     232                 :            :       const tk::Fields& G,
     233                 :            :       const tk::Fields& U,
     234                 :            :       [[maybe_unused]] const tk::Fields& W,
     235                 :            :       const std::vector< tk::real >&,
     236                 :            :       real,
     237                 :            :       tk::Fields& R ) const
     238                 :            :     {
     239 [ -  + ][ -  - ]:      21870 :       Assert( G.nprop() == m_ncomp*3,
         [ -  - ][ -  - ]
     240                 :            :               "Number of components in gradient vector incorrect" );
     241 [ -  + ][ -  - ]:      21870 :       Assert( U.nunk() == coord[0].size(), "Number of unknowns in solution "
         [ -  - ][ -  - ]
     242                 :            :               "vector at recent time step incorrect" );
     243 [ -  + ][ -  - ]:      21870 :       Assert( R.nunk() == coord[0].size(),
         [ -  - ][ -  - ]
     244                 :            :               "Number of unknowns and/or number of components in right-hand "
     245                 :            :               "side vector incorrect" );
     246                 :            : 
     247                 :            :       // compute/assemble gradients in points
     248         [ +  - ]:      43740 :       auto Grad = nodegrad( coord, inpoel, lid, bid, vol, esup, U, G );
     249                 :            : 
     250                 :            :       // zero right hand side for all components
     251 [ +  + ][ +  - ]:      43740 :       for (ncomp_t c=0; c<m_ncomp; ++c) R.fill( c, m_offset, 0.0 );
     252                 :            : 
     253                 :            :       // compute domain-edge integral
     254         [ +  - ]:      21870 :       domainint( coord, inpoel, edgeid, psup, dfn, U, Grad, R );
     255                 :            : 
     256                 :            :       // compute boundary integrals
     257         [ +  - ]:      21870 :       bndint( coord, triinpoel, symbctri, U, R );
     258                 :      21870 :     }
     259                 :            : 
     260                 :            :     //! Compute right hand side for DiagCG (CG+FCT)
     261                 :            :     //! \param[in] t Physical time
     262                 :            :     //! \param[in] deltat Size of time step
     263                 :            :     //! \param[in] coord Mesh node coordinates
     264                 :            :     //! \param[in] inpoel Mesh element connectivity
     265                 :            :     //! \param[in] U Solution vector at recent time step
     266                 :            :     //! \param[in,out] Ue Element-centered solution vector at intermediate step
     267                 :            :     //!    (used here internally as a scratch array)
     268                 :            :     //! \param[in,out] R Right-hand side vector computed
     269                 :       6279 :     void rhs( real t,
     270                 :            :               real deltat,
     271                 :            :               const std::array< std::vector< real >, 3 >& coord,
     272                 :            :               const std::vector< std::size_t >& inpoel,
     273                 :            :               const tk::Fields& U,
     274                 :            :               tk::Fields& Ue,
     275                 :            :               tk::Fields& R ) const
     276                 :            :     {
     277                 :            :       using tag::transport;
     278 [ -  + ][ -  - ]:       6279 :       Assert( U.nunk() == coord[0].size(), "Number of unknowns in solution "
         [ -  - ][ -  - ]
     279                 :            :               "vector at recent time step incorrect" );
     280 [ -  + ][ -  - ]:       6279 :       Assert( R.nunk() == coord[0].size(),
         [ -  - ][ -  - ]
     281                 :            :               "Number of unknowns in right-hand side vector incorrect" );
     282                 :            : 
     283                 :       6279 :       const auto& x = coord[0];
     284                 :       6279 :       const auto& y = coord[1];
     285                 :       6279 :       const auto& z = coord[2];
     286                 :            : 
     287                 :            :       // 1st stage: update element values from node values (gather-add)
     288         [ +  + ]:    8133961 :       for (std::size_t e=0; e<inpoel.size()/4; ++e) {
     289                 :            :         // access node IDs
     290                 :            :         const std::array< std::size_t, 4 >
     291                 :    8127682 :           N{{ inpoel[e*4+0], inpoel[e*4+1], inpoel[e*4+2], inpoel[e*4+3] }};
     292                 :            :         // compute element Jacobi determinant
     293                 :            :         const std::array< real, 3 >
     294                 :    8127682 :           ba{{ x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]] }},
     295                 :    8127682 :           ca{{ x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]] }},
     296                 :    8127682 :           da{{ x[N[3]]-x[N[0]], y[N[3]]-y[N[0]], z[N[3]]-z[N[0]] }};
     297                 :    8127682 :         const auto J = tk::triple( ba, ca, da );        // J = 6V
     298 [ -  + ][ -  - ]:    8127682 :         Assert( J > 0, "Element Jacobian non-positive" );
         [ -  - ][ -  - ]
     299                 :            : 
     300                 :            :         // shape function derivatives, nnode*ndim [4][3]
     301                 :            :         std::array< std::array< real, 3 >, 4 > grad;
     302                 :    8127682 :         grad[1] = tk::crossdiv( ca, da, J );
     303                 :    8127682 :         grad[2] = tk::crossdiv( da, ba, J );
     304                 :    8127682 :         grad[3] = tk::crossdiv( ba, ca, J );
     305         [ +  + ]:   32510728 :         for (std::size_t i=0; i<3; ++i)
     306                 :   24383046 :           grad[0][i] = -grad[1][i]-grad[2][i]-grad[3][i];
     307                 :            : 
     308                 :            :         // access solution at element nodes
     309         [ +  - ]:   16255364 :         std::vector< std::array< real, 4 > > u( m_ncomp );
     310 [ +  + ][ +  - ]:   16380424 :         for (ncomp_t c=0; c<m_ncomp; ++c) u[c] = U.extract( c, m_offset, N );
     311                 :            :         // access solution at elements
     312         [ +  - ]:   16255364 :         std::vector< const real* > ue( m_ncomp );
     313 [ +  + ][ +  - ]:   16380424 :         for (ncomp_t c=0; c<m_ncomp; ++c) ue[c] = Ue.cptr( c, m_offset );
     314                 :            : 
     315                 :            :         // get prescribed velocity
     316                 :    8127682 :         const std::array< std::vector<std::array<real,3>>, 4 > vel{{
     317         [ +  - ]:    8127682 :           Problem::prescribedVelocity( m_system, m_ncomp,
     318                 :            :                                        x[N[0]], y[N[0]], z[N[0]], t ),
     319         [ +  - ]:    8127682 :           Problem::prescribedVelocity( m_system, m_ncomp,
     320                 :            :                                        x[N[1]], y[N[1]], z[N[1]], t ),
     321         [ +  - ]:    8127682 :           Problem::prescribedVelocity( m_system, m_ncomp,
     322                 :            :                                        x[N[2]], y[N[2]], z[N[2]], t ),
     323         [ +  - ]:    8127682 :           Problem::prescribedVelocity( m_system, m_ncomp,
     324                 :            :                                        x[N[3]], y[N[3]], z[N[3]], t ) }};
     325                 :            : 
     326                 :            :         // sum flux (advection) contributions to element
     327                 :    8127682 :         auto d = deltat/2.0;
     328         [ +  + ]:   16380424 :         for (std::size_t c=0; c<m_ncomp; ++c)
     329         [ +  + ]:   33010968 :           for (std::size_t j=0; j<3; ++j)
     330         [ +  + ]:  123791130 :             for (std::size_t a=0; a<4; ++a)
     331         [ +  - ]:   99032904 :               Ue.var(ue[c],e) -= d * grad[a][j] * vel[a][c][j]*u[c][a];
     332                 :            :       }
     333                 :            : 
     334                 :            : 
     335                 :            :       // 2nd stage: form rhs from element values (scatter-add)
     336         [ +  + ]:    8133961 :       for (std::size_t e=0; e<inpoel.size()/4; ++e) {
     337                 :            :         // access node IDs
     338                 :            :         const std::array< std::size_t, 4 >
     339                 :    8127682 :           N{{ inpoel[e*4+0], inpoel[e*4+1], inpoel[e*4+2], inpoel[e*4+3] }};
     340                 :            :         // compute element Jacobi determinant
     341                 :            :         const std::array< real, 3 >
     342                 :    8127682 :           ba{{ x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]] }},
     343                 :    8127682 :           ca{{ x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]] }},
     344                 :    8127682 :           da{{ x[N[3]]-x[N[0]], y[N[3]]-y[N[0]], z[N[3]]-z[N[0]] }};
     345                 :    8127682 :         const auto J = tk::triple( ba, ca, da );        // J = 6V
     346 [ -  + ][ -  - ]:    8127682 :         Assert( J > 0, "Element Jacobian non-positive" );
         [ -  - ][ -  - ]
     347                 :            : 
     348                 :            :         // shape function derivatives, nnode*ndim [4][3]
     349                 :            :         std::array< std::array< real, 3 >, 4 > grad;
     350                 :    8127682 :         grad[1] = tk::crossdiv( ca, da, J );
     351                 :    8127682 :         grad[2] = tk::crossdiv( da, ba, J );
     352                 :    8127682 :         grad[3] = tk::crossdiv( ba, ca, J );
     353         [ +  + ]:   32510728 :         for (std::size_t i=0; i<3; ++i)
     354                 :   24383046 :           grad[0][i] = -grad[1][i]-grad[2][i]-grad[3][i];
     355                 :            : 
     356                 :            :         // access solution at elements
     357         [ +  - ]:   16255364 :         std::vector< real > ue( m_ncomp );
     358 [ +  + ][ +  - ]:   16380424 :         for (ncomp_t c=0; c<m_ncomp; ++c) ue[c] = Ue( e, c, m_offset );
     359                 :            :         // access pointer to right hand side at component and offset
     360         [ +  - ]:   16255364 :         std::vector< const real* > r( m_ncomp );
     361 [ +  + ][ +  - ]:   16380424 :         for (ncomp_t c=0; c<m_ncomp; ++c) r[c] = R.cptr( c, m_offset );
     362                 :            :         // access solution at nodes of element
     363         [ +  - ]:   16255364 :         std::vector< std::array< real, 4 > > u( m_ncomp );
     364 [ +  + ][ +  - ]:   16380424 :         for (ncomp_t c=0; c<m_ncomp; ++c) u[c] = U.extract( c, m_offset, N );
     365                 :            : 
     366                 :            :         // get prescribed velocity
     367                 :    8127682 :         auto xc = (x[N[0]] + x[N[1]] + x[N[2]] + x[N[3]]) / 4.0;
     368                 :    8127682 :         auto yc = (y[N[0]] + y[N[1]] + y[N[2]] + y[N[3]]) / 4.0;
     369                 :    8127682 :         auto zc = (z[N[0]] + z[N[1]] + z[N[2]] + z[N[3]]) / 4.0;
     370                 :    8127682 :         const auto vel =
     371         [ +  - ]:    8127682 :           Problem::prescribedVelocity( m_system, m_ncomp, xc, yc, zc, t );
     372                 :            : 
     373                 :            :         // scatter-add flux contributions to rhs at nodes
     374                 :    8127682 :         real d = deltat * J/6.0;
     375         [ +  + ]:   16380424 :         for (std::size_t c=0; c<m_ncomp; ++c)
     376         [ +  + ]:   33010968 :           for (std::size_t j=0; j<3; ++j)
     377         [ +  + ]:  123791130 :             for (std::size_t a=0; a<4; ++a)
     378         [ +  - ]:   99032904 :               R.var(r[c],N[a]) += d * grad[a][j] * vel[c][j]*ue[c];
     379                 :            : 
     380                 :            :         // add (optional) diffusion contribution to right hand side
     381         [ +  - ]:    8127682 :         m_physics.diffusionRhs(m_system, m_ncomp, deltat, J, grad, N, u, r, R);
     382                 :            :       }
     383                 :       6279 :     }
     384                 :            : 
     385                 :            :     //! Compute the minimum time step size (for unsteady time stepping)
     386                 :            :     //! \param[in] U Solution vector at recent time step
     387                 :            :     //! \param[in] coord Mesh node coordinates
     388                 :            :     //! \param[in] inpoel Mesh element connectivity
     389                 :            :     //! \param[in] t Physical time
     390                 :            :     //! \return Minimum time step size
     391                 :       3159 :     real dt( const std::array< std::vector< real >, 3 >& coord,
     392                 :            :              const std::vector< std::size_t >& inpoel,
     393                 :            :              tk::real t,
     394                 :            :              tk::real,
     395                 :            :              const tk::Fields& U,
     396                 :            :              const std::vector< tk::real >&,
     397                 :            :              const std::vector< tk::real >& ) const
     398                 :            :     {
     399                 :            :       using tag::transport;
     400 [ -  + ][ -  - ]:       3159 :       Assert( U.nunk() == coord[0].size(), "Number of unknowns in solution "
         [ -  - ][ -  - ]
     401                 :            :               "vector at recent time step incorrect" );
     402                 :       3159 :       const auto& x = coord[0];
     403                 :       3159 :       const auto& y = coord[1];
     404                 :       3159 :       const auto& z = coord[2];
     405                 :            :       // compute the minimum dt across all elements we own
     406                 :       3159 :       auto mindt = std::numeric_limits< tk::real >::max();
     407                 :       3159 :       auto eps = std::numeric_limits< tk::real >::epsilon();
     408                 :       3159 :       auto large = std::numeric_limits< tk::real >::max();
     409         [ +  + ]:    1870041 :       for (std::size_t e=0; e<inpoel.size()/4; ++e) {
     410                 :            :         const std::array< std::size_t, 4 >
     411                 :    1866882 :           N{{ inpoel[e*4+0], inpoel[e*4+1], inpoel[e*4+2], inpoel[e*4+3] }};
     412                 :            :         // compute cubic root of element volume as the characteristic length
     413                 :            :         const std::array< real, 3 >
     414                 :    1866882 :           ba{{ x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]] }},
     415                 :    1866882 :           ca{{ x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]] }},
     416                 :    1866882 :           da{{ x[N[3]]-x[N[0]], y[N[3]]-y[N[0]], z[N[3]]-z[N[0]] }};
     417                 :    1866882 :         const auto L = std::cbrt( tk::triple( ba, ca, da ) / 6.0 );
     418                 :            :         // access solution at element nodes at recent time step
     419         [ +  - ]:    3733764 :         std::vector< std::array< real, 4 > > u( m_ncomp );
     420 [ +  + ][ +  - ]:    3858824 :         for (ncomp_t c=0; c<m_ncomp; ++c) u[c] = U.extract( c, m_offset, N );
     421                 :            :         // get velocity for problem
     422                 :    1866882 :         const std::array< std::vector<std::array<real,3>>, 4 > vel{{
     423         [ +  - ]:    1866882 :           Problem::prescribedVelocity( m_system, m_ncomp,
     424                 :            :                                        x[N[0]], y[N[0]], z[N[0]], t ),
     425         [ +  - ]:    1866882 :           Problem::prescribedVelocity( m_system, m_ncomp,
     426                 :            :                                        x[N[1]], y[N[1]], z[N[1]], t ),
     427         [ +  - ]:    1866882 :           Problem::prescribedVelocity( m_system, m_ncomp,
     428                 :            :                                        x[N[2]], y[N[2]], z[N[2]], t ),
     429         [ +  - ]:    1866882 :           Problem::prescribedVelocity( m_system, m_ncomp,
     430                 :            :                                        x[N[3]], y[N[3]], z[N[3]], t ) }};
     431                 :            :         // compute the maximum length of the characteristic velocity (advection
     432                 :            :         // velocity) across the four element nodes
     433                 :    1866882 :         real maxvel = 0.0;
     434         [ +  + ]:    3858824 :         for (ncomp_t c=0; c<m_ncomp; ++c)
     435         [ +  + ]:    9959710 :           for (std::size_t i=0; i<4; ++i) {
     436                 :    7967768 :             auto v = tk::length( vel[i][c] );
     437         [ +  + ]:    7967768 :             if (v > maxvel) maxvel = v;
     438                 :            :           }
     439                 :            :         // compute element dt for the advection
     440         [ +  + ]:    1866882 :         auto advection_dt = std::abs(maxvel) > eps ? L / maxvel : large;
     441                 :            :         // compute element dt based on diffusion
     442         [ +  - ]:    1866882 :         auto diffusion_dt = m_physics.diffusion_dt( m_system, m_ncomp, L, u );
     443                 :            :         // compute minimum element dt
     444                 :    1866882 :         auto elemdt = std::min( advection_dt, diffusion_dt );
     445                 :            :         // find minimum dt across all elements
     446         [ +  + ]:    1866882 :         if (elemdt < mindt) mindt = elemdt;
     447                 :            :       }
     448                 :       3159 :       return mindt * g_inputdeck.get< tag::discr, tag::cfl >();
     449                 :            :     }
     450                 :            : 
     451                 :            :     //! Compute a time step size for each mesh node (for steady time stepping)
     452                 :          0 :     void dt( uint64_t,
     453                 :            :              const std::vector< tk::real >&,
     454                 :            :              const tk::Fields&,
     455                 :          0 :              std::vector< tk::real >& ) const {}
     456                 :            : 
     457                 :            :     //! \brief Query Dirichlet boundary condition value on a given side set for
     458                 :            :     //!    all components in this PDE system
     459                 :            :     //! \param[in] t Physical time
     460                 :            :     //! \param[in] deltat Time step size
     461                 :            :     //! \param[in] tp Physical time for each mesh node
     462                 :            :     //! \param[in] dtp Time step size for each mesh node
     463                 :            :     //! \param[in] ss Pair of side set ID and list of node IDs on the side set
     464                 :            :     //! \param[in] coord Mesh node coordinates
     465                 :            :     //! \param[in] increment If true, evaluate the solution increment between
     466                 :            :     //!   t and t+dt for Dirichlet BCs. If false, evlauate the solution instead.
     467                 :            :     //! \return Vector of pairs of bool and boundary condition value associated
     468                 :            :     //!   to mesh node IDs at which Dirichlet boundary conditions are set. Note
     469                 :            :     //!   that if increment is true, instead of the actual boundary condition
     470                 :            :     //!   value, we return the increment between t+deltat and t, since,
     471                 :            :     //!   depending on client code and solver, that may be what the solution
     472                 :            :     //!   requires.
     473                 :            :     std::map< std::size_t, std::vector< std::pair<bool,real> > >
     474                 :      13595 :     dirbc( real t,
     475                 :            :            real deltat,
     476                 :            :            const std::vector< tk::real >& tp,
     477                 :            :            const std::vector< tk::real >& dtp,
     478                 :            :            const std::pair< const int, std::vector< std::size_t > >& ss,
     479                 :            :            const std::array< std::vector< real >, 3 >& coord,
     480                 :            :            bool increment ) const
     481                 :            :     {
     482                 :            :       using tag::param; using tag::transport; using tag::bcdir;
     483                 :            :       using NodeBC = std::vector< std::pair< bool, real > >;
     484                 :      13595 :       std::map< std::size_t, NodeBC > bc;
     485                 :      13595 :       const auto& ubc = g_inputdeck.get< param, transport, tag::bc, bcdir >();
     486                 :      13595 :       const auto steady = g_inputdeck.get< tag::discr, tag::steady_state >();
     487         [ +  + ]:      13595 :       if (!ubc.empty()) {
     488 [ -  + ][ -  - ]:        760 :         Assert( ubc.size() > m_system, "Indexing out of Dirichlet BC eq-vector" );
         [ -  - ][ -  - ]
     489                 :        760 :         const auto& x = coord[0];
     490                 :        760 :         const auto& y = coord[1];
     491                 :        760 :         const auto& z = coord[2];
     492         [ +  + ]:       5320 :         for (const auto& b : ubc[m_system])
     493 [ +  - ][ +  + ]:       4560 :           if (std::stoi(b) == ss.first)
     494         [ +  + ]:     213070 :             for (auto n : ss.second) {
     495 [ -  + ][ -  - ]:     212310 :               Assert( x.size() > n, "Indexing out of coordinate array" );
         [ -  - ][ -  - ]
     496         [ -  + ]:     212310 :               if (steady) { t = tp[n]; deltat = dtp[n]; }
     497 [ +  - ][ +  - ]:     636930 :               const auto s = increment ?
         [ +  - ][ -  - ]
     498         [ +  - ]:     212310 :                 solinc( m_system, m_ncomp, x[n], y[n], z[n],
     499                 :            :                         t, deltat, Problem::initialize ) :
     500         [ -  - ]:          0 :                 Problem::initialize( m_system, m_ncomp, x[n], y[n], z[n],
     501                 :            :                                      t+deltat );
     502 [ +  - ][ +  - ]:     212310 :               auto& nbc = bc[n] = NodeBC( m_ncomp );
     503         [ +  + ]:     444520 :               for (ncomp_t c=0; c<m_ncomp; ++c)
     504                 :     232210 :                 nbc[c] = { true, s[c] };
     505                 :            :             }
     506                 :            :       }
     507                 :      13595 :       return bc;
     508                 :            :     }
     509                 :            : 
     510                 :            :     //! Set symmetry boundary conditions at nodes
     511                 :            :     void
     512                 :      55061 :     symbc(
     513                 :            :       tk::Fields&,
     514                 :            :       const std::array< std::vector< real >, 3 >&,
     515                 :            :       const std::unordered_map< int,
     516                 :            :               std::unordered_map< std::size_t,
     517                 :            :                 std::array< real, 4 > > >&,
     518                 :      55061 :       const std::unordered_set< std::size_t >& ) const {}
     519                 :            : 
     520                 :            :     //! Set farfield boundary conditions at nodes
     521                 :      48782 :     void farfieldbc(
     522                 :            :       tk::Fields&,
     523                 :            :       const std::array< std::vector< real >, 3 >&,
     524                 :            :       const std::unordered_map< int,
     525                 :            :               std::unordered_map< std::size_t,
     526                 :            :                 std::array< real, 4 > > >&,
     527                 :      48782 :       const std::unordered_set< std::size_t >& ) const {}
     528                 :            : 
     529                 :            :     //! Apply sponge conditions at boundary nodes (no-op for transport)
     530                 :      22259 :     void sponge( tk::Fields&,
     531                 :            :                  const std::array< std::vector< real >, 3 >&,
     532                 :      22259 :                  const std::unordered_set< std::size_t >& ) const {}
     533                 :            : 
     534                 :            :     //! Apply user defined time dependent BCs (no-op for transport)
     535                 :            :     void
     536                 :      22259 :     timedepbc( tk::real,
     537                 :            :       tk::Fields&,
     538                 :            :       const std::vector< std::unordered_set< std::size_t > >&,
     539                 :      22259 :       const std::vector< tk::Table<5> >& ) const {}
     540                 :            : 
     541                 :            :     //! Return analytic field names to be output to file
     542                 :            :     //! \return Vector of strings labelling analytic fields output in file
     543                 :       1065 :     std::vector< std::string > analyticFieldNames() const {
     544                 :       1065 :       std::vector< std::string > n;
     545                 :       1065 :       auto depvar = g_inputdeck.get< tag::param, eq, tag::depvar >()[m_system];
     546         [ +  + ]:       2133 :       for (ncomp_t c=0; c<m_ncomp; ++c)
     547 [ +  - ][ +  - ]:       1068 :         n.push_back( depvar + std::to_string(c) + "_analytic" );
         [ +  - ][ +  - ]
     548                 :       1065 :       return n;
     549                 :            :     }
     550                 :            : 
     551                 :            :     //! Return surface field names to be output to file
     552                 :            :     //! \return Vector of strings labelling surface fields output in file
     553                 :            :     //! \details This functions should be written in conjunction with
     554                 :            :     //!   surfOutput(), which provides the vector of surface fields to be output
     555                 :       1179 :     std::vector< std::string > surfNames() const { return {}; }
     556                 :            : 
     557                 :            :     //! Return surface field output going to file
     558                 :            :     std::vector< std::vector< real > >
     559                 :       1179 :     surfOutput( const std::map< int, std::vector< std::size_t > >&,
     560                 :       1179 :                 const tk::Fields& ) const { return {}; }
     561                 :            : 
     562                 :            :     //! Return time history field names to be output to file
     563                 :            :     //! \return Vector of strings labelling time history fields output in file
     564                 :          0 :     std::vector< std::string > histNames() const { return {}; }
     565                 :            : 
     566                 :            :     //! Return time history field output evaluated at time history points
     567                 :            :     std::vector< std::vector< real > >
     568                 :          0 :     histOutput( const std::vector< HistData >&,
     569                 :            :                 const std::vector< std::size_t >&,
     570                 :          0 :                 const tk::Fields& ) const { return {}; }
     571                 :            : 
     572                 :            :     //! Return names of integral variables to be output to diagnostics file
     573                 :            :     //! \return Vector of strings labelling integral variables output
     574                 :         77 :     std::vector< std::string > names() const {
     575                 :         77 :       std::vector< std::string > n;
     576                 :            :       const auto& depvar =
     577                 :         77 :         g_inputdeck.get< tag::param, tag::transport, tag::depvar >().
     578         [ +  - ]:         77 :         at(m_system);
     579                 :            :       // construct the name of the numerical solution for all components
     580         [ +  + ]:        155 :       for (ncomp_t c=0; c<m_ncomp; ++c)
     581 [ +  - ][ +  - ]:         78 :         n.push_back( depvar + std::to_string(c) );
                 [ +  - ]
     582                 :         77 :       return n;
     583                 :            :     }
     584                 :            : 
     585                 :            :   private:
     586                 :            :     const Physics m_physics;            //!< Physics policy
     587                 :            :     const Problem m_problem;            //!< Problem policy
     588                 :            :     const ncomp_t m_system;             //!< Equation system index
     589                 :            :     const ncomp_t m_ncomp;              //!< Number of components in this PDE
     590                 :            :     const ncomp_t m_offset;             //!< Offset this PDE operates from
     591                 :            : 
     592                 :            :     //! \brief Compute/assemble nodal gradients of primitive variables for
     593                 :            :     //!   ALECG in all points
     594                 :            :     //! \param[in] coord Mesh node coordinates
     595                 :            :     //! \param[in] inpoel Mesh element connectivity
     596                 :            :     //! \param[in] lid Global->local node ids
     597                 :            :     //! \param[in] bid Local chare-boundary node ids (value) associated to
     598                 :            :     //!    global node ids (key)
     599                 :            :     //! \param[in] vol Nodal volumes
     600                 :            :     //! \param[in] esup Elements surrounding points
     601                 :            :     //! \param[in] U Solution vector at recent time step
     602                 :            :     //! \param[in] G Nodal gradients of primitive variables in chare-boundary nodes
     603                 :            :     //! \return Gradients of primitive variables in all mesh points
     604                 :            :     tk::Fields
     605                 :      21870 :     nodegrad( const std::array< std::vector< real >, 3 >& coord,
     606                 :            :               const std::vector< std::size_t >& inpoel,
     607                 :            :               const std::unordered_map< std::size_t, std::size_t >& lid,
     608                 :            :               const std::unordered_map< std::size_t, std::size_t >& bid,
     609                 :            :               const std::vector< real >& vol,
     610                 :            :               const std::pair< std::vector< std::size_t >,
     611                 :            :                                std::vector< std::size_t > >& esup,
     612                 :            :               const tk::Fields& U,
     613                 :            :               const tk::Fields& G ) const
     614                 :            :     {
     615                 :            :       // allocate storage for nodal gradients of primitive variables
     616                 :      21870 :       tk::Fields Grad( U.nunk(), m_ncomp*3 );
     617                 :      21870 :       Grad.fill( 0.0 );
     618                 :            : 
     619                 :            :       // access node cooordinates
     620                 :      21870 :       const auto& x = coord[0];
     621                 :      21870 :       const auto& y = coord[1];
     622                 :      21870 :       const auto& z = coord[2];
     623                 :            : 
     624                 :            :       // compute gradients of primitive variables in points
     625                 :      21870 :       auto npoin = U.nunk();
     626                 :            :       #pragma omp simd
     627         [ +  + ]:    5931810 :       for (std::size_t p=0; p<npoin; ++p)
     628         [ +  + ]:   82269780 :         for (auto e : tk::Around(esup,p)) {
     629                 :            :           // access node IDs
     630                 :   76359840 :           std::size_t N[4] =
     631                 :   76359840 :             { inpoel[e*4+0], inpoel[e*4+1], inpoel[e*4+2], inpoel[e*4+3] };
     632                 :            :           // compute element Jacobi determinant, J = 6V
     633                 :   76359840 :           real bax = x[N[1]]-x[N[0]];
     634                 :   76359840 :           real bay = y[N[1]]-y[N[0]];
     635                 :   76359840 :           real baz = z[N[1]]-z[N[0]];
     636                 :   76359840 :           real cax = x[N[2]]-x[N[0]];
     637                 :   76359840 :           real cay = y[N[2]]-y[N[0]];
     638                 :   76359840 :           real caz = z[N[2]]-z[N[0]];
     639                 :   76359840 :           real dax = x[N[3]]-x[N[0]];
     640                 :   76359840 :           real day = y[N[3]]-y[N[0]];
     641                 :   76359840 :           real daz = z[N[3]]-z[N[0]];
     642                 :   76359840 :           auto J = tk::triple( bax, bay, baz, cax, cay, caz, dax, day, daz );
     643                 :   76359840 :           auto J24 = J/24.0;
     644                 :            :           // shape function derivatives, nnode*ndim [4][3]
     645                 :            :           real g[4][3];
     646                 :   76359840 :           tk::crossdiv( cax, cay, caz, dax, day, daz, J,
     647                 :            :                         g[1][0], g[1][1], g[1][2] );
     648                 :   76359840 :           tk::crossdiv( dax, day, daz, bax, bay, baz, J,
     649                 :            :                         g[2][0], g[2][1], g[2][2] );
     650                 :   76359840 :           tk::crossdiv( bax, bay, baz, cax, cay, caz, J,
     651                 :            :                         g[3][0], g[3][1], g[3][2] );
     652         [ +  + ]:  305439360 :           for (std::size_t i=0; i<3; ++i)
     653                 :  229079520 :             g[0][i] = -g[1][i] - g[2][i] - g[3][i];
     654                 :            :           // scatter-add gradient contributions to boundary nodes
     655         [ +  + ]:  152719680 :           for (std::size_t c=0; c<m_ncomp; ++c)
     656         [ +  + ]:  381799200 :             for (std::size_t b=0; b<4; ++b)
     657         [ +  + ]: 1221757440 :               for (std::size_t i=0; i<3; ++i)
     658 [ +  - ][ +  - ]:  916318080 :                 Grad(p,c*3+i,0) += J24 * g[b][i] * U(N[b],c,m_offset);
     659                 :            :         }
     660                 :            : 
     661                 :            :       // put in nodal gradients of chare-boundary points
     662         [ +  + ]:    2761410 :       for (const auto& [g,b] : bid) {
     663         [ +  - ]:    2739540 :         auto i = tk::cref_find( lid, g );
     664         [ +  + ]:   10958160 :         for (ncomp_t c=0; c<Grad.nprop(); ++c)
     665 [ +  - ][ +  - ]:    8218620 :           Grad(i,c,0) = G(b,c,0);
     666                 :            :       }
     667                 :            : 
     668                 :            :       // divide weak result in gradients by nodal volume
     669         [ +  + ]:    5931810 :       for (std::size_t p=0; p<npoin; ++p)
     670         [ +  + ]:   23639760 :         for (std::size_t c=0; c<m_ncomp*3; ++c)
     671         [ +  - ]:   17729820 :           Grad(p,c,0) /= vol[p];
     672                 :            : 
     673                 :      21870 :       return Grad;
     674                 :            :     }
     675                 :            : 
     676                 :            :     //! \brief Compute MUSCL reconstruction in edge-end points using a MUSCL
     677                 :            :     //!    procedure with van Leer limiting
     678                 :            :     //! \param[in] p Left node id of edge-end
     679                 :            :     //! \param[in] q Right node id of edge-end
     680                 :            :     //! \param[in] coord Array of nodal coordinates
     681                 :            :     //! \param[in] G Gradient of all unknowns in mesh points
     682                 :            :     //! \param[in,out] uL Primitive variables at left edge-end point
     683                 :            :     //! \param[in,out] uR Primitive variables at right edge-end point
     684                 :            :     void
     685                 :   59805420 :     muscl( std::size_t p,
     686                 :            :            std::size_t q,
     687                 :            :            const tk::UnsMesh::Coords& coord,
     688                 :            :            const tk::Fields& G,
     689                 :            :            std::vector< real >& uL,
     690                 :            :            std::vector< real >& uR ) const
     691                 :            :     {
     692 [ +  - ][ +  - ]:   59805420 :       Assert( uL.size() == m_ncomp && uR.size() == m_ncomp, "Size mismatch" );
         [ -  - ][ -  - ]
                 [ -  - ]
     693 [ -  + ][ -  - ]:   59805420 :       Assert( G.nprop()/3 == m_ncomp, "Size mismatch" );
         [ -  - ][ -  - ]
     694                 :            : 
     695                 :   59805420 :       const auto& x = coord[0];
     696                 :   59805420 :       const auto& y = coord[1];
     697                 :   59805420 :       const auto& z = coord[2];
     698                 :            : 
     699                 :            :       // edge vector
     700                 :   59805420 :       std::array< real, 3 > vw{ x[q]-x[p], y[q]-y[p], z[q]-z[p] };
     701                 :            : 
     702                 :            :       std::vector< real >
     703 [ +  - ][ +  - ]:  119610840 :         delta1( m_ncomp, 0.0 ), delta2( m_ncomp, 0.0 ), delta3( m_ncomp, 0.0 );
                 [ +  - ]
     704                 :            : 
     705                 :            :       // MUSCL reconstruction of edge-end-point primitive variables
     706         [ +  + ]:  119610840 :       for (std::size_t c=0; c<m_ncomp; ++c) {
     707                 :            :         // gradients
     708                 :            :         std::array< real, 3 >
     709 [ +  - ][ +  - ]:   59805420 :           g1{ G(p,c*3+0,0), G(p,c*3+1,0), G(p,c*3+2,0) },
                 [ +  - ]
     710 [ +  - ][ +  - ]:   59805420 :           g2{ G(q,c*3+0,0), G(q,c*3+1,0), G(q,c*3+2,0) };
                 [ +  - ]
     711                 :            : 
     712                 :   59805420 :         delta2[c] = uR[c] - uL[c];
     713                 :   59805420 :         delta1[c] = 2.0 * tk::dot(g1,vw) - delta2[c];
     714                 :   59805420 :         delta3[c] = 2.0 * tk::dot(g2,vw) - delta2[c];
     715                 :            : 
     716                 :            :         // form limiters
     717                 :   59805420 :         auto rL = (delta2[c] + muscl_eps) / (delta1[c] + muscl_eps);
     718                 :   59805420 :         auto rR = (delta2[c] + muscl_eps) / (delta3[c] + muscl_eps);
     719                 :   59805420 :         auto rLinv = (delta1[c] + muscl_eps) / (delta2[c] + muscl_eps);
     720                 :   59805420 :         auto rRinv = (delta3[c] + muscl_eps) / (delta2[c] + muscl_eps);
     721                 :            : 
     722                 :   59805420 :         auto phiL = (std::abs(rL) + rL) / (std::abs(rL) + 1.0);
     723                 :   59805420 :         auto phiR = (std::abs(rR) + rR) / (std::abs(rR) + 1.0);
     724                 :   59805420 :         auto phi_L_inv = (std::abs(rLinv) + rLinv) / (std::abs(rLinv) + 1.0);
     725                 :   59805420 :         auto phi_R_inv = (std::abs(rRinv) + rRinv) / (std::abs(rRinv) + 1.0);
     726                 :            : 
     727                 :            :         // update unknowns with reconstructed unknowns
     728                 :   59805420 :         uL[c] += 0.25*(delta1[c]*muscl_m1*phiL + delta2[c]*muscl_p1*phi_L_inv);
     729                 :   59805420 :         uR[c] -= 0.25*(delta3[c]*muscl_m1*phiR + delta2[c]*muscl_p1*phi_R_inv);
     730                 :            :       }
     731                 :   59805420 :     }
     732                 :            : 
     733                 :            :     //! Compute domain-edge integral for ALECG
     734                 :            :     //! \param[in] coord Mesh node coordinates
     735                 :            :     //! \param[in] inpoel Mesh element connectivity
     736                 :            :     //! \param[in] edgeid Local node id pair -> edge id map
     737                 :            :     //! \param[in] psup Points surrounding points
     738                 :            :     //! \param[in] dfn Dual-face normals
     739                 :            :     //! \param[in] U Solution vector at recent time step
     740                 :            :     //! \param[in] G Nodal gradients
     741                 :            :     //! \param[in,out] R Right-hand side vector computed
     742                 :      21870 :     void domainint( const std::array< std::vector< real >, 3 >& coord,
     743                 :            :                     const std::vector< std::size_t >& inpoel,
     744                 :            :                     const std::vector< std::size_t >& edgeid,
     745                 :            :                     const std::pair< std::vector< std::size_t >,
     746                 :            :                                      std::vector< std::size_t > >& psup,
     747                 :            :                     const std::vector< real >& dfn,
     748                 :            :                     const tk::Fields& U,
     749                 :            :                     const tk::Fields& G,
     750                 :            :                     tk::Fields& R ) const
     751                 :            :     {
     752                 :            :       // access node cooordinates
     753                 :      21870 :       const auto& x = coord[0];
     754                 :      21870 :       const auto& y = coord[1];
     755                 :      21870 :       const auto& z = coord[2];
     756                 :            : 
     757                 :            :       // compute derived data structures
     758 [ +  - ][ +  - ]:      43740 :       auto esued = tk::genEsued( inpoel, 4, tk::genEsup( inpoel, 4 ) );
     759                 :            : 
     760                 :            :       // access pointer to right hand side at component and offset
     761         [ +  - ]:      43740 :       std::vector< const real* > r( m_ncomp );
     762 [ +  + ][ +  - ]:      43740 :       for (ncomp_t c=0; c<m_ncomp; ++c) r[c] = R.cptr( c, m_offset );
     763                 :            : 
     764                 :            :       // domain-edge integral
     765         [ +  + ]:    5931810 :       for (std::size_t p=0,k=0; p<U.nunk(); ++p) {
     766         [ +  + ]:   65715360 :         for (auto q : tk::Around(psup,p)) {
     767                 :            :           // access dual-face normals for edge p-q
     768                 :   59805420 :           auto ed = edgeid[k++];
     769                 :   59805420 :           std::array< tk::real, 3 > n{ dfn[ed*6+0], dfn[ed*6+1], dfn[ed*6+2] };
     770                 :            : 
     771         [ +  - ]:  119610840 :           std::vector< tk::real > uL( m_ncomp, 0.0 );
     772         [ +  - ]:  119610840 :           std::vector< tk::real > uR( m_ncomp, 0.0 );
     773         [ +  + ]:  119610840 :           for (std::size_t c=0; c<m_ncomp; ++c) {
     774         [ +  - ]:   59805420 :             uL[c] = U(p,c,m_offset);
     775         [ +  - ]:   59805420 :             uR[c] = U(q,c,m_offset);
     776                 :            :           }
     777                 :            :           // compute MUSCL reconstruction in edge-end points
     778         [ +  - ]:   59805420 :           muscl( p, q, coord, G, uL, uR );
     779                 :            : 
     780                 :            :           // evaluate prescribed velocity
     781                 :   59805420 :           auto v =
     782         [ +  - ]:   59805420 :             Problem::prescribedVelocity( m_system, m_ncomp, x[p], y[p], z[p],
     783                 :            :               0.0 );
     784                 :            :           // sum donain-edge contributions
     785 [ +  - ][ +  + ]:  288884940 :           for (auto e : tk::cref_find(esued,{p,q})) {
     786                 :            :             const std::array< std::size_t, 4 >
     787                 :  229079520 :               N{{ inpoel[e*4+0], inpoel[e*4+1], inpoel[e*4+2], inpoel[e*4+3] }};
     788                 :            :             // compute element Jacobi determinant
     789                 :            :             const std::array< tk::real, 3 >
     790                 :  229079520 :               ba{{ x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]] }},
     791                 :  229079520 :               ca{{ x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]] }},
     792                 :  229079520 :               da{{ x[N[3]]-x[N[0]], y[N[3]]-y[N[0]], z[N[3]]-z[N[0]] }};
     793                 :  229079520 :             const auto J = tk::triple( ba, ca, da );        // J = 6V
     794                 :            :             // shape function derivatives, nnode*ndim [4][3]
     795                 :            :             std::array< std::array< tk::real, 3 >, 4 > grad;
     796                 :  229079520 :             grad[1] = tk::crossdiv( ca, da, J );
     797                 :  229079520 :             grad[2] = tk::crossdiv( da, ba, J );
     798                 :  229079520 :             grad[3] = tk::crossdiv( ba, ca, J );
     799         [ +  + ]:  916318080 :             for (std::size_t i=0; i<3; ++i)
     800                 :  687238560 :               grad[0][i] = -grad[1][i]-grad[2][i]-grad[3][i];
     801                 :  229079520 :             auto J48 = J/48.0;
     802         [ +  + ]: 1603556640 :             for (const auto& [a,b] : tk::lpoed) {
     803         [ +  - ]: 1374477120 :               auto s = tk::orient( {N[a],N[b]}, {p,q} );
     804         [ +  + ]: 5497908480 :               for (std::size_t j=0; j<3; ++j) {
     805         [ +  + ]: 8246862720 :                 for (std::size_t c=0; c<m_ncomp; ++c) {
     806         [ +  - ]: 8246862720 :                   R.var(r[c],p) -= J48 * s * (grad[a][j] - grad[b][j])
     807                 : 4123431360 :                                    * v[c][j]*(uL[c] + uR[c])
     808                 : 4123431360 :                     - J48 * std::abs(s * (grad[a][j] - grad[b][j]))
     809                 : 4123431360 :                           * std::abs(tk::dot(v[c],n)) * (uR[c] - uL[c]);
     810                 :            :                 }
     811                 :            :               }
     812                 :            :             }
     813                 :            :           }
     814                 :            :         }
     815                 :            :       }
     816                 :      21870 :     }
     817                 :            : 
     818                 :            :     //! Compute boundary integrals for ALECG
     819                 :            :     //! \param[in] coord Mesh node coordinates
     820                 :            :     //! \param[in] triinpoel Boundary triangle face connecitivity with local ids
     821                 :            :     //! \param[in] symbctri Vector with 1 at symmetry BC boundary triangles
     822                 :            :     //! \param[in] U Solution vector at recent time step
     823                 :            :     //! \param[in,out] R Right-hand side vector computed
     824                 :      21870 :     void bndint( const std::array< std::vector< real >, 3 >& coord,
     825                 :            :                  const std::vector< std::size_t >& triinpoel,
     826                 :            :                  const std::vector< int >& symbctri,
     827                 :            :                  const tk::Fields& U,
     828                 :            :                  tk::Fields& R ) const
     829                 :            :     {
     830                 :            :       // access node coordinates
     831                 :      21870 :       const auto& x = coord[0];
     832                 :      21870 :       const auto& y = coord[1];
     833                 :      21870 :       const auto& z = coord[2];
     834                 :            : 
     835                 :            :       // boundary integrals: compute fluxes in edges
     836         [ +  - ]:      43740 :       std::vector< real > bflux( triinpoel.size() * m_ncomp * 2 );
     837                 :            : 
     838         [ +  + ]:    1460670 :       for (std::size_t e=0; e<triinpoel.size()/3; ++e) {
     839                 :            :         // access node IDs
     840                 :            :         std::array< std::size_t, 3 >
     841                 :    1438800 :           N{ triinpoel[e*3+0], triinpoel[e*3+1], triinpoel[e*3+2] };
     842                 :            :         // apply symmetry BCs
     843         [ +  + ]:    1438800 :         if (symbctri[e]) continue;
     844                 :            :         // node coordinates
     845                 :      91500 :         std::array< tk::real, 3 > xp{ x[N[0]], x[N[1]], x[N[2]] },
     846                 :      91500 :                                   yp{ y[N[0]], y[N[1]], y[N[2]] },
     847                 :      91500 :                                   zp{ z[N[0]], z[N[1]], z[N[2]] };
     848                 :            :         // access solution at element nodes
     849         [ +  - ]:     183000 :         std::vector< std::array< real, 3 > > u( m_ncomp );
     850 [ +  + ][ +  - ]:     183000 :         for (ncomp_t c=0; c<m_ncomp; ++c) u[c] = U.extract( c, m_offset, N );
     851                 :            :         // evaluate prescribed velocity
     852                 :      91500 :         auto v =
     853         [ +  - ]:      91500 :           Problem::prescribedVelocity( m_system, m_ncomp, xp[0], yp[0], zp[0],
     854                 :            :             0.0 );
     855                 :            :         // compute face area
     856                 :      91500 :         auto A6 = tk::area( x[N[0]], x[N[1]], x[N[2]],
     857                 :            :                             y[N[0]], y[N[1]], y[N[2]],
     858                 :            :                             z[N[0]], z[N[1]], z[N[2]] ) / 6.0;
     859                 :      91500 :         auto A24 = A6/4.0;
     860                 :            :         // compute face normal
     861         [ +  - ]:      91500 :         auto n = tk::normal( xp, yp, zp );
     862                 :            :         // store flux in boundary elements
     863         [ +  + ]:     183000 :         for (std::size_t c=0; c<m_ncomp; ++c) {
     864                 :      91500 :           auto eb = (e*m_ncomp+c)*6;
     865                 :      91500 :           auto vdotn = tk::dot( v[c], n );
     866                 :      91500 :           auto Bab = A24 * vdotn * (u[c][0] + u[c][1]);
     867                 :      91500 :           bflux[eb+0] = Bab + A6 * vdotn * u[c][0];
     868                 :      91500 :           bflux[eb+1] = Bab;
     869                 :      91500 :           Bab = A24 * vdotn * (u[c][1] + u[c][2]);
     870                 :      91500 :           bflux[eb+2] = Bab + A6 * vdotn * u[c][1];
     871                 :      91500 :           bflux[eb+3] = Bab;
     872                 :      91500 :           Bab = A24 * vdotn * (u[c][2] + u[c][0]);
     873                 :      91500 :           bflux[eb+4] = Bab + A6 * vdotn * u[c][2];
     874                 :      91500 :           bflux[eb+5] = Bab;
     875                 :            :         }
     876                 :            :       }
     877                 :            : 
     878                 :            :       // access pointer to right hand side at component and offset
     879         [ +  - ]:      43740 :       std::vector< const real* > r( m_ncomp );
     880 [ +  + ][ +  - ]:      43740 :       for (ncomp_t c=0; c<m_ncomp; ++c) r[c] = R.cptr( c, m_offset );
     881                 :            : 
     882                 :            :       // boundary integrals: sum flux contributions to points
     883         [ +  + ]:    1460670 :       for (std::size_t e=0; e<triinpoel.size()/3; ++e) {
     884                 :    1438800 :         std::size_t N[3] =
     885                 :    1438800 :           { triinpoel[e*3+0], triinpoel[e*3+1], triinpoel[e*3+2] };
     886         [ +  + ]:    2877600 :         for (std::size_t c=0; c<m_ncomp; ++c) {
     887                 :    1438800 :           auto eb = (e*m_ncomp+c)*6;
     888         [ +  - ]:    1438800 :           R.var(r[c],N[0]) -= bflux[eb+0] + bflux[eb+5];
     889         [ +  - ]:    1438800 :           R.var(r[c],N[1]) -= bflux[eb+1] + bflux[eb+2];
     890         [ +  - ]:    1438800 :           R.var(r[c],N[2]) -= bflux[eb+3] + bflux[eb+4];
     891                 :            :         }
     892                 :            :       }
     893                 :            : 
     894                 :      21870 :       tk::destroy(bflux);
     895                 :      21870 :     }
     896                 :            : };
     897                 :            : 
     898                 :            : } // cg::
     899                 :            : } // inciter::
     900                 :            : 
     901                 :            : #endif // Transport_h

Generated by: LCOV version 1.14