Xyst test code coverage report
Current view: top level - Physics - Lax.cpp (source / functions) Hit Total Coverage
Commit: 5689ba12dc66a776d3d75f1ee48cc7d78eaa18dc Lines: 348 401 86.8 %
Date: 2024-11-22 19:02:53 Functions: 11 12 91.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 111 170 65.3 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/Physics/Lax.cpp
       4                 :            :   \copyright 2012-2015 J. Bakosi,
       5                 :            :              2016-2018 Los Alamos National Security, LLC.,
       6                 :            :              2019-2021 Triad National Security, LLC.,
       7                 :            :              2022-2024 J. Bakosi
       8                 :            :              All rights reserved. See the LICENSE file for details.
       9                 :            :   \brief     LaxCG: Time-derivative preconditioning for all Ma
      10                 :            :   \see       Luo, Baum, Lohner, "Extension of Harten-Lax-van Leer Scheme for
      11                 :            :              Flows at All Speeds", AIAA Journal, Vol. 43, No. 6, 2005
      12                 :            :   \see       Weiss & Smith, "Preconditioning Applied to Variable and Constant
      13                 :            :              Density Time-Accurate Flows on Unstructured Meshes", AIAA Journal,
      14                 :            :              Vol. 33, No. 11, 1995, pp. 2050-2057.
      15                 :            : */
      16                 :            : // *****************************************************************************
      17                 :            : 
      18                 :            : #include "Vector.hpp"
      19                 :            : #include "Around.hpp"
      20                 :            : #include "DerivedData.hpp"
      21                 :            : #include "EOS.hpp"
      22                 :            : #include "Lax.hpp"
      23                 :            : #include "Problems.hpp"
      24                 :            : #include "InciterConfig.hpp"
      25                 :            : 
      26                 :            : namespace inciter {
      27                 :            : 
      28                 :            : extern ctr::Config g_cfg;
      29                 :            : 
      30                 :            : } // ::inciter
      31                 :            : 
      32                 :            : namespace lax {
      33                 :            : 
      34                 :            : static const tk::real muscl_eps = 1.0e-9;
      35                 :            : static const tk::real muscl_const = 1.0/3.0;
      36                 :            : 
      37                 :            : using inciter::g_cfg;
      38                 :            : 
      39                 :            : static void
      40                 :   14957220 : muscl( std::size_t p,
      41                 :            :        std::size_t q,
      42                 :            :        const tk::UnsMesh::Coords& coord,
      43                 :            :        const tk::Fields& G,
      44                 :            :        tk::real& pL, tk::real& uL, tk::real& vL, tk::real& wL, tk::real& tL,
      45                 :            :        tk::real& pR, tk::real& uR, tk::real& vR, tk::real& wR, tk::real& tR )
      46                 :            : // *****************************************************************************
      47                 :            : //! Compute MUSCL reconstruction in edge-end points for the flow variables
      48                 :            : //! \param[in] p Left node id of edge-end
      49                 :            : //! \param[in] q Right node id of edge-end
      50                 :            : //! \param[in] coord Array of nodal coordinates
      51                 :            : //! \param[in] G Gradient of all unknowns in mesh points
      52                 :            : //! \param[in,out] pL Left pressure
      53                 :            : //! \param[in,out] uL Left X velocity
      54                 :            : //! \param[in,out] vL Left Y velocity
      55                 :            : //! \param[in,out] wL Left Z velocity
      56                 :            : //! \param[in,out] tL Left temperature
      57                 :            : //! \param[in,out] pR Right pressure
      58                 :            : //! \param[in,out] uR Right X velocity
      59                 :            : //! \param[in,out] vR Right Y velocity
      60                 :            : //! \param[in,out] wR Right Z velocity
      61                 :            : //! \param[in,out] tR Right temperature
      62                 :            : // *****************************************************************************
      63                 :            : {
      64                 :            :   // access node coordinates
      65                 :            :   const auto& x = coord[0];
      66                 :            :   const auto& y = coord[1];
      67                 :            :   const auto& z = coord[2];
      68                 :            : 
      69                 :            :   // edge vector
      70                 :   14957220 :   tk::real vw[3] = { x[q]-x[p], y[q]-y[p], z[q]-z[p] };
      71                 :            : 
      72                 :            :   tk::real delta1[5], delta2[5], delta3[5];
      73                 :   14957220 :   tk::real ls[5] = { pL, uL, vL, wL, tL },
      74                 :   14957220 :            rs[5] = { pR, uR, vR, wR, tR },
      75                 :            :            url[5], urr[5];
      76                 :   14957220 :   memcpy( url, ls, sizeof ls );
      77                 :   14957220 :   memcpy( urr, rs, sizeof rs );
      78                 :            : 
      79                 :            :   // MUSCL reconstruction of edge-end-point primitive variables
      80         [ +  + ]:   89743320 :   for (std::size_t c=0; c<5; ++c) {
      81                 :            : 
      82                 :   74786100 :     auto g1 = G(p,c*3+0)*vw[0] + G(p,c*3+1)*vw[1] + G(p,c*3+2)*vw[2];
      83                 :   74786100 :     auto g2 = G(q,c*3+0)*vw[0] + G(q,c*3+1)*vw[1] + G(q,c*3+2)*vw[2];
      84                 :            : 
      85                 :   74786100 :     delta2[c] = rs[c] - ls[c];
      86                 :   74786100 :     delta1[c] = 2.0 * g1 - delta2[c];
      87                 :   74786100 :     delta3[c] = 2.0 * g2 - delta2[c];
      88                 :            : 
      89                 :            :     // MUSCL extrapolation option 1:
      90                 :            :     // ---------------------------------------------------------------------
      91                 :            :     // See Waltz, J., Morgan, N. R., Canfield, T. R., Charest, M. R., Risinger,
      92                 :            :     // L. D., & Wohlbier, J. G. (2014). A three-dimensional finite element
      93                 :            :     // arbitrary Lagrangian–Eulerian method for shock hydrodynamics on
      94                 :            :     // unstructured grids. Computers & Fluids, 92, 172-187.
      95                 :            : 
      96                 :            :     // van Leer limiter
      97                 :   74786100 :     auto rcL = (delta2[c] + muscl_eps) / (delta1[c] + muscl_eps);
      98                 :   74786100 :     auto rcR = (delta2[c] + muscl_eps) / (delta3[c] + muscl_eps);
      99                 :   74786100 :     auto rLinv = (delta1[c] + muscl_eps) / (delta2[c] + muscl_eps);
     100                 :   74786100 :     auto rRinv = (delta3[c] + muscl_eps) / (delta2[c] + muscl_eps);
     101                 :   74786100 :     auto phiL = (std::abs(rcL) + rcL) / (std::abs(rcL) + 1.0);
     102                 :   74786100 :     auto phiR = (std::abs(rcR) + rcR) / (std::abs(rcR) + 1.0);
     103                 :   74786100 :     auto phi_L_inv = (std::abs(rLinv) + rLinv) / (std::abs(rLinv) + 1.0);
     104                 :   74786100 :     auto phi_R_inv = (std::abs(rRinv) + rRinv) / (std::abs(rRinv) + 1.0);
     105                 :            :     // update unknowns with reconstructed unknowns
     106                 :   74786100 :     url[c] += 0.25*(delta1[c]*(1.0-muscl_const)*phiL +
     107                 :   74786100 :                     delta2[c]*(1.0+muscl_const)*phi_L_inv);
     108                 :   74786100 :     urr[c] -= 0.25*(delta3[c]*(1.0-muscl_const)*phiR +
     109                 :   74786100 :                     delta2[c]*(1.0+muscl_const)*phi_R_inv);
     110                 :            : 
     111                 :            :     // MUSCL extrapolation option 2:
     112                 :            :     // ---------------------------------------------------------------------
     113                 :            :     // See Luo, H., Baum, J. D., & Lohner, R. (1994). Edge-based finite element
     114                 :            :     // scheme for the Euler equations. AIAA journal, 32(6), 1183-1190.
     115                 :            :     // van Leer, B. (1974). Towards the ultimate conservative difference
     116                 :            :     // scheme. II. Monotonicity and conservation combined in a second-order
     117                 :            :     // scheme. Journal of computational physics, 14(4), 361-370.
     118                 :            :     // Derived from the flux limiter phi as: s = phi_inv - (1 - phi)
     119                 :            : 
     120                 :            :     // van Albada limiter
     121                 :            :     //auto sL = std::max(0.0, (2.0*delta1[c]*delta2[c] + muscl_eps)
     122                 :            :     //  /(delta1[c]*delta1[c] + delta2[c]*delta2[c] + muscl_eps));
     123                 :            :     //auto sR = std::max(0.0, (2.0*delta3[c]*delta2[c] + muscl_eps)
     124                 :            :     //  /(delta3[c]*delta3[c] + delta2[c]*delta2[c] + muscl_eps));
     125                 :            :     //// update unknowns with reconstructed unknowns
     126                 :            :     //url[c] += 0.25*sL*(delta1[c]*(1.0 - muscl_const*sL)
     127                 :            :     //                 + delta2[c]*(1.0 + muscl_const*sL));
     128                 :            :     //urr[c] -= 0.25*sR*(delta3[c]*(1.0 - muscl_const*sR)
     129                 :            :     //                 + delta2[c]*(1.0 + muscl_const*sR));
     130                 :            :   }
     131                 :            : 
     132                 :            :   // force first order if the reconstructions for pressure or temperature
     133                 :            :   // would have allowed negative values
     134 [ +  - ][ -  + ]:   14957220 :   if (ls[0] < delta1[0] || ls[4] < delta1[4]) memcpy( url, ls, sizeof ls );
     135 [ +  - ][ -  + ]:   14957220 :   if (rs[0] < -delta3[0] || rs[4] < -delta3[4]) memcpy( urr, rs, sizeof rs );
     136                 :            : 
     137                 :   14957220 :   pL = url[0];
     138                 :   14957220 :   uL = url[1];
     139                 :   14957220 :   vL = url[2];
     140                 :   14957220 :   wL = url[3];
     141                 :   14957220 :   tL = url[4];
     142                 :            : 
     143                 :   14957220 :   pR = urr[0];
     144                 :   14957220 :   uR = urr[1];
     145                 :   14957220 :   vR = urr[2];
     146                 :   14957220 :   wR = urr[3];
     147                 :   14957220 :   tR = urr[4];
     148                 :   14957220 : }
     149                 :            : 
     150                 :            : static void
     151                 :          0 : muscl( std::size_t p, std::size_t q, const tk::UnsMesh::Coords& coord,
     152                 :            :        const tk::Fields& G, tk::real uL[], tk::real uR[] )
     153                 :            : // *****************************************************************************
     154                 :            : //! Compute MUSCL reconstruction in edge-end points for transported scalars
     155                 :            : //! \param[in] p Left node id of edge-end
     156                 :            : //! \param[in] q Right node id of edge-end
     157                 :            : //! \param[in] coord Array of nodal coordinates
     158                 :            : //! \param[in] G Gradient of all unknowns in mesh points
     159                 :            : //! \param[in,out] uL Primitive variables at left edge-end point
     160                 :            : //! \param[in,out] uR Primitive variables at right edge-end point
     161                 :            : // *****************************************************************************
     162                 :            : {
     163                 :            :   #if defined(__clang__)
     164                 :            :     #pragma clang diagnostic push
     165                 :            :     #pragma clang diagnostic ignored "-Wvla"
     166                 :            :     #pragma clang diagnostic ignored "-Wvla-extension"
     167                 :            :   #elif defined(STRICT_GNUC)
     168                 :            :     #pragma GCC diagnostic push
     169                 :            :     #pragma GCC diagnostic ignored "-Wvla"
     170                 :            :   #endif
     171                 :            : 
     172                 :          0 :   auto ns = G.nprop() / 3 - 5;
     173                 :            : 
     174                 :            :   const auto& x = coord[0];
     175                 :            :   const auto& y = coord[1];
     176                 :            :   const auto& z = coord[2];
     177                 :            : 
     178                 :            :   // edge vector
     179                 :          0 :   tk::real vw[3] = { x[q]-x[p], y[q]-y[p], z[q]-z[p] };
     180                 :            : 
     181                 :          0 :   tk::real delta1[ns], delta2[ns], delta3[ns];
     182                 :            : 
     183                 :            :   // MUSCL reconstruction of edge-end-point primitive variables
     184         [ -  - ]:          0 :   for (std::size_t c=0; c<ns; ++c) {
     185                 :          0 :     auto g = (5+c)*3;
     186                 :          0 :     auto g1 = G(p,g+0)*vw[0] + G(p,g+1)*vw[1] + G(p,g+2)*vw[2];
     187                 :          0 :     auto g2 = G(q,g+0)*vw[0] + G(q,g+1)*vw[1] + G(q,g+2)*vw[2];
     188                 :            : 
     189                 :          0 :     delta2[c] = uR[5+c] - uL[5+c];
     190                 :          0 :     delta1[c] = 2.0 * g1 - delta2[c];
     191                 :          0 :     delta3[c] = 2.0 * g2 - delta2[c];
     192                 :            : 
     193                 :            :     // van Leer limiter
     194                 :          0 :     auto rL = (delta2[c] + muscl_eps) / (delta1[c] + muscl_eps);
     195                 :          0 :     auto rR = (delta2[c] + muscl_eps) / (delta3[c] + muscl_eps);
     196                 :          0 :     auto rLinv = (delta1[c] + muscl_eps) / (delta2[c] + muscl_eps);
     197                 :          0 :     auto rRinv = (delta3[c] + muscl_eps) / (delta2[c] + muscl_eps);
     198                 :          0 :     auto phiL = (std::abs(rL) + rL) / (std::abs(rL) + 1.0);
     199                 :          0 :     auto phiR = (std::abs(rR) + rR) / (std::abs(rR) + 1.0);
     200                 :          0 :     auto phi_L_inv = (std::abs(rLinv) + rLinv) / (std::abs(rLinv) + 1.0);
     201                 :          0 :     auto phi_R_inv = (std::abs(rRinv) + rRinv) / (std::abs(rRinv) + 1.0);
     202                 :            :     // update unknowns with reconstructed unknowns
     203                 :          0 :     uL[5+c] += 0.25*(delta1[c]*(1.0-muscl_const)*phiL +
     204                 :          0 :                      delta2[c]*(1.0+muscl_const)*phi_L_inv);
     205                 :          0 :     uR[5+c] -= 0.25*(delta3[c]*(1.0-muscl_const)*phiR +
     206                 :          0 :                      delta2[c]*(1.0+muscl_const)*phi_R_inv);
     207                 :            :   }
     208                 :            : 
     209                 :            :   #if defined(__clang__)
     210                 :            :     #pragma clang diagnostic pop
     211                 :            :   #elif defined(STRICT_GNUC)
     212                 :            :     #pragma GCC diagnostic pop
     213                 :            :   #endif
     214                 :          0 : }
     215                 :            : 
     216                 :            : void
     217                 :      10200 : grad( const std::array< std::vector< std::size_t >, 3 >& dsupedge,
     218                 :            :       const std::array< std::vector< tk::real >, 3 >& dsupint,
     219                 :            :       const std::array< std::vector< tk::real >, 3 >& coord,
     220                 :            :       const std::vector< std::size_t >& triinpoel,
     221                 :            :       const tk::Fields& U,
     222                 :            :       tk::Fields& G )
     223                 :            : // *****************************************************************************
     224                 :            : //  Compute nodal gradients of primitive variables in all points
     225                 :            : //! \param[in] dsupedge Domain superedges
     226                 :            : //! \param[in] dsupint Domain superedge integrals
     227                 :            : //! \param[in] coord Mesh node coordinates
     228                 :            : //! \param[in] triinpoel Boundary face connectivity
     229                 :            : //! \param[in] U Solution vector of primitive variables at recent time step
     230                 :            : //! \param[in,out] G Nodal gradients
     231                 :            : //! \return Gradients of primitive variables in all mesh points
     232                 :            : // *****************************************************************************
     233                 :            : {
     234                 :            :   #if defined(__clang__)
     235                 :            :     #pragma clang diagnostic push
     236                 :            :     #pragma clang diagnostic ignored "-Wvla"
     237                 :            :     #pragma clang diagnostic ignored "-Wvla-extension"
     238                 :            :   #elif defined(STRICT_GNUC)
     239                 :            :     #pragma GCC diagnostic push
     240                 :            :     #pragma GCC diagnostic ignored "-Wvla"
     241                 :            :   #endif
     242                 :            : 
     243                 :            :   // cppcheck-suppress unreadVariable
     244                 :            :   auto ncomp = U.nprop();
     245                 :            : 
     246                 :            :   Assert( G.nunk() == U.nunk(), "Size mismatch" );
     247                 :            :   Assert( G.nprop() == ncomp*3, "Size mismatch" );
     248                 :            :   G.fill( 0.0 );
     249                 :            : 
     250                 :            :   // domain integral
     251                 :            : 
     252                 :            :   // domain edge contributions: tetrahedron superedges
     253         [ +  + ]:    1603650 :   for (std::size_t e=0; e<dsupedge[0].size()/4; ++e) {
     254                 :    1593450 :     const auto N = dsupedge[0].data() + e*4;
     255         [ +  + ]:    9560700 :     for (std::size_t c=0; c<ncomp; ++c) {
     256                 :    7967250 :       tk::real u[] = { U(N[0],c), U(N[1],c), U(N[2],c), U(N[3],c) };
     257         [ +  + ]:   31869000 :       for (std::size_t j=0; j<3; ++j) {
     258                 :            :         tk::real f[6];
     259                 :            :         const auto d = dsupint[0].data();
     260                 :   23901750 :         f[0] = d[(e*6+0)*3+j] * (u[1] + u[0]);
     261                 :   23901750 :         f[1] = d[(e*6+1)*3+j] * (u[2] + u[1]);
     262                 :   23901750 :         f[2] = d[(e*6+2)*3+j] * (u[0] + u[2]);
     263                 :   23901750 :         f[3] = d[(e*6+3)*3+j] * (u[3] + u[0]);
     264                 :   23901750 :         f[4] = d[(e*6+4)*3+j] * (u[3] + u[1]);
     265                 :   23901750 :         f[5] = d[(e*6+5)*3+j] * (u[3] + u[2]);
     266                 :   23901750 :         G(N[0],c*3+j) = G(N[0],c*3+j) - f[0] + f[2] - f[3];
     267                 :   23901750 :         G(N[1],c*3+j) = G(N[1],c*3+j) + f[0] - f[1] - f[4];
     268                 :   23901750 :         G(N[2],c*3+j) = G(N[2],c*3+j) + f[1] - f[2] - f[5];
     269                 :   23901750 :         G(N[3],c*3+j) = G(N[3],c*3+j) + f[3] + f[4] + f[5];
     270                 :            :       }
     271                 :            :     }
     272                 :            :   }
     273                 :            : 
     274                 :            :   // domain edge contributions: triangle superedges
     275         [ +  + ]:     693990 :   for (std::size_t e=0; e<dsupedge[1].size()/3; ++e) {
     276                 :     683790 :     const auto N = dsupedge[1].data() + e*3;
     277         [ +  + ]:    4102740 :     for (std::size_t c=0; c<ncomp; ++c) {
     278                 :    3418950 :       tk::real u[] = { U(N[0],c), U(N[1],c), U(N[2],c) };
     279         [ +  + ]:   13675800 :       for (std::size_t j=0; j<3; ++j) {
     280                 :            :         tk::real f[3];
     281                 :            :         const auto d = dsupint[1].data();
     282                 :   10256850 :         f[0] = d[(e*3+0)*3+j] * (u[1] + u[0]);
     283                 :   10256850 :         f[1] = d[(e*3+1)*3+j] * (u[2] + u[1]);
     284                 :   10256850 :         f[2] = d[(e*3+2)*3+j] * (u[0] + u[2]);
     285                 :   10256850 :         G(N[0],c*3+j) = G(N[0],c*3+j) - f[0] + f[2];
     286                 :   10256850 :         G(N[1],c*3+j) = G(N[1],c*3+j) + f[0] - f[1];
     287                 :   10256850 :         G(N[2],c*3+j) = G(N[2],c*3+j) + f[1] - f[2];
     288                 :            :       }
     289                 :            :     }
     290                 :            :   }
     291                 :            : 
     292                 :            :   // domain edge contributions: edges
     293         [ +  + ]:    3355350 :   for (std::size_t e=0; e<dsupedge[2].size()/2; ++e) {
     294                 :    3345150 :     const auto N = dsupedge[2].data() + e*2;
     295                 :    3345150 :     const auto d = dsupint[2].data() + e*3;
     296         [ +  + ]:   20070900 :     for (std::size_t c=0; c<ncomp; ++c) {
     297                 :   16725750 :       tk::real u[] = { U(N[0],c), U(N[1],c) };
     298         [ +  + ]:   66903000 :       for (std::size_t j=0; j<3; ++j) {
     299                 :   50177250 :         tk::real f = d[j] * (u[1] + u[0]);
     300                 :   50177250 :         G(N[0],c*3+j) -= f;
     301                 :   50177250 :         G(N[1],c*3+j) += f;
     302                 :            :       }
     303                 :            :     }
     304                 :            :   }
     305                 :            : 
     306                 :            :   // boundary integral
     307                 :            : 
     308                 :            :   const auto& x = coord[0];
     309                 :            :   const auto& y = coord[1];
     310                 :            :   const auto& z = coord[2];
     311                 :            : 
     312         [ +  + ]:    1385760 :   for (std::size_t e=0; e<triinpoel.size()/3; ++e) {
     313                 :    1375560 :     const auto N = triinpoel.data() + e*3;
     314                 :            :     const std::array< tk::real, 3 >
     315                 :    1375560 :       ba{ x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]] },
     316                 :    1375560 :       ca{ x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]] };
     317                 :            :     auto n = tk::cross( ba, ca );
     318                 :    1375560 :     n[0] /= 12.0;
     319                 :    1375560 :     n[1] /= 12.0;
     320                 :    1375560 :     n[2] /= 12.0;
     321         [ +  + ]:    8253360 :     for (std::size_t c=0; c<ncomp; ++c) {
     322                 :    6877800 :       tk::real u[] = { U(N[0],c), U(N[1],c), U(N[2],c) };
     323                 :    6877800 :       auto uab = (u[0] + u[1])/4.0;
     324                 :    6877800 :       auto ubc = (u[1] + u[2])/4.0;
     325                 :    6877800 :       auto uca = (u[2] + u[0])/4.0;
     326                 :    6877800 :       tk::real g[] = { uab + uca + u[0],
     327                 :    6877800 :                        uab + ubc + u[1],
     328                 :    6877800 :                        ubc + uca + u[2] };
     329         [ +  + ]:   27511200 :       for (std::size_t j=0; j<3; ++j) {
     330                 :   20633400 :         G(N[0],c*3+j) += g[j] * n[j];
     331                 :   20633400 :         G(N[1],c*3+j) += g[j] * n[j];
     332                 :   20633400 :         G(N[2],c*3+j) += g[j] * n[j];
     333                 :            :       }
     334                 :            :     }
     335                 :            :   }
     336                 :            : 
     337                 :            :   #if defined(__clang__)
     338                 :            :     #pragma clang diagnostic pop
     339                 :            :   #elif defined(STRICT_GNUC)
     340                 :            :     #pragma GCC diagnostic pop
     341                 :            :   #endif
     342                 :      10200 : }
     343                 :            : 
     344                 :            : tk::real
     345                 :   33294340 : refvel( tk::real r, tk::real p, tk::real v )
     346                 :            : // *****************************************************************************
     347                 :            : //  Compute reference velocitity of the preconditioned system
     348                 :            : //! \param[in] r Density
     349                 :            : //! \param[in] p Pressure
     350                 :            : //! \param[in] v Velocity magnitude
     351                 :            : //! \return Reference velocity
     352                 :            : // *****************************************************************************
     353                 :            : {
     354                 :   33294340 :   auto K = g_cfg.get< tag::turkel >();
     355                 :   33294340 :   auto velinf = g_cfg.get< tag::velinf >();
     356         [ +  + ]:   33294340 :   auto vinf = tk::length( velinf[0], velinf[1], velinf[2] );
     357                 :            : 
     358 [ +  + ][ +  - ]:   68474060 :   return std::min( eos::soundspeed( r, p ), std::max( v, K*vinf ) );
     359                 :            :   //return eos::soundspeed( r, p );
     360                 :            : }
     361                 :            : 
     362                 :            : static std::tuple< tk::real, tk::real >
     363                 :   29914440 : sigvel( tk::real p, tk::real T, tk::real v, tk::real vn )
     364                 :            : // *****************************************************************************
     365                 :            : //  Compute signal velocitities of the preconditioned system
     366                 :            : //! \param[in] p Pressure
     367                 :            : //! \param[in] T Temperature
     368                 :            : //! \param[in] v Velocity magnitude
     369                 :            : //! \param[in] vn Face-normal velocity
     370                 :            : //! \return v', c'
     371                 :            : // *****************************************************************************
     372                 :            : {
     373                 :   29914440 :   auto g = g_cfg.get< tag::mat_spec_heat_ratio >();
     374                 :   29914440 :   auto rgas = g_cfg.get< tag::mat_spec_gas_const >();
     375                 :   29914440 :   auto cp = g*rgas/(g-1.0);
     376                 :            : 
     377                 :   29914440 :   auto r = p/T/rgas;
     378                 :   29914440 :   auto rp = r/p;
     379                 :   29914440 :   auto rt = -r/T;
     380                 :   29914440 :   auto vr = refvel( r, p, v );
     381                 :   29914440 :   auto vr2 = vr*vr;
     382                 :   29914440 :   auto beta = rp + rt/r/cp;
     383                 :   29914440 :   auto alpha = 0.5*(1.0 - beta*vr2);
     384                 :   29914440 :   auto vpri = vn*(1.0 - alpha);
     385                 :   29914440 :   auto cpri = std::sqrt( alpha*alpha*vn*vn + vr2 );
     386                 :            : 
     387                 :   29914440 :   return { vpri, cpri };
     388                 :            : }
     389                 :            : 
     390                 :            : static void
     391                 :   10333320 : rusanov( const tk::UnsMesh::Coords& coord,
     392                 :            :          const tk::Fields& G,
     393                 :            :          const tk::real dsupint[],
     394                 :            :          std::size_t p,
     395                 :            :          std::size_t q,
     396                 :            :          const tk::real L[],
     397                 :            :          const tk::real R[],
     398                 :            :          tk::real f[] )
     399                 :            : // *****************************************************************************
     400                 :            : //! Compute advection fluxes on a single edge with Rusanov's flux
     401                 :            : //! \param[in] coord Mesh node coordinates
     402                 :            : //! \param[in] G Nodal gradients
     403                 :            : //! \param[in] dsupint Domain superedge integral for this edge
     404                 :            : //! \param[in] p Left node index of edge
     405                 :            : //! \param[in] q Right node index of edge
     406                 :            : //! \param[in,out] L Left physics state variables
     407                 :            : //! \param[in,out] R Rigth physics state variables
     408                 :            : //! \param[in,out] f Flux computed
     409                 :            : // *****************************************************************************
     410                 :            : {
     411                 :   10333320 :   auto ncomp = G.nprop() / 3;
     412                 :            : 
     413                 :            :   #if defined(__clang__)
     414                 :            :     #pragma clang diagnostic push
     415                 :            :     #pragma clang diagnostic ignored "-Wvla"
     416                 :            :     #pragma clang diagnostic ignored "-Wvla-extension"
     417                 :            :   #elif defined(STRICT_GNUC)
     418                 :            :     #pragma GCC diagnostic push
     419                 :            :     #pragma GCC diagnostic ignored "-Wvla"
     420                 :            :   #endif
     421                 :            : 
     422                 :            :   // will work on copies of physics variables
     423                 :   10333320 :   tk::real l[ncomp], r[ncomp];
     424                 :   10333320 :   memcpy( l, L, sizeof l );
     425                 :   10333320 :   memcpy( r, R, sizeof r );
     426                 :            : 
     427                 :            :   // MUSCL reconstruction in edge-end points for flow variables
     428                 :   10333320 :   muscl( p, q, coord, G, l[0], l[1], l[2], l[3], l[4],
     429                 :   10333320 :                          r[0], r[1], r[2], r[3], r[4] );
     430                 :            : 
     431                 :            :   // dualface-normal velocities
     432                 :   10333320 :   auto nx = dsupint[0];
     433                 :   10333320 :   auto ny = dsupint[1];
     434                 :   10333320 :   auto nz = dsupint[2];
     435                 :   10333320 :   auto vnL = l[1]*nx + l[2]*ny + l[3]*nz;
     436                 :   10333320 :   auto vnR = r[1]*nx + r[2]*ny + r[3]*nz;
     437                 :            : 
     438                 :            :   // pressure
     439                 :   10333320 :   auto pL = l[0];
     440                 :   10333320 :   auto pR = r[0];
     441                 :            : 
     442                 :            :   // preconditioned wave speed
     443                 :            :   auto len = tk::length( nx, ny, nz );
     444                 :   10333320 :   auto [vpL, cpL] = sigvel( l[0], l[4], tk::length(l[1],l[2],l[3]), vnL );
     445                 :   10333320 :   auto [vpR, cpR] = sigvel( r[0], r[4], tk::length(r[1],r[2],r[3]), vnR );
     446                 :            : 
     447                 :            :   // convert to conserved variables
     448                 :   10333320 :   auto g = g_cfg.get< tag::mat_spec_heat_ratio >();
     449                 :   10333320 :   auto rgas = g_cfg.get< tag::mat_spec_gas_const >();
     450                 :   10333320 :   l[0] = pL/l[4]/rgas;
     451                 :   10333320 :   l[1] *= l[0];
     452                 :   10333320 :   l[2] *= l[0];
     453                 :   10333320 :   l[3] *= l[0];
     454                 :   10333320 :   l[4] = pL/(g-1.0) + 0.5*(l[1]*l[1] + l[2]*l[2] + l[3]*l[3])/l[0];
     455                 :   10333320 :   r[0] = pR/r[4]/rgas;
     456                 :   10333320 :   r[1] *= r[0];
     457                 :   10333320 :   r[2] *= r[0];
     458                 :   10333320 :   r[3] *= r[0];
     459                 :   10333320 :   r[4] = pR/(g-1.0) + 0.5*(r[1]*r[1] + r[2]*r[2] + r[3]*r[3])/r[0];
     460                 :            : 
     461                 :            :   // dissipation: option 1
     462                 :            :   //auto sL = std::abs(vpL) + cpL;
     463                 :            :   //auto sR = std::abs(vpR) + cpR;
     464                 :            :   //auto fw = std::max( sL, sR ) * len;
     465                 :            : 
     466                 :            :   // dissipation: option 2
     467                 :            :   using std::abs;
     468                 :            :   using std::max;
     469 [ +  + ][ +  + ]:   19342253 :   auto sp = max(abs(vpL-cpL),max(abs(vpR-cpR),max(abs(vpL+cpL),abs(vpR+cpR))));
                 [ +  + ]
     470                 :   10333320 :   auto sL = -sp;
     471         [ +  - ]:   10333320 :   auto sR = +sp;
     472                 :   10333320 :   auto fw = std::max( sL, sR ) * len;
     473                 :            : 
     474                 :            :   // flow fluxes
     475                 :   10333320 :   f[0] = l[0]*vnL + r[0]*vnR + fw*(r[0] - l[0]);
     476                 :   10333320 :   f[1] = l[1]*vnL + r[1]*vnR + (pL + pR)*nx + fw*(r[1] - l[1]);
     477                 :   10333320 :   f[2] = l[2]*vnL + r[2]*vnR + (pL + pR)*ny + fw*(r[2] - l[2]);
     478                 :   10333320 :   f[3] = l[3]*vnL + r[3]*vnR + (pL + pR)*nz + fw*(r[3] - l[3]);
     479                 :   10333320 :   f[4] = (l[4] + pL)*vnL + (r[4] + pR)*vnR + fw*(r[4] - l[4]);
     480                 :            : 
     481                 :            :   // artificial viscosity
     482                 :   10333320 :   const auto stab2 = g_cfg.get< tag::stab2 >();
     483         [ -  + ]:   10333320 :   if (stab2) {
     484                 :          0 :     auto stab2coef = g_cfg.get< tag::stab2coef >();
     485                 :          0 :     auto fws = stab2coef * fw;
     486                 :          0 :     f[0] -= fws*(l[0] - r[0]);
     487                 :          0 :     f[1] -= fws*(l[1] - r[1]);
     488                 :          0 :     f[2] -= fws*(l[2] - r[2]);
     489                 :          0 :     f[3] -= fws*(l[3] - r[3]);
     490                 :          0 :     f[4] -= fws*(l[4] - r[4]);
     491                 :            :   }
     492                 :            : 
     493         [ +  - ]:   10333320 :   if (ncomp == 5) return;
     494                 :            : 
     495                 :            :   // MUSCL reconstruction in edge-end points for scalars
     496                 :          0 :   muscl( p, q, coord, G, l, r );
     497                 :            : 
     498                 :            :   // scalar dissipation
     499         [ -  - ]:          0 :   auto sw = std::max( std::abs(vnL), std::abs(vnR) );
     500                 :            : 
     501                 :            :   // scalar fluxes
     502         [ -  - ]:          0 :   for (std::size_t c=5; c<ncomp; ++c) {
     503                 :          0 :     f[c] = l[c]*vnL + r[c]*vnR + sw*(r[c] - l[c]);
     504                 :            :   }
     505                 :            : 
     506                 :            :   #if defined(__clang__)
     507                 :            :     #pragma clang diagnostic pop
     508                 :            :   #elif defined(STRICT_GNUC)
     509                 :            :     #pragma GCC diagnostic pop
     510                 :            :   #endif
     511                 :   10333320 : }
     512                 :            : 
     513                 :            : static void
     514                 :    4623900 : hllc( const tk::UnsMesh::Coords& coord,
     515                 :            :       const tk::Fields& G,
     516                 :            :       const tk::real dsupint[],
     517                 :            :       std::size_t p,
     518                 :            :       std::size_t q,
     519                 :            :       const tk::real L[],
     520                 :            :       const tk::real R[],
     521                 :            :       tk::real f[] )
     522                 :            : // *****************************************************************************
     523                 :            : //! Compute advection fluxes on a single edge with Harten-Lax-vanLeer-Contact
     524                 :            : //! \param[in] coord Mesh node coordinates
     525                 :            : //! \param[in] G Nodal gradients
     526                 :            : //! \param[in] dsupint Domain superedge integral for this edge
     527                 :            : //! \param[in] p Left node index of edge
     528                 :            : //! \param[in] q Right node index of edge
     529                 :            : //! \param[in,out] L Left physics state variables
     530                 :            : //! \param[in,out] R Rigth physics state variables
     531                 :            : //! \param[in,out] f Flux computed
     532                 :            : //! \see Toro, Riemann Solver and Numerical Methods for Fluid Dynamics. 3rd
     533                 :            : //!      Edition, Springer, New York, 2009
     534                 :            : //! \see Davis, Simplified Second-Order Godunov-Type Methods, SIAM J. Sci. Stat.
     535                 :            : //!      Comput. 9:445-473, 1988
     536                 :            : //! \see Roe, Approximate Riemann Solvers, Parameter Vectors, and Difference
     537                 :            : //!      Schemes, J. Comput Phys., 43:357-372, 1981
     538                 :            : // *****************************************************************************
     539                 :            : {
     540                 :    4623900 :   auto ncomp = G.nprop() / 3;
     541                 :            : 
     542                 :            :   #if defined(__clang__)
     543                 :            :     #pragma clang diagnostic push
     544                 :            :     #pragma clang diagnostic ignored "-Wvla"
     545                 :            :     #pragma clang diagnostic ignored "-Wvla-extension"
     546                 :            :   #elif defined(STRICT_GNUC)
     547                 :            :     #pragma GCC diagnostic push
     548                 :            :     #pragma GCC diagnostic ignored "-Wvla"
     549                 :            :   #endif
     550                 :            : 
     551                 :            :   // will work on copies of physics variables
     552                 :    4623900 :   tk::real l[ncomp], r[ncomp];
     553                 :    4623900 :   memcpy( l, L, sizeof l );
     554                 :    4623900 :   memcpy( r, R, sizeof r );
     555                 :            : 
     556                 :            :   // MUSCL reconstruction in edge-end points for flow variables
     557                 :    4623900 :   muscl( p, q, coord, G, l[0], l[1], l[2], l[3], l[4],
     558                 :    4623900 :                          r[0], r[1], r[2], r[3], r[4] );
     559                 :            : 
     560                 :            :   // dualface-normal velocities
     561                 :    4623900 :   auto nx = -dsupint[0];
     562                 :    4623900 :   auto ny = -dsupint[1];
     563                 :    4623900 :   auto nz = -dsupint[2];
     564                 :            :   auto len = tk::length( nx, ny, nz );
     565                 :    4623900 :   nx /= len;
     566                 :    4623900 :   ny /= len;
     567                 :    4623900 :   nz /= len;
     568                 :    4623900 :   auto qL = l[1]*nx + l[2]*ny + l[3]*nz;
     569                 :    4623900 :   auto qR = r[1]*nx + r[2]*ny + r[3]*nz;
     570                 :            : 
     571                 :            :   // pressure
     572                 :    4623900 :   auto pL = l[0];
     573                 :    4623900 :   auto pR = r[0];
     574                 :            : 
     575                 :            :   // preconditioned signal velocities
     576                 :    4623900 :   auto [vpL, cpL] = sigvel( l[0], l[4], tk::length(l[1],l[2],l[3]), qL*len );
     577                 :    4623900 :   auto [vpR, cpR] = sigvel( r[0], r[4], tk::length(r[1],r[2],r[3]), qR*len );
     578                 :            : 
     579                 :            :   // convert to conserved variables
     580                 :    4623900 :   auto g = g_cfg.get< tag::mat_spec_heat_ratio >();
     581                 :    4623900 :   auto rgas = g_cfg.get< tag::mat_spec_gas_const >();
     582                 :    4623900 :   l[0] = pL/l[4]/rgas;
     583                 :    4623900 :   l[1] *= l[0];
     584                 :    4623900 :   l[2] *= l[0];
     585                 :    4623900 :   l[3] *= l[0];
     586                 :    4623900 :   l[4] = pL/(g-1.0) + 0.5*(l[1]*l[1] + l[2]*l[2] + l[3]*l[3])/l[0];
     587                 :    4623900 :   r[0] = pR/r[4]/rgas;
     588                 :    4623900 :   r[1] *= r[0];
     589                 :    4623900 :   r[2] *= r[0];
     590                 :    4623900 :   r[3] *= r[0];
     591                 :    4623900 :   r[4] = pR/(g-1.0) + 0.5*(r[1]*r[1] + r[2]*r[2] + r[3]*r[3])/r[0];
     592                 :            : 
     593                 :            :   // preconditioned left and right wave speeds
     594                 :            : 
     595                 :            :   // option 1
     596                 :            :   //auto sL = std::min( vpL - cpL, vpR - cpR );
     597                 :            :   //auto sR = std::max( vpL + cpL, vpR + cpR );
     598                 :            : 
     599                 :            :   // option 2
     600                 :            :   //auto sL = vpL - cpL;
     601                 :            :   //auto sR = vpR + cpR;
     602                 :            : 
     603                 :            :   // option 3
     604                 :            :   using std::abs;
     605                 :            :   using std::max;
     606 [ +  + ][ +  + ]:    9384125 :   auto sp = max(abs(vpL-cpL),max(abs(vpR-cpR),max(abs(vpL+cpL),abs(vpR+cpR))));
                 [ +  + ]
     607                 :    4623900 :   auto sL = -sp;
     608                 :            :   auto sR = +sp;
     609                 :            : 
     610                 :            :   //using std::sqrt;
     611                 :            :   //auto hl = (l[4]/l[0] + pL) / l[0];
     612                 :            :   //auto hr = (r[4]/r[0] + pR) / r[0];
     613                 :            :   //auto srl = sqrt( l[0] );
     614                 :            :   //auto srr = sqrt( r[0] );
     615                 :            :   //auto hh = (srl*hl + srr*hr) / (srl + srr);
     616                 :            :   //auto uh = (srl*vpL + srr*vpR) / (srl + srr);
     617                 :            :   //auto ch = sqrt( (g-1.0)*(hh - 0.5*(uh*uh)) );
     618                 :            :   //// option 4
     619                 :            :   //auto sL = std::min( vpL - cpL, uh - ch );
     620                 :            :   //auto sR = std::max( vpR + cpR, uh + ch );
     621                 :            :   // option 5
     622                 :            :   //auto sL = uh - ch;
     623                 :            :   //auto sR = uh + ch;
     624                 :            : 
     625                 :            :   // no preconditioning
     626                 :            :   //auto cL = eos::soundspeed(l[0],pL);
     627                 :            :   //auto cR = eos::soundspeed(r[0],pR);
     628                 :            :   //auto sL = fmin( qL - cL, qR - cR );
     629                 :            :   //auto sR = fmax( qL + cL, qR + cR );
     630                 :            : 
     631                 :            :   // contact wave speed and pressure
     632                 :    4623900 :   auto tL = sL - qL;
     633                 :    4623900 :   auto tR = sR - qR;
     634                 :    4623900 :   auto sM = (r[0]*qR*tR - l[0]*qL*tL + pL - pR) / (r[0]*tR - l[0]*tL);
     635                 :    4623900 :   auto pS = pL - l[0]*tL*(qL - sM);
     636                 :            : 
     637                 :            :   // intermediate left-, and right-state conserved unknowns
     638                 :    4623900 :   tk::real uL[ncomp], uR[ncomp];
     639                 :    4623900 :   auto s = sL - sM;
     640                 :    4623900 :   uL[0] = tL*l[0]/s;
     641                 :    4623900 :   uL[1] = (tL*l[1] + (pS-pL)*nx)/s;
     642                 :    4623900 :   uL[2] = (tL*l[2] + (pS-pL)*ny)/s;
     643                 :    4623900 :   uL[3] = (tL*l[3] + (pS-pL)*nz)/s;
     644                 :    4623900 :   uL[4] = (tL*l[4] - pL*qL + pS*sM)/s;
     645                 :    4623900 :   s = sR - sM;
     646                 :    4623900 :   uR[0] = tR*r[0]/s;
     647                 :    4623900 :   uR[1] = (tR*r[1] + (pS-pR)*nx)/s;
     648                 :    4623900 :   uR[2] = (tR*r[2] + (pS-pR)*ny)/s;
     649                 :    4623900 :   uR[3] = (tR*r[3] + (pS-pR)*nz)/s;
     650                 :    4623900 :   uR[4] = (tR*r[4] - pR*qR + pS*sM)/s;
     651                 :            : 
     652                 :    4623900 :   auto L2 = -2.0*len;
     653                 :    4623900 :   nx *= L2;
     654                 :    4623900 :   ny *= L2;
     655                 :    4623900 :   nz *= L2;
     656                 :            : 
     657                 :            :   // flow fluxes
     658         [ -  + ]:    4623900 :   if (sL > 0.0) {
     659                 :          0 :     auto qL2 = qL * L2;
     660                 :          0 :     f[0] = l[0]*qL2;
     661                 :          0 :     f[1] = l[1]*qL2 + pL*nx;
     662                 :          0 :     f[2] = l[2]*qL2 + pL*ny;
     663                 :          0 :     f[3] = l[3]*qL2 + pL*nz;
     664                 :          0 :     f[4] = (l[4] + pL)*qL2;
     665                 :            :   }
     666 [ +  - ][ +  + ]:    4623900 :   else if (sL <= 0.0 && sM > 0.0) {
     667                 :    2505530 :     auto qL2 = qL * L2;
     668                 :    2505530 :     auto sL2 = sL * L2;
     669                 :    2505530 :     f[0] = l[0]*qL2 + sL2*(uL[0] - l[0]);
     670                 :    2505530 :     f[1] = l[1]*qL2 + pL*nx + sL2*(uL[1] - l[1]);
     671                 :    2505530 :     f[2] = l[2]*qL2 + pL*ny + sL2*(uL[2] - l[2]);
     672                 :    2505530 :     f[3] = l[3]*qL2 + pL*nz + sL2*(uL[3] - l[3]);
     673                 :    2505530 :     f[4] = (l[4] + pL)*qL2 + sL2*(uL[4] - l[4]);
     674                 :    2505530 :   }
     675 [ +  - ][ +  - ]:    2118370 :   else if (sM <= 0.0 && sR >= 0.0) {
     676                 :    2118370 :     auto qR2 = qR * L2;
     677                 :    2118370 :     auto sR2 = sR * L2;
     678                 :    2118370 :     f[0] = r[0]*qR2 + sR2*(uR[0] - r[0]);
     679                 :    2118370 :     f[1] = r[1]*qR2 + pR*nx + sR2*(uR[1] - r[1]);
     680                 :    2118370 :     f[2] = r[2]*qR2 + pR*ny + sR2*(uR[2] - r[2]);
     681                 :    2118370 :     f[3] = r[3]*qR2 + pR*nz + sR2*(uR[3] - r[3]);
     682                 :    2118370 :     f[4] = (r[4] + pR)*qR2 + sR2*(uR[4] - r[4]);
     683                 :    2118370 :   }
     684                 :            :   else {
     685                 :          0 :     auto qR2 = qR * L2;
     686                 :          0 :     f[0] = r[0]*qR2;
     687                 :          0 :     f[1] = r[1]*qR2 + pR*nx;
     688                 :          0 :     f[2] = r[2]*qR2 + pR*ny;
     689                 :          0 :     f[3] = r[3]*qR2 + pR*nz;
     690                 :          0 :     f[4] = (r[4] + pR)*qR2;
     691                 :            :   }
     692                 :            : 
     693                 :            :   // artificial viscosity
     694                 :            :   //const auto stab2 = g_cfg.get< tag::stab2 >();
     695                 :            :   //if (stab2) {
     696                 :            :   //  auto stab2coef = g_cfg.get< tag::stab2coef >();
     697                 :            :   //  auto sl = std::abs(vpL) + cpL;
     698                 :            :   //  auto sr = std::abs(vpR) + cpR;
     699                 :            :   //  auto fws = stab2coef * std::max(sl,sr) * len;
     700                 :            :   //  f[0] -= fws*(l[0] - r[0]);
     701                 :            :   //  f[1] -= fws*(l[1] - r[1]);
     702                 :            :   //  f[2] -= fws*(l[2] - r[2]);
     703                 :            :   //  f[3] -= fws*(l[3] - r[3]);
     704                 :            :   //  f[4] -= fws*(l[4] - r[4]);
     705                 :            :   //}
     706                 :            : 
     707         [ +  - ]:    4623900 :   if (ncomp == 5) return;
     708                 :            : 
     709                 :            :   // MUSCL reconstruction in edge-end points for scalars
     710                 :          0 :   muscl( p, q, coord, G, l, r );
     711                 :            : 
     712                 :            :   // scalar fluxes
     713                 :            :   //auto sw = std::max( std::abs(vpL), std::abs(vpR) ) * len;
     714                 :            :   //for (std::size_t c=5; c<ncomp; ++c) {
     715                 :            :   //  f[c] = (l[c]*qL + r[c]*qR)*len + sw*(r[c] - l[c]);
     716                 :            :   //}
     717                 :            : 
     718                 :            :   #if defined(__clang__)
     719                 :            :     #pragma clang diagnostic pop
     720                 :            :   #elif defined(STRICT_GNUC)
     721                 :            :     #pragma GCC diagnostic pop
     722                 :            :   #endif
     723                 :    4623900 : }
     724                 :            : 
     725                 :            : static
     726                 :            : std::function< void( const tk::UnsMesh::Coords&,
     727                 :            :                      const tk::Fields&,
     728                 :            :                      const tk::real[],
     729                 :            :                      std::size_t,
     730                 :            :                      std::size_t,
     731                 :            :                      const tk::real[],
     732                 :            :                      const tk::real[],
     733                 :            :                      tk::real[] ) >
     734                 :      10200 : FLUX()
     735                 :            : // *****************************************************************************
     736                 :            : //! Configure flux function to use
     737                 :            : //! \return Function to call to compute flux between two edge-end points
     738                 :            : // *****************************************************************************
     739                 :            : {
     740                 :            :   const auto& flux = g_cfg.get< tag::flux >();
     741                 :            : 
     742         [ +  + ]:      10200 :   if (flux == "rusanov")
     743                 :            :     return rusanov;
     744         [ +  - ]:        240 :   else if (flux == "hllc")
     745                 :            :     return hllc;
     746                 :            :   else
     747 [ -  - ][ -  - ]:          0 :     Throw( "Flux not configured" );
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
     748                 :            : }
     749                 :            : 
     750                 :            : static void
     751                 :      10200 : advdom( const tk::UnsMesh::Coords& coord,
     752                 :            :         const std::array< std::vector< std::size_t >, 3 >& dsupedge,
     753                 :            :         const std::array< std::vector< tk::real >, 3 >& dsupint,
     754                 :            :         const tk::Fields& G,
     755                 :            :         const tk::Fields& U,
     756                 :            :         // cppcheck-suppress constParameter
     757                 :            :         tk::Fields& R )
     758                 :            : // *****************************************************************************
     759                 :            : //! Compute domain integral for advection
     760                 :            : //! \param[in] coord Mesh node coordinates
     761                 :            : //! \param[in] dsupedge Domain superedges
     762                 :            : //! \param[in] dsupint Domain superedge integrals
     763                 :            : //! \param[in] G Nodal gradients
     764                 :            : //! \param[in] U Solution vector of primitive variables at recent time step
     765                 :            : //! \param[in,out] R Right-hand side vector computed
     766                 :            : // *****************************************************************************
     767                 :            : {
     768                 :            :   // number of transported scalars
     769                 :            :   auto ncomp = U.nprop();
     770                 :            : 
     771                 :            :   // configure flux function
     772                 :      10200 :   auto flux = FLUX();
     773                 :            : 
     774                 :            :   #if defined(__clang__)
     775                 :            :     #pragma clang diagnostic push
     776                 :            :     #pragma clang diagnostic ignored "-Wvla"
     777                 :            :     #pragma clang diagnostic ignored "-Wvla-extension"
     778                 :            :   #elif defined(STRICT_GNUC)
     779                 :            :     #pragma GCC diagnostic push
     780                 :            :     #pragma GCC diagnostic ignored "-Wvla"
     781                 :            :   #endif
     782                 :            : 
     783                 :            :   // domain edge contributions: tetrahedron superedges
     784         [ +  + ]:    1603650 :   for (std::size_t e=0; e<dsupedge[0].size()/4; ++e) {
     785                 :    1593450 :     const auto N = dsupedge[0].data() + e*4;
     786                 :    1593450 :     tk::real u[4][ncomp];
     787         [ +  + ]:    9560700 :     for (std::size_t c=0; c<ncomp; ++c) {
     788                 :    7967250 :       u[0][c] = U(N[0],c);
     789                 :    7967250 :       u[1][c] = U(N[1],c);
     790                 :    7967250 :       u[2][c] = U(N[2],c);
     791                 :    7967250 :       u[3][c] = U(N[3],c);
     792                 :            :     }
     793                 :            :     // edge fluxes
     794         [ -  + ]:    1593450 :     tk::real f[6][ncomp];
     795                 :            :     const auto d = dsupint[0].data();
     796         [ -  + ]:    1593450 :     flux( coord, G, d+(e*6+0)*3, N[0], N[1], u[0], u[1], f[0] );
     797         [ -  + ]:    1593450 :     flux( coord, G, d+(e*6+1)*3, N[1], N[2], u[1], u[2], f[1] );
     798         [ -  + ]:    1593450 :     flux( coord, G, d+(e*6+2)*3, N[2], N[0], u[2], u[0], f[2] );
     799         [ -  + ]:    1593450 :     flux( coord, G, d+(e*6+3)*3, N[0], N[3], u[0], u[3], f[3] );
     800         [ -  + ]:    1593450 :     flux( coord, G, d+(e*6+4)*3, N[1], N[3], u[1], u[3], f[4] );
     801         [ -  + ]:    1593450 :     flux( coord, G, d+(e*6+5)*3, N[2], N[3], u[2], u[3], f[5] );
     802                 :            :     // edge flux contributions
     803         [ +  + ]:    9560700 :     for (std::size_t c=0; c<ncomp; ++c) {
     804                 :    7967250 :       R(N[0],c) = R(N[0],c) - f[0][c] + f[2][c] - f[3][c];
     805                 :    7967250 :       R(N[1],c) = R(N[1],c) + f[0][c] - f[1][c] - f[4][c];
     806                 :    7967250 :       R(N[2],c) = R(N[2],c) + f[1][c] - f[2][c] - f[5][c];
     807                 :    7967250 :       R(N[3],c) = R(N[3],c) + f[3][c] + f[4][c] + f[5][c];
     808                 :            :     }
     809                 :    1593450 :   }
     810                 :            : 
     811                 :            :   // domain edge contributions: triangle superedges
     812         [ +  + ]:     693990 :   for (std::size_t e=0; e<dsupedge[1].size()/3; ++e) {
     813                 :     683790 :     const auto N = dsupedge[1].data() + e*3;
     814                 :     683790 :     tk::real u[3][ncomp];
     815         [ +  + ]:    4102740 :     for (std::size_t c=0; c<ncomp; ++c) {
     816                 :    3418950 :       u[0][c] = U(N[0],c);
     817                 :    3418950 :       u[1][c] = U(N[1],c);
     818                 :    3418950 :       u[2][c] = U(N[2],c);
     819                 :            :     }
     820                 :            :     // edge fluxes
     821         [ -  + ]:     683790 :     tk::real f[3][ncomp];
     822                 :            :     const auto d = dsupint[1].data();
     823         [ -  + ]:     683790 :     flux( coord, G, d+(e*3+0)*3, N[0], N[1], u[0], u[1], f[0] );
     824         [ -  + ]:     683790 :     flux( coord, G, d+(e*3+1)*3, N[1], N[2], u[1], u[2], f[1] );
     825         [ -  + ]:     683790 :     flux( coord, G, d+(e*3+2)*3, N[2], N[0], u[2], u[0], f[2] );
     826                 :            :     // edge flux contributions
     827         [ +  + ]:    4102740 :     for (std::size_t c=0; c<ncomp; ++c) {
     828                 :    3418950 :       R(N[0],c) = R(N[0],c) - f[0][c] + f[2][c];
     829                 :    3418950 :       R(N[1],c) = R(N[1],c) + f[0][c] - f[1][c];
     830                 :    3418950 :       R(N[2],c) = R(N[2],c) + f[1][c] - f[2][c];
     831                 :            :     }
     832                 :     683790 :   }
     833                 :            : 
     834                 :            :   // domain edge contributions: edges
     835         [ +  + ]:    3355350 :   for (std::size_t e=0; e<dsupedge[2].size()/2; ++e) {
     836                 :    3345150 :     const auto N = dsupedge[2].data() + e*2;
     837                 :    3345150 :     tk::real u[2][ncomp];
     838         [ +  + ]:   20070900 :     for (std::size_t c=0; c<ncomp; ++c) {
     839                 :   16725750 :       u[0][c] = U(N[0],c);
     840                 :   16725750 :       u[1][c] = U(N[1],c);
     841                 :            :     }
     842                 :            :     // edge fluxes
     843         [ -  + ]:    3345150 :     tk::real f[ncomp];
     844                 :            :     const auto d = dsupint[2].data();
     845         [ -  + ]:    3345150 :     flux( coord, G, d+e*3, N[0], N[1], u[0], u[1], f );
     846                 :            :     // edge flux contributions
     847         [ +  + ]:   20070900 :     for (std::size_t c=0; c<ncomp; ++c) {
     848                 :   16725750 :       R(N[0],c) -= f[c];
     849                 :   16725750 :       R(N[1],c) += f[c];
     850                 :            :     }
     851                 :    3345150 :   }
     852                 :            : 
     853                 :            :   #if defined(__clang__)
     854                 :            :     #pragma clang diagnostic pop
     855                 :            :   #elif defined(STRICT_GNUC)
     856                 :            :     #pragma GCC diagnostic pop
     857                 :            :   #endif
     858                 :      10200 : }
     859                 :            : 
     860                 :            : static void
     861                 :      10200 : advbnd( const std::vector< std::size_t >& triinpoel,
     862                 :            :         const std::array< std::vector< tk::real >, 3 >& coord,
     863                 :            :         const std::vector< std::uint8_t >& besym,
     864                 :            :         const tk::Fields& U,
     865                 :            :         tk::Fields& R )
     866                 :            : // *****************************************************************************
     867                 :            : //! Compute boundary integral for advection
     868                 :            : //! \param[in] triinpoel Boundary face connectivity
     869                 :            : //! \param[in] coord Mesh node coordinates
     870                 :            : //! \param[in] besym Boundary element symmetry BC flags
     871                 :            : //! \param[in] U Solution vector at recent time step
     872                 :            : //! \param[in,out] R Right-hand side vector
     873                 :            : // *****************************************************************************
     874                 :            : {
     875                 :            :   auto ncomp = U.nprop();
     876                 :            : 
     877                 :      10200 :   auto g = g_cfg.get< tag::mat_spec_heat_ratio >();
     878                 :      10200 :   auto rgas = g_cfg.get< tag::mat_spec_gas_const >();
     879                 :            : 
     880                 :            :   const auto& x = coord[0];
     881                 :            :   const auto& y = coord[1];
     882                 :            :   const auto& z = coord[2];
     883                 :            : 
     884                 :            :   #if defined(__clang__)
     885                 :            :     #pragma clang diagnostic push
     886                 :            :     #pragma clang diagnostic ignored "-Wvla"
     887                 :            :     #pragma clang diagnostic ignored "-Wvla-extension"
     888                 :            :   #elif defined(STRICT_GNUC)
     889                 :            :     #pragma GCC diagnostic push
     890                 :            :     #pragma GCC diagnostic ignored "-Wvla"
     891                 :            :   #endif
     892                 :            : 
     893         [ +  + ]:    1385760 :   for (std::size_t e=0; e<triinpoel.size()/3; ++e) {
     894                 :    1375560 :     const auto N = triinpoel.data() + e*3;
     895                 :            : 
     896                 :    1375560 :     auto rA  = U(N[0],0)/U(N[0],4)/rgas;
     897                 :    1375560 :     auto ruA = U(N[0],1) * rA;
     898                 :    1375560 :     auto rvA = U(N[0],2) * rA;
     899                 :    1375560 :     auto rwA = U(N[0],3) * rA;
     900                 :    1375560 :     auto reA = U(N[0],0)/(g-1.0) + 0.5*(ruA*ruA + rvA*rvA + rwA*rwA)/rA;
     901                 :            : 
     902                 :    1375560 :     auto rB  = U(N[1],0)/U(N[1],4)/rgas;
     903                 :    1375560 :     auto ruB = U(N[1],1) * rB;
     904                 :    1375560 :     auto rvB = U(N[1],2) * rB;
     905                 :    1375560 :     auto rwB = U(N[1],3) * rB;
     906                 :    1375560 :     auto reB = U(N[1],0)/(g-1.0) + 0.5*(ruB*ruB + rvB*rvB + rwB*rwB)/rB;
     907                 :            : 
     908                 :    1375560 :     auto rC  = U(N[2],0)/U(N[2],4)/rgas;
     909                 :    1375560 :     auto ruC = U(N[2],1) * rC;
     910                 :    1375560 :     auto rvC = U(N[2],2) * rC;
     911                 :    1375560 :     auto rwC = U(N[2],3) * rC;
     912                 :    1375560 :     auto reC = U(N[2],0)/(g-1.0) + 0.5*(ruC*ruC + rvC*rvC + rwC*rwC)/rC;
     913                 :            : 
     914                 :            :     const std::array< tk::real, 3 >
     915                 :    1375560 :       ba{ x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]] },
     916         [ +  + ]:    1375560 :       ca{ x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]] };
     917                 :            :     auto [nx,ny,nz] = tk::cross( ba, ca );      // 2A
     918                 :    1375560 :     nx /= 12.0;
     919                 :    1375560 :     ny /= 12.0;
     920                 :    1375560 :     nz /= 12.0;
     921                 :            : 
     922         [ +  + ]:    1375560 :     tk::real vn, f[ncomp][3];
     923                 :    1375560 :     const auto sym = besym.data() + e*3;
     924                 :            : 
     925         [ +  + ]:    1375560 :     vn = sym[0] ? 0.0 : (nx*U(N[0],1) + ny*U(N[0],2) + nz*U(N[0],3));
     926                 :            :     // flow
     927                 :    1375560 :     f[0][0] = rA*vn;
     928                 :    1375560 :     f[1][0] = ruA*vn + U(N[0],0)*nx;
     929                 :    1375560 :     f[2][0] = rvA*vn + U(N[0],0)*ny;
     930                 :    1375560 :     f[3][0] = rwA*vn + U(N[0],0)*nz;
     931                 :    1375560 :     f[4][0] = (reA + U(N[0],0))*vn;
     932                 :            :     // scalar
     933         [ -  + ]:    1375560 :     for (std::size_t c=5; c<ncomp; ++c) f[c][0] = U(N[0],c)*vn;
     934                 :            : 
     935         [ +  + ]:    1375560 :     vn = sym[1] ? 0.0 : (nx*U(N[1],1) + ny*U(N[1],2) + nz*U(N[1],3));
     936                 :            :     // flow
     937                 :    1375560 :     f[0][1] = rB*vn;
     938                 :    1375560 :     f[1][1] = ruB*vn + U(N[1],0)*nx;
     939                 :    1375560 :     f[2][1] = rvB*vn + U(N[1],0)*ny;
     940                 :    1375560 :     f[3][1] = rwB*vn + U(N[1],0)*nz;
     941                 :    1375560 :     f[4][1] = (reB + U(N[1],0))*vn;
     942                 :            :     // scalar
     943         [ -  + ]:    1375560 :     for (std::size_t c=5; c<ncomp; ++c) f[c][1] = U(N[1],c)*vn;
     944                 :            : 
     945         [ +  + ]:    1375560 :     vn = sym[2] ? 0.0 : (nx*U(N[2],1) + ny*U(N[2],2) + nz*U(N[2],3));
     946                 :            :     // flow
     947                 :    1375560 :     f[0][2] = rC*vn;
     948                 :    1375560 :     f[1][2] = ruC*vn + U(N[2],0)*nx;
     949                 :    1375560 :     f[2][2] = rvC*vn + U(N[2],0)*ny;
     950                 :    1375560 :     f[3][2] = rwC*vn + U(N[2],0)*nz;
     951                 :    1375560 :     f[4][2] = (reC + U(N[2],0))*vn;
     952                 :            :     // scalar
     953         [ -  + ]:    1375560 :     for (std::size_t c=5; c<ncomp; ++c) f[c][2] = U(N[2],c)*vn;
     954                 :            : 
     955         [ +  + ]:    8253360 :     for (std::size_t c=0; c<ncomp; ++c) {
     956                 :    6877800 :       auto fab = (f[c][0] + f[c][1])/4.0;
     957                 :    6877800 :       auto fbc = (f[c][1] + f[c][2])/4.0;
     958                 :    6877800 :       auto fca = (f[c][2] + f[c][0])/4.0;
     959                 :    6877800 :       R(N[0],c) += fab + fca + f[c][0];
     960                 :    6877800 :       R(N[1],c) += fab + fbc + f[c][1];
     961                 :    6877800 :       R(N[2],c) += fbc + fca + f[c][2];
     962                 :            :     }
     963         [ +  + ]:    1375560 :   }
     964                 :            : 
     965                 :            :   #if defined(__clang__)
     966                 :            :     #pragma clang diagnostic pop
     967                 :            :   #elif defined(STRICT_GNUC)
     968                 :            :     #pragma GCC diagnostic pop
     969                 :            :   #endif
     970                 :      10200 : }
     971                 :            : 
     972                 :            : static void
     973                 :      10200 : src( const std::array< std::vector< tk::real >, 3 >& coord,
     974                 :            :      const std::vector< tk::real >& v,
     975                 :            :      tk::real t,
     976                 :            :      const std::vector< tk::real >& tp,
     977                 :            :      tk::Fields& R )
     978                 :            : // *****************************************************************************
     979                 :            : //  Compute source integral
     980                 :            : //! \param[in] coord Mesh node coordinates
     981                 :            : //! \param[in] v Nodal mesh volumes without contributions from other chares
     982                 :            : //! \param[in] t Physical time
     983                 :            : //! \param[in] tp Physical time for each mesh node
     984                 :            : //! \param[in,out] R Right-hand side vector computed
     985                 :            : // *****************************************************************************
     986                 :            : {
     987                 :      10200 :   auto src = problems::SRC();
     988         [ +  - ]:      10200 :   if (!src) return;
     989                 :            : 
     990                 :            :   const auto& x = coord[0];
     991                 :            :   const auto& y = coord[1];
     992                 :            :   const auto& z = coord[2];
     993                 :            : 
     994         [ -  - ]:          0 :   for (std::size_t p=0; p<R.nunk(); ++p) {
     995         [ -  - ]:          0 :     if (g_cfg.get< tag::steady >()) t = tp[p];
     996         [ -  - ]:          0 :     auto s = src( x[p], y[p], z[p], t );
     997         [ -  - ]:          0 :     for (std::size_t c=0; c<s.size(); ++c) R(p,c) -= s[c] * v[p];
     998                 :            :   }
     999                 :            : }
    1000                 :            : 
    1001                 :            : void
    1002                 :      10200 : rhs( const std::array< std::vector< std::size_t >, 3 >& dsupedge,
    1003                 :            :      const std::array< std::vector< tk::real >, 3 >& dsupint,
    1004                 :            :      const std::array< std::vector< tk::real >, 3 >& coord,
    1005                 :            :      const std::vector< std::size_t >& triinpoel,
    1006                 :            :      const std::vector< std::uint8_t >& besym,
    1007                 :            :      const tk::Fields& G,
    1008                 :            :      const tk::Fields& U,
    1009                 :            :      const std::vector< tk::real >& v,
    1010                 :            :      tk::real t,
    1011                 :            :      const std::vector< tk::real >& tp,
    1012                 :            :      tk::Fields& R )
    1013                 :            : // *****************************************************************************
    1014                 :            : //  Compute right hand side
    1015                 :            : //! \param[in] dsupedge Domain superedges
    1016                 :            : //! \param[in] dsupint Domain superedge integrals
    1017                 :            : //! \param[in] coord Mesh node coordinates
    1018                 :            : //! \param[in] triinpoel Boundary face connectivity
    1019                 :            : //! \param[in] besym Boundary element symmetry BC flags
    1020                 :            : //! \param[in] G Gradients in mesh nodes
    1021                 :            : //! \param[in] U Solution vector of primitive variables at recent time step
    1022                 :            : //! \param[in] v Nodal mesh volumes without contributions from other chares
    1023                 :            : //! \param[in] t Physical time
    1024                 :            : //! \param[in] tp Physical time for each mesh node
    1025                 :            : //! \param[in,out] R Right-hand side vector computed
    1026                 :            : // *****************************************************************************
    1027                 :            : {
    1028                 :            :   Assert( U.nunk() == coord[0].size(), "Number of unknowns in solution "
    1029                 :            :           "vector at recent time step incorrect" );
    1030                 :            :   Assert( R.nunk() == coord[0].size(),
    1031                 :            :           "Number of unknowns and/or number of components in right-hand "
    1032                 :            :           "side vector incorrect" );
    1033                 :            : 
    1034                 :            :   R.fill( 0.0 );
    1035                 :      10200 :   advdom( coord, dsupedge, dsupint, G, U, R );
    1036                 :      10200 :   advbnd( triinpoel, coord, besym, U, R );
    1037                 :      10200 :   src( coord, v, t, tp, R );
    1038                 :      10200 : }
    1039                 :            : 
    1040                 :            : } // lax::

Generated by: LCOV version 1.16