Xyst test code coverage report
Current view: top level - Physics - Lohner.cpp (source / functions) Hit Total Coverage
Commit: 5689ba12dc66a776d3d75f1ee48cc7d78eaa18dc Lines: 466 467 99.8 %
Date: 2024-11-22 19:02:53 Functions: 13 13 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 137 162 84.6 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/Physics/Lohner.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     LohCG: Artificial compressibility solver for incompressible flow
      10                 :            : */
      11                 :            : // *****************************************************************************
      12                 :            : 
      13                 :            : #include "Vector.hpp"
      14                 :            : #include "Around.hpp"
      15                 :            : #include "DerivedData.hpp"
      16                 :            : #include "EOS.hpp"
      17                 :            : #include "Lohner.hpp"
      18                 :            : #include "Problems.hpp"
      19                 :            : #include "InciterConfig.hpp"
      20                 :            : 
      21                 :            : namespace inciter {
      22                 :            : 
      23                 :            : extern ctr::Config g_cfg;
      24                 :            : 
      25                 :            : } // ::inciter
      26                 :            : 
      27                 :            : namespace lohner {
      28                 :            : 
      29                 :            : static const tk::real muscl_eps = 1.0e-9;
      30                 :            : static const tk::real muscl_const = 1.0/3.0;
      31                 :            : 
      32                 :            : using inciter::g_cfg;
      33                 :            : 
      34                 :            : void
      35                 :        650 : div( const std::array< std::vector< std::size_t >, 3 >& dsupedge,
      36                 :            :      const std::array< std::vector< tk::real >, 3 >& dsupint,
      37                 :            :      const std::array< std::vector< tk::real >, 3 >& coord,
      38                 :            :      const std::vector< std::size_t >& triinpoel,
      39                 :            :      const tk::Fields& U,
      40                 :            :      std::vector< tk::real >& D,
      41                 :            :      std::size_t pos )
      42                 :            : // *****************************************************************************
      43                 :            : //  Compute divergence of a vector in all points
      44                 :            : //! \param[in] dsupedge Domain superedges
      45                 :            : //! \param[in] dsupint Domain superedge integrals
      46                 :            : //! \param[in] coord Mesh node coordinates
      47                 :            : //! \param[in] triinpoel Boundary face connectivity
      48                 :            : //! \param[in] U Vector whose divergence to compute
      49                 :            : //! \param[in,out] D Vector added to
      50                 :            : //! \param[in] pos Position at which the three vector components are in U
      51                 :            : // *****************************************************************************
      52                 :            : {
      53                 :            :   Assert( U.nunk() == D.size(), "Size mismatch" );
      54                 :            : 
      55                 :            :   // Lambda to compute the velocity divergence contribution for edge p-q
      56                 :     130884 :   auto div = [&]( const tk::real d[], std::size_t p, std::size_t q ){
      57                 :     130884 :     return d[0] * (U(p,pos+0) + U(q,pos+0)) +
      58                 :     130884 :            d[1] * (U(p,pos+1) + U(q,pos+1)) +
      59                 :     130884 :            d[2] * (U(p,pos+2) + U(q,pos+2));
      60                 :        650 :   };
      61                 :            : 
      62                 :            :   #if defined(__clang__)
      63                 :            :     #pragma clang diagnostic push
      64                 :            :     #pragma clang diagnostic ignored "-Wvla"
      65                 :            :     #pragma clang diagnostic ignored "-Wvla-extension"
      66                 :            :   #elif defined(STRICT_GNUC)
      67                 :            :     #pragma GCC diagnostic push
      68                 :            :     #pragma GCC diagnostic ignored "-Wvla"
      69                 :            :   #endif
      70                 :            : 
      71                 :            :   // domain integral
      72                 :            : 
      73                 :            :   // domain edge contributions: tetrahedron superedges
      74         [ +  + ]:      12018 :   for (std::size_t e=0; e<dsupedge[0].size()/4; ++e) {
      75                 :      11368 :     const auto N = dsupedge[0].data() + e*4;
      76                 :            :     const auto d = dsupint[0].data();
      77                 :            :     // edge fluxes
      78                 :            :     tk::real f[] = {
      79                 :      11368 :       div( d+(e*6+0)*4, N[0], N[1] ),
      80                 :      11368 :       div( d+(e*6+1)*4, N[1], N[2] ),
      81                 :      11368 :       div( d+(e*6+2)*4, N[2], N[0] ),
      82                 :      11368 :       div( d+(e*6+3)*4, N[0], N[3] ),
      83                 :      11368 :       div( d+(e*6+4)*4, N[1], N[3] ),
      84                 :      11368 :       div( d+(e*6+5)*4, N[2], N[3] ) };
      85                 :            :     // edge flux contributions
      86                 :      11368 :     D[N[0]] = D[N[0]] - f[0] + f[2] - f[3];
      87                 :      11368 :     D[N[1]] = D[N[1]] + f[0] - f[1] - f[4];
      88                 :      11368 :     D[N[2]] = D[N[2]] + f[1] - f[2] - f[5];
      89                 :      11368 :     D[N[3]] = D[N[3]] + f[3] + f[4] + f[5];
      90                 :            :   }
      91                 :            : 
      92                 :            :   // domain edge contributions: triangle superedges
      93         [ +  + ]:      12014 :   for (std::size_t e=0; e<dsupedge[1].size()/3; ++e) {
      94                 :      11364 :     const auto N = dsupedge[1].data() + e*3;
      95                 :            :     const auto d = dsupint[1].data();
      96                 :            :     // edge fluxes
      97                 :            :     tk::real f[] = {
      98                 :      11364 :       div( d+(e*3+0)*4, N[0], N[1] ),
      99                 :      11364 :       div( d+(e*3+1)*4, N[1], N[2] ),
     100                 :      11364 :       div( d+(e*3+2)*4, N[2], N[0] ) };
     101                 :            :     // edge flux contributions
     102                 :      11364 :     D[N[0]] = D[N[0]] - f[0] + f[2];
     103                 :      11364 :     D[N[1]] = D[N[1]] + f[0] - f[1];
     104                 :      11364 :     D[N[2]] = D[N[2]] + f[1] - f[2];
     105                 :            :   }
     106                 :            : 
     107                 :            :   // domain edge contributions: edges
     108         [ +  + ]:      29234 :   for (std::size_t e=0; e<dsupedge[2].size()/2; ++e) {
     109                 :      28584 :     const auto N = dsupedge[2].data() + e*2;
     110                 :            :     const auto d = dsupint[2].data();
     111                 :            :     // edge flux
     112                 :      28584 :     tk::real f = div( d+e*4, N[0], N[1] );
     113                 :            :     // edge flux contributions
     114                 :      28584 :     D[N[0]] -= f;
     115                 :      28584 :     D[N[1]] += f;
     116                 :            :   }
     117                 :            : 
     118                 :            :   // boundary integral
     119                 :            : 
     120                 :            :   const auto& x = coord[0];
     121                 :            :   const auto& y = coord[1];
     122                 :            :   const auto& z = coord[2];
     123                 :            : 
     124         [ +  + ]:      47642 :   for (std::size_t e=0; e<triinpoel.size()/3; ++e) {
     125                 :      46992 :     const auto N = triinpoel.data() + e*3;
     126                 :            :     tk::real n[3];
     127                 :      46992 :     tk::crossdiv( x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]],
     128                 :      46992 :                   x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]], 6.0,
     129                 :            :                   n[0], n[1], n[2] );
     130                 :      46992 :     auto uxA = U(N[0],pos+0);
     131                 :      46992 :     auto uyA = U(N[0],pos+1);
     132                 :      46992 :     auto uzA = U(N[0],pos+2);
     133                 :      46992 :     auto uxB = U(N[1],pos+0);
     134                 :      46992 :     auto uyB = U(N[1],pos+1);
     135                 :      46992 :     auto uzB = U(N[1],pos+2);
     136                 :      46992 :     auto uxC = U(N[2],pos+0);
     137                 :      46992 :     auto uyC = U(N[2],pos+1);
     138                 :      46992 :     auto uzC = U(N[2],pos+2);
     139                 :      46992 :     auto ux = (6.0*uxA + uxB + uxC)/8.0;
     140                 :      46992 :     auto uy = (6.0*uyA + uyB + uyC)/8.0;
     141                 :      46992 :     auto uz = (6.0*uzA + uzB + uzC)/8.0;
     142                 :      46992 :     D[N[0]] += ux*n[0] + uy*n[1] + uz*n[2];
     143                 :      46992 :     ux = (uxA + 6.0*uxB + uxC)/8.0;
     144                 :      46992 :     uy = (uyA + 6.0*uyB + uyC)/8.0;
     145                 :      46992 :     uz = (uzA + 6.0*uzB + uzC)/8.0;
     146                 :      46992 :     D[N[1]] += ux*n[0] + uy*n[1] + uz*n[2];
     147                 :      46992 :     ux = (uxA + uxB + 6.0*uxC)/8.0;
     148                 :      46992 :     uy = (uyA + uyB + 6.0*uyC)/8.0;
     149                 :      46992 :     uz = (uzA + uzB + 6.0*uzC)/8.0;
     150                 :      46992 :     D[N[2]] += ux*n[0] + uy*n[1] + uz*n[2];
     151                 :            :   }
     152                 :            : 
     153                 :            :   #if defined(__clang__)
     154                 :            :     #pragma clang diagnostic pop
     155                 :            :   #elif defined(STRICT_GNUC)
     156                 :            :     #pragma GCC diagnostic pop
     157                 :            :   #endif
     158                 :        650 : }
     159                 :            : 
     160                 :            : void
     161         [ +  - ]:        325 : grad( const std::array< std::vector< std::size_t >, 3 >& dsupedge,
     162                 :            :       const std::array< std::vector< tk::real >, 3 >& dsupint,
     163                 :            :       const std::array< std::vector< tk::real >, 3 >& coord,
     164                 :            :       const std::vector< std::size_t >& triinpoel,
     165                 :            :       const std::vector< tk::real >& U,
     166                 :            :       tk::Fields& G )
     167                 :            : // *****************************************************************************
     168                 :            : //  Compute gradients of scalar in all points
     169                 :            : //! \param[in] dsupedge Domain superedges
     170                 :            : //! \param[in] dsupint Domain superedge integrals
     171                 :            : //! \param[in] coord Mesh node coordinates
     172                 :            : //! \param[in] triinpoel Boundary face connectivity
     173                 :            : //! \param[in] U Scalar whose gradient to compute
     174                 :            : //! \param[in,out] G Nodal gradient of scalar in all points
     175                 :            : // *****************************************************************************
     176                 :            : {
     177         [ +  - ]:        325 :   if (G.nprop() == 0) return;
     178                 :            : 
     179                 :            :   Assert( G.nunk() == U.size(), "Size mismatch" );
     180                 :            :   Assert( G.nprop() > 2, "Size mismatch" );
     181                 :            :   Assert( G.nprop() % 3 == 0, "Size mismatch" );
     182                 :            : 
     183                 :            :   #if defined(__clang__)
     184                 :            :     #pragma clang diagnostic push
     185                 :            :     #pragma clang diagnostic ignored "-Wvla"
     186                 :            :     #pragma clang diagnostic ignored "-Wvla-extension"
     187                 :            :   #elif defined(STRICT_GNUC)
     188                 :            :     #pragma GCC diagnostic push
     189                 :            :     #pragma GCC diagnostic ignored "-Wvla"
     190                 :            :   #endif
     191                 :            : 
     192                 :            :   // domain integral
     193                 :            : 
     194                 :            :   // domain edge contributions: tetrahedron superedges
     195         [ +  + ]:       6009 :   for (std::size_t e=0; e<dsupedge[0].size()/4; ++e) {
     196                 :       5684 :     const auto N = dsupedge[0].data() + e*4;
     197                 :            :     const auto d = dsupint[0].data();
     198                 :       5684 :     tk::real u[] = { U[N[0]], U[N[1]], U[N[2]], U[N[3]] };
     199         [ +  + ]:      22736 :     for (std::size_t j=0; j<3; ++j) {
     200                 :            :       tk::real f[] = {
     201                 :      17052 :         d[(e*6+0)*4+j] * (u[1] + u[0]),
     202                 :      17052 :         d[(e*6+1)*4+j] * (u[2] + u[1]),
     203                 :      17052 :         d[(e*6+2)*4+j] * (u[0] + u[2]),
     204                 :      17052 :         d[(e*6+3)*4+j] * (u[3] + u[0]),
     205                 :      17052 :         d[(e*6+4)*4+j] * (u[3] + u[1]),
     206                 :      17052 :         d[(e*6+5)*4+j] * (u[3] + u[2]) };
     207                 :      17052 :       G(N[0],j) = G(N[0],j) - f[0] + f[2] - f[3];
     208                 :      17052 :       G(N[1],j) = G(N[1],j) + f[0] - f[1] - f[4];
     209                 :      17052 :       G(N[2],j) = G(N[2],j) + f[1] - f[2] - f[5];
     210                 :      17052 :       G(N[3],j) = G(N[3],j) + f[3] + f[4] + f[5];
     211                 :            :     }
     212                 :            :   }
     213                 :            : 
     214                 :            :   // domain edge contributions: triangle superedges
     215         [ +  + ]:       6007 :   for (std::size_t e=0; e<dsupedge[1].size()/3; ++e) {
     216                 :       5682 :     const auto N = dsupedge[1].data() + e*3;
     217                 :            :     const auto d = dsupint[1].data();
     218                 :       5682 :     tk::real u[] = { U[N[0]], U[N[1]], U[N[2]] };
     219         [ +  + ]:      22728 :     for (std::size_t j=0; j<3; ++j) {
     220                 :            :       tk::real f[] = {
     221                 :      17046 :         d[(e*3+0)*4+j] * (u[1] + u[0]),
     222                 :      17046 :         d[(e*3+1)*4+j] * (u[2] + u[1]),
     223                 :      17046 :         d[(e*3+2)*4+j] * (u[0] + u[2]) };
     224                 :      17046 :       G(N[0],j) = G(N[0],j) - f[0] + f[2];
     225                 :      17046 :       G(N[1],j) = G(N[1],j) + f[0] - f[1];
     226                 :      17046 :       G(N[2],j) = G(N[2],j) + f[1] - f[2];
     227                 :            :     }
     228                 :            :   }
     229                 :            : 
     230                 :            :   // domain edge contributions: edges
     231         [ +  + ]:      14617 :   for (std::size_t e=0; e<dsupedge[2].size()/2; ++e) {
     232                 :      14292 :     const auto N = dsupedge[2].data() + e*2;
     233                 :      14292 :     const auto d = dsupint[2].data() + e*4;
     234                 :      14292 :     tk::real u[] = { U[N[0]], U[N[1]] };
     235         [ +  + ]:      57168 :     for (std::size_t j=0; j<3; ++j) {
     236                 :      42876 :       tk::real f = d[j] * (u[1] + u[0]);
     237                 :      42876 :       G(N[0],j) -= f;
     238                 :      42876 :       G(N[1],j) += f;
     239                 :            :     }
     240                 :            :   }
     241                 :            : 
     242                 :            :   // boundary integral
     243                 :            : 
     244                 :            :   const auto& x = coord[0];
     245                 :            :   const auto& y = coord[1];
     246                 :            :   const auto& z = coord[2];
     247                 :            : 
     248         [ +  + ]:      23821 :   for (std::size_t e=0; e<triinpoel.size()/3; ++e) {
     249                 :      23496 :     const auto N = triinpoel.data() + e*3;
     250                 :            :     tk::real n[3];
     251                 :      23496 :     tk::crossdiv( x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]],
     252                 :      23496 :                   x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]], 6.0,
     253                 :            :                   n[0], n[1], n[2] );
     254                 :      23496 :     auto uA = U[N[0]];
     255                 :      23496 :     auto uB = U[N[1]];
     256                 :      23496 :     auto uC = U[N[2]];
     257                 :      23496 :     auto f = (6.0*uA + uB + uC)/8.0;
     258                 :      23496 :     G(N[0],0) += f * n[0];
     259                 :      23496 :     G(N[0],1) += f * n[1];
     260                 :      23496 :     G(N[0],2) += f * n[2];
     261                 :      23496 :     f = (uA + 6.0*uB + uC)/8.0;
     262                 :      23496 :     G(N[1],0) += f * n[0];
     263                 :      23496 :     G(N[1],1) += f * n[1];
     264                 :      23496 :     G(N[1],2) += f * n[2];
     265                 :      23496 :     f = (uA + uB + 6.0*uC)/8.0;
     266                 :      23496 :     G(N[2],0) += f * n[0];
     267                 :      23496 :     G(N[2],1) += f * n[1];
     268                 :      23496 :     G(N[2],2) += f * n[2];
     269                 :            :   }
     270                 :            : 
     271                 :            :   #if defined(__clang__)
     272                 :            :     #pragma clang diagnostic pop
     273                 :            :   #elif defined(STRICT_GNUC)
     274                 :            :     #pragma GCC diagnostic pop
     275                 :            :   #endif
     276                 :            : }
     277                 :            : 
     278                 :            : void
     279                 :        325 : vgrad( const std::array< std::vector< std::size_t >, 3 >& dsupedge,
     280                 :            :        const std::array< std::vector< tk::real >, 3 >& dsupint,
     281                 :            :        const std::array< std::vector< tk::real >, 3 >& coord,
     282                 :            :        const std::vector< std::size_t >& triinpoel,
     283                 :            :        const tk::Fields& U,
     284                 :            :        tk::Fields& G )
     285                 :            : // *****************************************************************************
     286                 :            : //  Compute velocity gradients in all points
     287                 :            : //! \param[in] dsupedge Domain superedges
     288                 :            : //! \param[in] dsupint Domain superedge integrals
     289                 :            : //! \param[in] coord Mesh node coordinates
     290                 :            : //! \param[in] triinpoel Boundary face connectivity
     291                 :            : //! \param[in] U Velocity whose gradient to compute
     292                 :            : //! \param[in,out] G Nodal velocity gradients (9 components) in all points
     293                 :            : // *****************************************************************************
     294                 :            : {
     295                 :            :   Assert( G.nunk() == U.nunk(), "Size mismatch" );
     296                 :            :   Assert( G.nprop() == 9, "Size mismatch" );
     297                 :            : 
     298                 :            :   #if defined(__clang__)
     299                 :            :     #pragma clang diagnostic push
     300                 :            :     #pragma clang diagnostic ignored "-Wvla"
     301                 :            :     #pragma clang diagnostic ignored "-Wvla-extension"
     302                 :            :   #elif defined(STRICT_GNUC)
     303                 :            :     #pragma GCC diagnostic push
     304                 :            :     #pragma GCC diagnostic ignored "-Wvla"
     305                 :            :   #endif
     306                 :            : 
     307                 :            :   // domain integral
     308                 :            : 
     309                 :            :   // domain edge contributions: tetrahedron superedges
     310         [ +  + ]:       6009 :   for (std::size_t e=0; e<dsupedge[0].size()/4; ++e) {
     311                 :       5684 :     const auto N = dsupedge[0].data() + e*4;
     312                 :            :     const auto d = dsupint[0].data();
     313         [ +  + ]:      22736 :     for (std::size_t i=0; i<3; ++i) {
     314                 :      17052 :       tk::real u[] = { U(N[0],i+1), U(N[1],i+1), U(N[2],i+1), U(N[3],i+1) };
     315                 :      17052 :       auto i3 = i*3;
     316         [ +  + ]:      68208 :       for (std::size_t j=0; j<3; ++j) {
     317                 :      51156 :         tk::real f[] = { d[(e*6+0)*4+j] * (u[1] + u[0]),
     318                 :      51156 :                          d[(e*6+1)*4+j] * (u[2] + u[1]),
     319                 :      51156 :                          d[(e*6+2)*4+j] * (u[0] + u[2]),
     320                 :      51156 :                          d[(e*6+3)*4+j] * (u[3] + u[0]),
     321                 :      51156 :                          d[(e*6+4)*4+j] * (u[3] + u[1]),
     322                 :      51156 :                          d[(e*6+5)*4+j] * (u[3] + u[2]) };
     323                 :      51156 :         G(N[0],i3+j) = G(N[0],i3+j) - f[0] + f[2] - f[3];
     324                 :      51156 :         G(N[1],i3+j) = G(N[1],i3+j) + f[0] - f[1] - f[4];
     325                 :      51156 :         G(N[2],i3+j) = G(N[2],i3+j) + f[1] - f[2] - f[5];
     326                 :      51156 :         G(N[3],i3+j) = G(N[3],i3+j) + f[3] + f[4] + f[5];
     327                 :            :       }
     328                 :            :     }
     329                 :            :   }
     330                 :            : 
     331                 :            :   // domain edge contributions: triangle superedges
     332         [ +  + ]:       6007 :   for (std::size_t e=0; e<dsupedge[1].size()/3; ++e) {
     333                 :       5682 :     const auto N = dsupedge[1].data() + e*3;
     334                 :            :     const auto d = dsupint[1].data();
     335         [ +  + ]:      22728 :     for (std::size_t i=0; i<3; ++i) {
     336                 :      17046 :       tk::real u[] = { U(N[0],i+1), U(N[1],i+1), U(N[2],i+1) };
     337                 :      17046 :       auto i3 = i*3;
     338         [ +  + ]:      68184 :       for (std::size_t j=0; j<3; ++j) {
     339                 :      51138 :         tk::real f[] = { d[(e*3+0)*4+j] * (u[1] + u[0]),
     340                 :      51138 :                          d[(e*3+1)*4+j] * (u[2] + u[1]),
     341                 :      51138 :                          d[(e*3+2)*4+j] * (u[0] + u[2]) };
     342                 :      51138 :         G(N[0],i3+j) = G(N[0],i3+j) - f[0] + f[2];
     343                 :      51138 :         G(N[1],i3+j) = G(N[1],i3+j) + f[0] - f[1];
     344                 :      51138 :         G(N[2],i3+j) = G(N[2],i3+j) + f[1] - f[2];
     345                 :            :       }
     346                 :            :     }
     347                 :            :   }
     348                 :            : 
     349                 :            :   // domain edge contributions: edges
     350         [ +  + ]:      14617 :   for (std::size_t e=0; e<dsupedge[2].size()/2; ++e) {
     351                 :      14292 :     const auto N = dsupedge[2].data() + e*2;
     352                 :      14292 :     const auto d = dsupint[2].data() + e*4;
     353         [ +  + ]:      57168 :     for (std::size_t i=0; i<3; ++i) {
     354                 :      42876 :       tk::real u[] = { U(N[0],i+1), U(N[1],i+1) };
     355                 :      42876 :       auto i3 = i*3;
     356         [ +  + ]:     171504 :       for (std::size_t j=0; j<3; ++j) {
     357                 :     128628 :         tk::real f = d[j] * (u[1] + u[0]);
     358                 :     128628 :         G(N[0],i3+j) -= f;
     359                 :     128628 :         G(N[1],i3+j) += f;
     360                 :            :       }
     361                 :            :     }
     362                 :            :   }
     363                 :            : 
     364                 :            :   // boundary integral
     365                 :            : 
     366                 :            :   const auto& x = coord[0];
     367                 :            :   const auto& y = coord[1];
     368                 :            :   const auto& z = coord[2];
     369                 :            : 
     370         [ +  + ]:      23821 :   for (std::size_t e=0; e<triinpoel.size()/3; ++e) {
     371                 :      23496 :     const auto N = triinpoel.data() + e*3;
     372                 :            :     tk::real n[3];
     373                 :      23496 :     tk::crossdiv( x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]],
     374                 :      23496 :                   x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]], 6.0,
     375                 :            :                   n[0], n[1], n[2] );
     376         [ +  + ]:      93984 :     for (std::size_t i=0; i<3; ++i) {
     377                 :      70488 :       tk::real u[] = { U(N[0],i+1), U(N[1],i+1), U(N[2],i+1) };
     378                 :      70488 :       auto i3 = i*3;
     379                 :      70488 :       auto f = (6.0*u[0] + u[1] + u[2])/8.0;
     380                 :      70488 :       G(N[0],i3+0) += f * n[0];
     381                 :      70488 :       G(N[0],i3+1) += f * n[1];
     382                 :      70488 :       G(N[0],i3+2) += f * n[2];
     383                 :      70488 :       f = (u[0] + 6.0*u[1] + u[2])/8.0;
     384                 :      70488 :       G(N[1],i3+0) += f * n[0];
     385                 :      70488 :       G(N[1],i3+1) += f * n[1];
     386                 :      70488 :       G(N[1],i3+2) += f * n[2];
     387                 :      70488 :       f = (u[0] + u[1] + 6.0*u[2])/8.0;
     388                 :      70488 :       G(N[2],i3+0) += f * n[0];
     389                 :      70488 :       G(N[2],i3+1) += f * n[1];
     390                 :      70488 :       G(N[2],i3+2) += f * n[2];
     391                 :            :     }
     392                 :            :   }
     393                 :            : 
     394                 :            :   #if defined(__clang__)
     395                 :            :     #pragma clang diagnostic pop
     396                 :            :   #elif defined(STRICT_GNUC)
     397                 :            :     #pragma GCC diagnostic pop
     398                 :            :   #endif
     399                 :        325 : }
     400                 :            : 
     401                 :            : static tk::real
     402         [ -  + ]:     588978 : flux( const tk::Fields& U,
     403                 :            :       const tk::Fields& G,
     404                 :            :       std::size_t i,
     405                 :            :       std::size_t j,
     406                 :            :       std::size_t p,
     407                 :            :       std::size_t q )
     408                 :            : // *****************************************************************************
     409                 :            : //! Compute momentum flux over edge of points p-q
     410                 :            : //! \param[in] U Velocity vector
     411                 :            : //! \param[in] G Velocity gradients
     412                 :            : //! \param[in] i Tensor component, 1st index
     413                 :            : //! \param[in] j Tensor component, 2nd index
     414                 :            : //! \param[in] p Left node index of edge
     415                 :            : //! \param[in] q Right node index of edge
     416                 :            : //! \return Momentum flux contribution for edge p-q
     417                 :            : // *****************************************************************************
     418                 :            : {
     419                 :     588978 :   auto inv = U(p,i)*U(p,j) + U(q,i)*U(q,j);
     420                 :            : 
     421                 :            :   auto eps = std::numeric_limits< tk::real >::epsilon();
     422                 :     588978 :   auto mu = g_cfg.get< tag::mat_dyn_viscosity >();
     423         [ -  + ]:     588978 :   if (mu < eps) return -inv;
     424                 :            : 
     425 [ +  + ][ +  + ]:    1177956 :   auto vis = G(p,i*3+j) + G(p,j*3+i) + G(q,i*3+j) + G(q,j*3+i);
     426         [ +  + ]:     588978 :   if (i == j) {
     427                 :     196326 :     vis -= 2.0/3.0 * ( G(p,0) + G(p,4) + G(p,8) + G(q,0) + G(q,4) + G(q,8) );
     428                 :            :   }
     429                 :     588978 :   return mu*vis - inv;
     430                 :            : }
     431                 :            : 
     432                 :            : static tk::real
     433         [ -  + ]:     634392 : flux( const tk::Fields& U,
     434                 :            :       const tk::Fields& G,
     435                 :            :       std::size_t i,
     436                 :            :       std::size_t j,
     437                 :            :       std::size_t p )
     438                 :            : // *****************************************************************************
     439                 :            : //! Compute momentum flux in point p
     440                 :            : //! \param[in] U Velocity vector
     441                 :            : //! \param[in] G Velocity gradients
     442                 :            : //! \param[in] i Tensor component, 1st index
     443                 :            : //! \param[in] j Tensor component, 2nd index
     444                 :            : //! \param[in] p Node index of point
     445                 :            : //! \return Momentum flux contribution for point p
     446                 :            : // *****************************************************************************
     447                 :            : {
     448                 :     634392 :   auto inv = U(p,i)*U(p,j);
     449                 :            : 
     450                 :            :   auto eps = std::numeric_limits< tk::real >::epsilon();
     451                 :     634392 :   auto mu = g_cfg.get< tag::mat_dyn_viscosity >();
     452         [ -  + ]:     634392 :   if (mu < eps) return -inv;
     453                 :            : 
     454         [ +  + ]:     634392 :   auto vis = G(p,i*3+j) + G(p,j*3+i);
     455         [ +  + ]:     634392 :   if (i == j) {
     456                 :     211464 :     vis -= 2.0/3.0 * ( G(p,0) + G(p,4) + G(p,8) );
     457                 :            :   }
     458                 :     634392 :   return mu*vis - inv;
     459                 :            : }
     460                 :            : 
     461                 :            : void
     462                 :        325 : flux( const std::array< std::vector< std::size_t >, 3 >& dsupedge,
     463                 :            :       const std::array< std::vector< tk::real >, 3 >& dsupint,
     464                 :            :       const std::array< std::vector< tk::real >, 3 >& coord,
     465                 :            :       const std::vector< std::size_t >& triinpoel,
     466                 :            :       const tk::Fields& U,
     467                 :            :       const tk::Fields& G,
     468                 :            :       tk::Fields& F )
     469                 :            : // *****************************************************************************
     470                 :            : //  Compute momentum flux in all points
     471                 :            : //! \param[in] dsupedge Domain superedges
     472                 :            : //! \param[in] dsupint Domain superedge integrals
     473                 :            : //! \param[in] coord Mesh node coordinates
     474                 :            : //! \param[in] triinpoel Boundary face connectivity
     475                 :            : //! \param[in] U Velocity field
     476                 :            : //! \param[in] G Velocity gradients, dui/dxj, 9 components
     477                 :            : //! \param[in,out] F Momentum flux, Fi = d[ sij - uiuj ] / dxj, where
     478                 :            : //!    s_ij = mu[ dui/dxj + duj/dxi - 2/3 duk/dxk delta_ij ]
     479                 :            : // *****************************************************************************
     480                 :            : {
     481                 :            :   Assert( F.nunk() == U.nunk(), "Size mismatch" );
     482                 :            :   Assert( F.nprop() == 3, "Size mismatch" );
     483                 :            :   Assert( G.nunk() == U.nunk(), "Size mismatch" );
     484                 :            :   Assert( G.nprop() == 9, "Size mismatch" );
     485                 :            : 
     486                 :            :   #if defined(__clang__)
     487                 :            :     #pragma clang diagnostic push
     488                 :            :     #pragma clang diagnostic ignored "-Wvla"
     489                 :            :     #pragma clang diagnostic ignored "-Wvla-extension"
     490                 :            :   #elif defined(STRICT_GNUC)
     491                 :            :     #pragma GCC diagnostic push
     492                 :            :     #pragma GCC diagnostic ignored "-Wvla"
     493                 :            :   #endif
     494                 :            : 
     495                 :            :   // domain integral
     496                 :            : 
     497                 :            :   // domain edge contributions: tetrahedron superedges
     498         [ +  + ]:       6009 :   for (std::size_t e=0; e<dsupedge[0].size()/4; ++e) {
     499                 :       5684 :     const auto N = dsupedge[0].data() + e*4;
     500                 :            :     const auto d = dsupint[0].data();
     501         [ +  + ]:      22736 :     for (std::size_t i=0; i<3; ++i) {
     502         [ +  + ]:      68208 :       for (std::size_t j=0; j<3; ++j) {
     503                 :      51156 :         tk::real f[] = { d[(e*6+0)*4+j] * flux(U,G,i,j,N[1],N[0]),
     504                 :      51156 :                          d[(e*6+1)*4+j] * flux(U,G,i,j,N[2],N[1]),
     505                 :      51156 :                          d[(e*6+2)*4+j] * flux(U,G,i,j,N[0],N[2]),
     506                 :      51156 :                          d[(e*6+3)*4+j] * flux(U,G,i,j,N[3],N[0]),
     507                 :      51156 :                          d[(e*6+4)*4+j] * flux(U,G,i,j,N[3],N[1]),
     508                 :      51156 :                          d[(e*6+5)*4+j] * flux(U,G,i,j,N[3],N[2]) };
     509                 :      51156 :         F(N[0],i) = F(N[0],i) - f[0] + f[2] - f[3];
     510                 :      51156 :         F(N[1],i) = F(N[1],i) + f[0] - f[1] - f[4];
     511                 :      51156 :         F(N[2],i) = F(N[2],i) + f[1] - f[2] - f[5];
     512                 :      51156 :         F(N[3],i) = F(N[3],i) + f[3] + f[4] + f[5];
     513                 :            :       }
     514                 :            :     }
     515                 :            :   }
     516                 :            : 
     517                 :            :   // domain edge contributions: triangle superedges
     518         [ +  + ]:       6007 :   for (std::size_t e=0; e<dsupedge[1].size()/3; ++e) {
     519                 :       5682 :     const auto N = dsupedge[1].data() + e*3;
     520                 :            :     const auto d = dsupint[1].data();
     521         [ +  + ]:      22728 :     for (std::size_t i=0; i<3; ++i) {
     522         [ +  + ]:      68184 :       for (std::size_t j=0; j<3; ++j) {
     523                 :      51138 :         tk::real f[] = { d[(e*3+0)*4+j] * flux(U,G,i,j,N[1],N[0]),
     524                 :      51138 :                          d[(e*3+1)*4+j] * flux(U,G,i,j,N[2],N[1]),
     525                 :      51138 :                          d[(e*3+2)*4+j] * flux(U,G,i,j,N[0],N[2]), };
     526                 :      51138 :         F(N[0],i) = F(N[0],i) - f[0] + f[2];
     527                 :      51138 :         F(N[1],i) = F(N[1],i) + f[0] - f[1];
     528                 :      51138 :         F(N[2],i) = F(N[2],i) + f[1] - f[2];
     529                 :            :       }
     530                 :            :     }
     531                 :            :   }
     532                 :            : 
     533                 :            :   // domain edge contributions: edges
     534         [ +  + ]:      14617 :   for (std::size_t e=0; e<dsupedge[2].size()/2; ++e) {
     535                 :      14292 :     const auto N = dsupedge[2].data() + e*2;
     536                 :      14292 :     const auto d = dsupint[2].data() + e*4;
     537         [ +  + ]:      57168 :     for (std::size_t i=0; i<3; ++i) {
     538         [ +  + ]:     171504 :       for (std::size_t j=0; j<3; ++j) {
     539                 :     128628 :         tk::real f = d[j] * flux(U,G,i,j,N[1],N[0]);
     540                 :     128628 :         F(N[0],i) -= f;
     541                 :     128628 :         F(N[1],i) += f;
     542                 :            :       }
     543                 :            :     }
     544                 :            :   }
     545                 :            : 
     546                 :            :   // boundary integral
     547                 :            : 
     548                 :            :   const auto& x = coord[0];
     549                 :            :   const auto& y = coord[1];
     550                 :            :   const auto& z = coord[2];
     551                 :            : 
     552         [ +  + ]:      23821 :   for (std::size_t e=0; e<triinpoel.size()/3; ++e) {
     553                 :      23496 :     const auto N = triinpoel.data() + e*3;
     554                 :            :     tk::real n[3];
     555                 :      23496 :     tk::crossdiv( x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]],
     556                 :      23496 :                   x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]], 6.0,
     557                 :            :                   n[0], n[1], n[2] );
     558         [ +  + ]:      93984 :     for (std::size_t i=0; i<3; ++i) {
     559                 :      70488 :       auto fxA = flux(U,G,i,0,N[0]);
     560                 :      70488 :       auto fyA = flux(U,G,i,1,N[0]);
     561                 :      70488 :       auto fzA = flux(U,G,i,2,N[0]);
     562                 :      70488 :       auto fxB = flux(U,G,i,0,N[1]);
     563                 :      70488 :       auto fyB = flux(U,G,i,1,N[1]);
     564                 :      70488 :       auto fzB = flux(U,G,i,2,N[1]);
     565                 :      70488 :       auto fxC = flux(U,G,i,0,N[2]);
     566                 :      70488 :       auto fyC = flux(U,G,i,1,N[2]);
     567                 :      70488 :       auto fzC = flux(U,G,i,2,N[2]);
     568                 :      70488 :       auto fx = (6.0*fxA + fxB + fxC)/8.0;
     569                 :      70488 :       auto fy = (6.0*fyA + fyB + fyC)/8.0;
     570                 :      70488 :       auto fz = (6.0*fzA + fzB + fzC)/8.0;
     571                 :      70488 :       F(N[0],i) += fx*n[0] + fy*n[1] + fz*n[2];
     572                 :      70488 :       fx = (fxA + 6.0*fxB + fxC)/8.0;
     573                 :      70488 :       fy = (fyA + 6.0*fyB + fyC)/8.0;
     574                 :      70488 :       fz = (fzA + 6.0*fzB + fzC)/8.0;
     575                 :      70488 :       F(N[1],i) += fx*n[0] + fy*n[1] + fz*n[2];
     576                 :      70488 :       fx = (fxA + fxB + 6.0*fxC)/8.0;
     577                 :      70488 :       fy = (fyA + fyB + 6.0*fyC)/8.0;
     578                 :      70488 :       fz = (fzA + fzB + 6.0*fzC)/8.0;
     579                 :      70488 :       F(N[2],i) += fx*n[0] + fy*n[1] + fz*n[2];
     580                 :            :     }
     581                 :            :   }
     582                 :            : 
     583                 :            :   #if defined(__clang__)
     584                 :            :     #pragma clang diagnostic pop
     585                 :            :   #elif defined(STRICT_GNUC)
     586                 :            :     #pragma GCC diagnostic pop
     587                 :            :   #endif
     588                 :        325 : }
     589                 :            : 
     590                 :            : void
     591         [ +  - ]:        140 : grad( const std::array< std::vector< std::size_t >, 3 >& dsupedge,
     592                 :            :       const std::array< std::vector< tk::real >, 3 >& dsupint,
     593                 :            :       const std::array< std::vector< tk::real >, 3 >& coord,
     594                 :            :       const std::vector< std::size_t >& triinpoel,
     595                 :            :       const tk::Fields& U,
     596                 :            :       tk::Fields& G )
     597                 :            : // *****************************************************************************
     598                 :            : //  Compute gradients of scalar in all points
     599                 :            : //! \param[in] dsupedge Domain superedges
     600                 :            : //! \param[in] dsupint Domain superedge integrals
     601                 :            : //! \param[in] coord Mesh node coordinates
     602                 :            : //! \param[in] triinpoel Boundary face connectivity
     603                 :            : //! \param[in] U Unknown vector whose gradient to compute
     604                 :            : //! \param[in,out] G Nodal gradients in all points
     605                 :            : // *****************************************************************************
     606                 :            : {
     607         [ +  - ]:        140 :   if (G.nprop() == 0) return;
     608                 :            : 
     609                 :            :   Assert( G.nunk() == U.nunk(), "Size mismatch" );
     610                 :            :   Assert( G.nprop() > 2, "Size mismatch" );
     611                 :            :   Assert( G.nprop() % 3 == 0, "Size mismatch" );
     612                 :            :   Assert( G.nprop() == (U.nprop()-1)*3, "Size mismatch" );
     613                 :            : 
     614                 :            :   const auto ncomp = U.nprop();
     615                 :            : 
     616                 :            :   #if defined(__clang__)
     617                 :            :     #pragma clang diagnostic push
     618                 :            :     #pragma clang diagnostic ignored "-Wvla"
     619                 :            :     #pragma clang diagnostic ignored "-Wvla-extension"
     620                 :            :   #elif defined(STRICT_GNUC)
     621                 :            :     #pragma GCC diagnostic push
     622                 :            :     #pragma GCC diagnostic ignored "-Wvla"
     623                 :            :   #endif
     624                 :            : 
     625                 :            :   // domain integral
     626                 :            : 
     627                 :            :   // domain edge contributions: tetrahedron superedges
     628         [ +  + ]:      70000 :   for (std::size_t e=0; e<dsupedge[0].size()/4; ++e) {
     629                 :      69860 :     const auto N = dsupedge[0].data() + e*4;
     630                 :            :     const auto d = dsupint[0].data();
     631         [ +  + ]:     279440 :     for (std::size_t c=1; c<ncomp; ++c) {
     632                 :     209580 :       tk::real u[] = { U(N[0],c), U(N[1],c), U(N[2],c), U(N[3],c) };
     633                 :     209580 :       auto g = (c-1)*3;
     634         [ +  + ]:     838320 :       for (std::size_t j=0; j<3; ++j) {
     635                 :            :         tk::real f[] = {
     636                 :     628740 :           d[(e*6+0)*4+j] * (u[1] + u[0]),
     637                 :     628740 :           d[(e*6+1)*4+j] * (u[2] + u[1]),
     638                 :     628740 :           d[(e*6+2)*4+j] * (u[0] + u[2]),
     639                 :     628740 :           d[(e*6+3)*4+j] * (u[3] + u[0]),
     640                 :     628740 :           d[(e*6+4)*4+j] * (u[3] + u[1]),
     641                 :     628740 :           d[(e*6+5)*4+j] * (u[3] + u[2]) };
     642                 :     628740 :         G(N[0],g+j) = G(N[0],g+j) - f[0] + f[2] - f[3];
     643                 :     628740 :         G(N[1],g+j) = G(N[1],g+j) + f[0] - f[1] - f[4];
     644                 :     628740 :         G(N[2],g+j) = G(N[2],g+j) + f[1] - f[2] - f[5];
     645                 :     628740 :         G(N[3],g+j) = G(N[3],g+j) + f[3] + f[4] + f[5];
     646                 :            :       }
     647                 :            :     }
     648                 :            :   }
     649                 :            : 
     650                 :            :   // domain edge contributions: triangle superedges
     651         [ +  + ]:      69440 :   for (std::size_t e=0; e<dsupedge[1].size()/3; ++e) {
     652                 :      69300 :     const auto N = dsupedge[1].data() + e*3;
     653                 :            :     const auto d = dsupint[1].data();
     654         [ +  + ]:     277200 :     for (std::size_t c=1; c<ncomp; ++c) {
     655                 :     207900 :       tk::real u[] = { U(N[0],c), U(N[1],c), U(N[2],c) };
     656                 :     207900 :       auto g = (c-1)*3;
     657         [ +  + ]:     831600 :       for (std::size_t j=0; j<3; ++j) {
     658                 :            :         tk::real f[] = {
     659                 :     623700 :           d[(e*3+0)*4+j] * (u[1] + u[0]),
     660                 :     623700 :           d[(e*3+1)*4+j] * (u[2] + u[1]),
     661                 :     623700 :           d[(e*3+2)*4+j] * (u[0] + u[2]) };
     662                 :     623700 :         G(N[0],g+j) = G(N[0],g+j) - f[0] + f[2];
     663                 :     623700 :         G(N[1],g+j) = G(N[1],g+j) + f[0] - f[1];
     664                 :     623700 :         G(N[2],g+j) = G(N[2],g+j) + f[1] - f[2];
     665                 :            :       }
     666                 :            :     }
     667                 :            :   }
     668                 :            : 
     669                 :            :   // domain edge contributions: edges
     670         [ +  + ]:     132020 :   for (std::size_t e=0; e<dsupedge[2].size()/2; ++e) {
     671                 :     131880 :     const auto N = dsupedge[2].data() + e*2;
     672                 :     131880 :     const auto d = dsupint[2].data() + e*4;
     673         [ +  + ]:     527520 :     for (std::size_t c=1; c<ncomp; ++c) {
     674                 :     395640 :       tk::real u[] = { U(N[0],c), U(N[1],c) };
     675                 :     395640 :       auto g = (c-1)*3;
     676         [ +  + ]:    1582560 :       for (std::size_t j=0; j<3; ++j) {
     677                 :    1186920 :         tk::real f = d[j] * (u[1] + u[0]);
     678                 :    1186920 :         G(N[0],g+j) -= f;
     679                 :    1186920 :         G(N[1],g+j) += f;
     680                 :            :       }
     681                 :            :     }
     682                 :            :   }
     683                 :            : 
     684                 :            :   // boundary integral
     685                 :            : 
     686                 :            :   const auto& x = coord[0];
     687                 :            :   const auto& y = coord[1];
     688                 :            :   const auto& z = coord[2];
     689                 :            : 
     690         [ +  + ]:     338940 :   for (std::size_t e=0; e<triinpoel.size()/3; ++e) {
     691                 :     338800 :     const auto N = triinpoel.data() + e*3;
     692                 :            :     tk::real n[3];
     693                 :     338800 :     tk::crossdiv( x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]],
     694                 :     338800 :                   x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]], 6.0,
     695                 :            :                   n[0], n[1], n[2] );
     696         [ +  + ]:    1355200 :     for (std::size_t c=1; c<ncomp; ++c) {
     697                 :    1016400 :       auto g = (c-1)*3;
     698                 :    1016400 :       auto uA = U(N[0],c);
     699                 :    1016400 :       auto uB = U(N[1],c);
     700                 :    1016400 :       auto uC = U(N[2],c);
     701                 :    1016400 :       auto f = (6.0*uA + uB + uC)/8.0;
     702                 :    1016400 :       G(N[0],g+0) += f * n[0];
     703                 :    1016400 :       G(N[0],g+1) += f * n[1];
     704                 :    1016400 :       G(N[0],g+2) += f * n[2];
     705                 :    1016400 :       f = (uA + 6.0*uB + uC)/8.0;
     706                 :    1016400 :       G(N[1],g+0) += f * n[0];
     707                 :    1016400 :       G(N[1],g+1) += f * n[1];
     708                 :    1016400 :       G(N[1],g+2) += f * n[2];
     709                 :    1016400 :       f = (uA + uB + 6.0*uC)/8.0;
     710                 :    1016400 :       G(N[2],g+0) += f * n[0];
     711                 :    1016400 :       G(N[2],g+1) += f * n[1];
     712                 :    1016400 :       G(N[2],g+2) += f * n[2];
     713                 :            :     }
     714                 :            :   }
     715                 :            : 
     716                 :            :   #if defined(__clang__)
     717                 :            :     #pragma clang diagnostic pop
     718                 :            :   #elif defined(STRICT_GNUC)
     719                 :            :     #pragma GCC diagnostic pop
     720                 :            :   #endif
     721                 :            : }
     722                 :            : 
     723                 :            : static void
     724                 :    1748200 : adv_damp2( const tk::real supint[],
     725                 :            :            const tk::Fields& U,
     726                 :            :            const tk::Fields&,
     727                 :            :            const std::array< std::vector< tk::real >, 3 >&,
     728                 :            :            std::size_t p,
     729                 :            :            std::size_t q,
     730                 :            :            tk::real f[] )
     731                 :            : // *****************************************************************************
     732                 :            : //! Compute advection fluxes on a single edge using 2nd-order damping
     733                 :            : //! \param[in] supint Edge integral
     734                 :            : //! \param[in] U Velocity and transported scalars at recent time step
     735                 :            : //! \param[in] p Left node index of edge
     736                 :            : //! \param[in] q Right node index of edge
     737                 :            : //! \param[in,out] f Flux computed
     738                 :            : // *****************************************************************************
     739                 :            : {
     740                 :    1748200 :   auto nx = supint[0];
     741                 :    1748200 :   auto ny = supint[1];
     742         [ +  + ]:    1748200 :   auto nz = supint[2];
     743                 :            : 
     744                 :            :   // left state
     745                 :    1748200 :   auto pL = U(p,0);
     746                 :    1748200 :   auto uL = U(p,1);
     747                 :    1748200 :   auto vL = U(p,2);
     748                 :    1748200 :   auto wL = U(p,3);
     749                 :    1748200 :   auto vnL = uL*nx + vL*ny + wL*nz;
     750                 :            : 
     751                 :            :   // right state
     752                 :    1748200 :   auto pR = U(q,0);
     753                 :    1748200 :   auto uR = U(q,1);
     754                 :    1748200 :   auto vR = U(q,2);
     755                 :    1748200 :   auto wR = U(q,3);
     756                 :    1748200 :   auto vnR = uR*nx + vR*ny + wR*nz;
     757                 :            : 
     758                 :    1748200 :   auto s = g_cfg.get< tag::soundspeed >();
     759                 :    1748200 :   auto s2 = s*s;
     760                 :    1748200 :   auto d = supint[3] * g_cfg.get< tag::mat_dyn_viscosity >();
     761                 :            : 
     762                 :            :   // flow
     763                 :    1748200 :   auto pf = pL + pR;
     764                 :    1748200 :   f[0] = (vnL + vnR)*s2;
     765                 :    1748200 :   f[1] = uL*vnL + uR*vnR + pf*nx - d*(uR - uL);
     766                 :    1748200 :   f[2] = vL*vnL + vR*vnR + pf*ny - d*(vR - vL);
     767                 :    1748200 :   f[3] = wL*vnL + wR*vnR + pf*nz - d*(wR - wL);
     768                 :            : 
     769                 :            :   // artificial viscosity
     770                 :    1748200 :   const auto stab2 = g_cfg.get< tag::stab2 >();
     771         [ +  + ]:    1748200 :   if (!stab2) return;
     772                 :            : 
     773                 :            :   auto len = tk::length( nx, ny, nz );
     774                 :    1472460 :   auto sl = std::abs(vnL) + s*len;
     775                 :    1472460 :   auto sr = std::abs(vnR) + s*len;
     776         [ +  + ]:    1472460 :   auto aw = g_cfg.get< tag::stab2coef >() * std::max(sl,sr) * len;
     777                 :    1472460 :   f[0] += aw * (pR - pL)*s2;
     778                 :    1472460 :   f[1] += aw * (uR - uL);
     779                 :    1472460 :   f[2] += aw * (vR - vL);
     780                 :    1472460 :   f[3] += aw * (wR - wL);
     781                 :            : }
     782                 :            : 
     783                 :            : static void
     784                 :     758940 : adv_damp4( const tk::real supint[],
     785                 :            :            const tk::Fields& U,
     786                 :            :            const tk::Fields& G,
     787                 :            :            const std::array< std::vector< tk::real >, 3 >& coord,
     788                 :            :            std::size_t p,
     789                 :            :            std::size_t q,
     790                 :            :            tk::real f[] )
     791                 :            : // *****************************************************************************
     792                 :            : //! Compute advection fluxes on a single edge using 4th-order damping
     793                 :            : //! \param[in] supint Edge integral
     794                 :            : //! \param[in] U Velocity and transported scalars at recent time step
     795                 :            : //! \param[in] G Gradients of velocity and transported scalars
     796                 :            : //! \param[in] coord Mesh node coordinates
     797                 :            : //! \param[in] p Left node index of edge
     798                 :            : //! \param[in] q Right node index of edge
     799                 :            : //! \param[in,out] f Flux computed
     800                 :            : // *****************************************************************************
     801                 :            : {
     802                 :            :   const auto ncomp = U.nprop();
     803                 :            : 
     804                 :            :   const auto& x = coord[0];
     805                 :            :   const auto& y = coord[1];
     806                 :            :   const auto& z = coord[2];
     807                 :            : 
     808                 :            :   // edge vector
     809                 :     758940 :   auto dx = x[p] - x[q];
     810                 :     758940 :   auto dy = y[p] - y[q];
     811                 :     758940 :   auto dz = z[p] - z[q];
     812                 :            : 
     813                 :            :   #if defined(__clang__)
     814                 :            :     #pragma clang diagnostic push
     815                 :            :     #pragma clang diagnostic ignored "-Wvla"
     816                 :            :     #pragma clang diagnostic ignored "-Wvla-extension"
     817                 :            :   #elif defined(STRICT_GNUC)
     818                 :            :     #pragma GCC diagnostic push
     819                 :            :     #pragma GCC diagnostic ignored "-Wvla"
     820                 :            :   #endif
     821                 :            : 
     822                 :     758940 :   tk::real uL[] = { U(p,1), U(p,2), U(p,3) };
     823                 :     758940 :   tk::real uR[] = { U(q,1), U(q,2), U(q,3) };
     824                 :            : 
     825                 :            :   // MUSCL reconstruction in edge-end points
     826         [ +  + ]:    3035760 :   for (std::size_t c=0; c<ncomp-1; ++c) {
     827                 :    2276820 :     auto g = c*3;
     828                 :    2276820 :     auto g1 = G(p,g+0)*dx + G(p,g+1)*dy + G(p,g+2)*dz;
     829                 :    2276820 :     auto g2 = G(q,g+0)*dx + G(q,g+1)*dy + G(q,g+2)*dz;
     830                 :    2276820 :     auto delta2 = uR[c] - uL[c];
     831                 :    2276820 :     auto delta1 = 2.0 * g1 - delta2;
     832                 :    2276820 :     auto delta3 = 2.0 * g2 - delta2;
     833                 :            : 
     834                 :            :     // van Leer limiter
     835                 :    2276820 :     auto rL = (delta2 + muscl_eps) / (delta1 + muscl_eps);
     836                 :    2276820 :     auto rR = (delta2 + muscl_eps) / (delta3 + muscl_eps);
     837                 :    2276820 :     auto rLinv = (delta1 + muscl_eps) / (delta2 + muscl_eps);
     838                 :    2276820 :     auto rRinv = (delta3 + muscl_eps) / (delta2 + muscl_eps);
     839                 :    2276820 :     auto phiL = (std::abs(rL) + rL) / (std::abs(rL) + 1.0);
     840                 :    2276820 :     auto phiR = (std::abs(rR) + rR) / (std::abs(rR) + 1.0);
     841                 :    2276820 :     auto phi_L_inv = (std::abs(rLinv) + rLinv) / (std::abs(rLinv) + 1.0);
     842                 :    2276820 :     auto phi_R_inv = (std::abs(rRinv) + rRinv) / (std::abs(rRinv) + 1.0);
     843                 :            :     // update unknowns with reconstructed unknowns
     844                 :    2276820 :     uL[c] += 0.25*(delta1*(1.0-muscl_const)*phiL +
     845                 :    2276820 :                    delta2*(1.0+muscl_const)*phi_L_inv);
     846                 :    2276820 :     uR[c] -= 0.25*(delta3*(1.0-muscl_const)*phiR +
     847                 :    2276820 :                    delta2*(1.0+muscl_const)*phi_R_inv);
     848                 :            :   }
     849                 :            : 
     850                 :     758940 :   auto nx = supint[0];
     851                 :     758940 :   auto ny = supint[1];
     852                 :     758940 :   auto nz = supint[2];
     853                 :            : 
     854                 :            :   // normal velocities
     855                 :     758940 :   auto vnL = uL[0]*nx + uL[1]*ny + uL[2]*nz;
     856                 :     758940 :   auto vnR = uR[0]*nx + uR[1]*ny + uR[2]*nz;
     857                 :            : 
     858                 :     758940 :   auto s = g_cfg.get< tag::soundspeed >();
     859                 :     758940 :   auto s2 = s*s;
     860         [ -  + ]:     758940 :   auto d = supint[3] * g_cfg.get< tag::mat_dyn_viscosity >();
     861                 :            : 
     862                 :            :   // flow
     863                 :     758940 :   auto pf = U(p,0) + U(q,0);
     864                 :     758940 :   f[0] = (vnL + vnR)*s2;
     865                 :     758940 :   f[1] = uL[0]*vnL + uR[0]*vnR + pf*nx - d*(uR[0] - uL[0]);
     866                 :     758940 :   f[2] = uL[1]*vnL + uR[1]*vnR + pf*ny - d*(uR[1] - uL[1]);
     867                 :     758940 :   f[3] = uL[2]*vnL + uR[2]*vnR + pf*nz - d*(uR[2] - uL[2]);
     868                 :            : 
     869                 :            :   // artificial viscosity
     870                 :     758940 :   const auto stab2 = g_cfg.get< tag::stab2 >();
     871         [ -  + ]:     758940 :   if (!stab2) return;
     872                 :            : 
     873                 :            :   auto len = tk::length( nx, ny, nz );
     874                 :     758940 :   auto sl = std::abs(vnL) + s*len;
     875                 :     758940 :   auto sr = std::abs(vnR) + s*len;
     876         [ +  + ]:     758940 :   auto aw = g_cfg.get< tag::stab2coef >() * std::max(sl,sr) * len;
     877                 :     758940 :   f[0] += aw * (U(q,0) - U(p,0))*s2;
     878                 :     758940 :   f[1] += aw * (uR[0] - uL[0]);
     879                 :     758940 :   f[2] += aw * (uR[1] - uL[1]);
     880                 :     758940 :   f[3] += aw * (uR[2] - uL[2]);
     881                 :            : 
     882                 :            :   #if defined(__clang__)
     883                 :            :     #pragma clang diagnostic pop
     884                 :            :   #elif defined(STRICT_GNUC)
     885                 :            :     #pragma GCC diagnostic pop
     886                 :            :   #endif
     887                 :            : }
     888                 :            : 
     889                 :            : static void
     890                 :       4660 : adv( const std::array< std::vector< std::size_t >, 3 >& dsupedge,
     891                 :            :      const std::array< std::vector< tk::real >, 3 >& dsupint,
     892                 :            :      const std::array< std::vector< tk::real >, 3 >& coord,
     893                 :            :      const std::vector< std::size_t >& triinpoel,
     894                 :            :      const tk::Fields& U,
     895                 :            :      const tk::Fields& G,
     896                 :            :      // cppcheck-suppress constParameter
     897                 :            :      tk::Fields& R )
     898                 :            : // *****************************************************************************
     899                 :            : //! Add advection to rhs
     900                 :            : //! \param[in] dsupedge Domain superedges
     901                 :            : //! \param[in] dsupint Domain superedge integrals
     902                 :            : //! \param[in] coord Mesh node coordinates
     903                 :            : //! \param[in] triinpoel Boundary face connectivity
     904                 :            : //! \param[in] U Velocity and transported scalars at recent time step
     905                 :            : //! \param[in] G Gradients of velocity and transported scalars
     906                 :            : //! \param[in,out] R Right-hand side vector added to
     907                 :            : // *****************************************************************************
     908                 :            : {
     909                 :            :   const auto ncomp = U.nprop();
     910                 :            : 
     911                 :            :   // configure advection
     912                 :       4660 :   auto adv = [](){
     913                 :            :     const auto& flux = g_cfg.get< tag::flux >();
     914         [ +  + ]:       4660 :          if (flux == "damp2") return adv_damp2;
     915         [ -  + ]:        140 :     else if (flux == "damp4") return adv_damp4;
     916 [ -  - ][ -  - ]:          0 :     else Throw( "Flux not correctly configured" );
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
     917                 :       4660 :   }();
     918                 :            : 
     919                 :            :   #if defined(__clang__)
     920                 :            :     #pragma clang diagnostic push
     921                 :            :     #pragma clang diagnostic ignored "-Wvla"
     922                 :            :     #pragma clang diagnostic ignored "-Wvla-extension"
     923                 :            :   #elif defined(STRICT_GNUC)
     924                 :            :     #pragma GCC diagnostic push
     925                 :            :     #pragma GCC diagnostic ignored "-Wvla"
     926                 :            :   #endif
     927                 :            : 
     928                 :            :   // domain integral
     929                 :            : 
     930                 :            :   // domain edge contributions: tetrahedron superedges
     931         [ +  + ]:     229120 :   for (std::size_t e=0; e<dsupedge[0].size()/4; ++e) {
     932                 :     224460 :     const auto N = dsupedge[0].data() + e*4;
     933                 :     224460 :     tk::real f[6][ncomp];
     934                 :            :     const auto d = dsupint[0].data();
     935                 :     224460 :     adv( d+(e*6+0)*4, U, G, coord, N[0], N[1], f[0] );
     936                 :     224460 :     adv( d+(e*6+1)*4, U, G, coord, N[1], N[2], f[1] );
     937                 :     224460 :     adv( d+(e*6+2)*4, U, G, coord, N[2], N[0], f[2] );
     938                 :     224460 :     adv( d+(e*6+3)*4, U, G, coord, N[0], N[3], f[3] );
     939                 :     224460 :     adv( d+(e*6+4)*4, U, G, coord, N[1], N[3], f[4] );
     940                 :     224460 :     adv( d+(e*6+5)*4, U, G, coord, N[2], N[3], f[5] );
     941         [ +  + ]:    1122300 :     for (std::size_t c=0; c<ncomp; ++c) {
     942                 :     897840 :       R(N[0],c) = R(N[0],c) - f[0][c] + f[2][c] - f[3][c];
     943                 :     897840 :       R(N[1],c) = R(N[1],c) + f[0][c] - f[1][c] - f[4][c];
     944                 :     897840 :       R(N[2],c) = R(N[2],c) + f[1][c] - f[2][c] - f[5][c];
     945                 :     897840 :       R(N[3],c) = R(N[3],c) + f[3][c] + f[4][c] + f[5][c];
     946                 :            :     }
     947                 :     224460 :   }
     948                 :            : 
     949                 :            :   // domain edge contributions: triangle superedges
     950         [ +  + ]:     230050 :   for (std::size_t e=0; e<dsupedge[1].size()/3; ++e) {
     951                 :     225390 :     const auto N = dsupedge[1].data() + e*3;
     952                 :     225390 :     tk::real f[3][ncomp];
     953                 :            :     const auto d = dsupint[1].data();
     954                 :     225390 :     adv( d+(e*3+0)*4, U, G, coord, N[0], N[1], f[0] );
     955                 :     225390 :     adv( d+(e*3+1)*4, U, G, coord, N[1], N[2], f[1] );
     956                 :     225390 :     adv( d+(e*3+2)*4, U, G, coord, N[2], N[0], f[2] );
     957         [ +  + ]:    1126950 :     for (std::size_t c=0; c<ncomp; ++c) {
     958                 :     901560 :       R(N[0],c) = R(N[0],c) - f[0][c] + f[2][c];
     959                 :     901560 :       R(N[1],c) = R(N[1],c) + f[0][c] - f[1][c];
     960                 :     901560 :       R(N[2],c) = R(N[2],c) + f[1][c] - f[2][c];
     961                 :            :     }
     962                 :     225390 :   }
     963                 :            : 
     964                 :            :   // domain edge contributions: edges
     965         [ +  + ]:     488870 :   for (std::size_t e=0; e<dsupedge[2].size()/2; ++e) {
     966                 :     484210 :     const auto N = dsupedge[2].data() + e*2;
     967                 :     484210 :     tk::real f[ncomp];
     968                 :            :     const auto d = dsupint[2].data();
     969                 :     484210 :     adv( d+e*4, U, G, coord, N[0], N[1], f );
     970         [ +  + ]:    2421050 :     for (std::size_t c=0; c<ncomp; ++c) {
     971                 :    1936840 :       R(N[0],c) -= f[c];
     972                 :    1936840 :       R(N[1],c) += f[c];
     973                 :            :     }
     974                 :     484210 :   }
     975                 :            : 
     976                 :            :   // boundary integral
     977                 :            : 
     978                 :            :   const auto& x = coord[0];
     979                 :            :   const auto& y = coord[1];
     980                 :            :   const auto& z = coord[2];
     981                 :            : 
     982                 :       4660 :   auto s = g_cfg.get< tag::soundspeed >();
     983                 :       4660 :   auto s2 = s * s;
     984                 :            : 
     985         [ +  + ]:    1046660 :   for (std::size_t e=0; e<triinpoel.size()/3; ++e) {
     986                 :    1042000 :     const auto N = triinpoel.data() + e*3;
     987                 :            :     tk::real n[3];
     988                 :    1042000 :     tk::crossdiv( x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]],
     989                 :    1042000 :                   x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]], 6.0,
     990                 :            :                   n[0], n[1], n[2] );
     991                 :    1042000 :     tk::real f[ncomp][3];
     992                 :            : 
     993                 :    1042000 :     auto p = U(N[0],0);
     994                 :    1042000 :     auto u = U(N[0],1);
     995                 :    1042000 :     auto v = U(N[0],2);
     996                 :    1042000 :     auto w = U(N[0],3);
     997                 :    1042000 :     auto vn = n[0]*u + n[1]*v + n[2]*w;
     998                 :    1042000 :     f[0][0] = vn * s2;
     999                 :    1042000 :     f[1][0] = u*vn + p*n[0];
    1000                 :    1042000 :     f[2][0] = v*vn + p*n[1];
    1001                 :    1042000 :     f[3][0] = w*vn + p*n[2];
    1002                 :            : 
    1003                 :    1042000 :     p = U(N[1],0);
    1004                 :    1042000 :     u = U(N[1],1);
    1005                 :    1042000 :     v = U(N[1],2);
    1006                 :    1042000 :     w = U(N[1],3);
    1007                 :    1042000 :     vn = n[0]*u + n[1]*v + n[2]*w;
    1008                 :    1042000 :     f[0][1] = vn * s2;
    1009                 :    1042000 :     f[1][1] = u*vn + p*n[0];
    1010                 :    1042000 :     f[2][1] = v*vn + p*n[1];
    1011                 :    1042000 :     f[3][1] = w*vn + p*n[2];
    1012                 :            : 
    1013                 :    1042000 :     p = U(N[2],0);
    1014                 :    1042000 :     u = U(N[2],1);
    1015                 :    1042000 :     v = U(N[2],2);
    1016                 :    1042000 :     w = U(N[2],3);
    1017                 :    1042000 :     vn = n[0]*u + n[1]*v + n[2]*w;
    1018                 :    1042000 :     f[0][2] = vn * s2;
    1019                 :    1042000 :     f[1][2] = u*vn + p*n[0];
    1020                 :    1042000 :     f[2][2] = v*vn + p*n[1];
    1021                 :    1042000 :     f[3][2] = w*vn + p*n[2];
    1022                 :            : 
    1023         [ +  + ]:    5210000 :     for (std::size_t c=0; c<ncomp; ++c) {
    1024                 :    4168000 :       R(N[0],c) += (6.0*f[c][0] + f[c][1] + f[c][2])/8.0;
    1025                 :    4168000 :       R(N[1],c) += (f[c][0] + 6.0*f[c][1] + f[c][2])/8.0;
    1026                 :    4168000 :       R(N[2],c) += (f[c][0] + f[c][1] + 6.0*f[c][2])/8.0;
    1027                 :            :     }
    1028                 :    1042000 :   }
    1029                 :            : 
    1030                 :            :   #if defined(__clang__)
    1031                 :            :     #pragma clang diagnostic pop
    1032                 :            :   #elif defined(STRICT_GNUC)
    1033                 :            :     #pragma GCC diagnostic pop
    1034                 :            :   #endif
    1035                 :       4660 : }
    1036                 :            : 
    1037                 :            : void
    1038                 :       4660 : rhs( const std::array< std::vector< std::size_t >, 3 >& dsupedge,
    1039                 :            :      const std::array< std::vector< tk::real >, 3 >& dsupint,
    1040                 :            :      const std::array< std::vector< tk::real >, 3 >& coord,
    1041                 :            :      const std::vector< std::size_t >& triinpoel,
    1042                 :            :      const tk::Fields& U,
    1043                 :            :      const tk::Fields& G,
    1044                 :            :      tk::Fields& R )
    1045                 :            : // *****************************************************************************
    1046                 :            : //  Compute right hand side
    1047                 :            : //! \param[in] dsupedge Domain superedges
    1048                 :            : //! \param[in] dsupint Domain superedge integrals
    1049                 :            : //! \param[in] coord Mesh node coordinates
    1050                 :            : //! \param[in] triinpoel Boundary face connectivity
    1051                 :            : //! \param[in] U Solution vector of primitive variables at recent time step
    1052                 :            : //! \param[in] G Gradients of velocity and transported scalars
    1053                 :            : //! \param[in,out] R Right-hand side vector computed
    1054                 :            : // *****************************************************************************
    1055                 :            : {
    1056                 :            :   Assert( U.nunk() == coord[0].size(), "Number of unknowns in solution "
    1057                 :            :           "vector at recent time step incorrect" );
    1058                 :            :   Assert( R.nunk() == coord[0].size(),
    1059                 :            :           "Number of unknowns and/or number of components in right-hand "
    1060                 :            :           "side vector incorrect" );
    1061                 :            : 
    1062                 :            :   R.fill( 0.0 );
    1063                 :       4660 :   adv( dsupedge, dsupint, coord, triinpoel, U, G, R );
    1064                 :       4660 : }
    1065                 :            : 
    1066                 :            : } // lohner::

Generated by: LCOV version 1.16