Xyst test code coverage report
Current view: top level - Physics - Chorin.cpp (source / functions) Hit Total Coverage
Commit: 5689ba12dc66a776d3d75f1ee48cc7d78eaa18dc Lines: 437 447 97.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: 115 140 82.1 %

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

Generated by: LCOV version 1.16