Quinoa all test code coverage report
Current view: top level - PDE/Integrate - Surface.cpp (source / functions) Hit Total Coverage
Commit: -128-NOTFOUND Lines: 151 294 51.4 %
Date: 2024-11-22 08:51:48 Functions: 3 5 60.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 83 358 23.2 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/PDE/Integrate/Surface.cpp
       4                 :            :   \copyright 2012-2015 J. Bakosi,
       5                 :            :              2016-2018 Los Alamos National Security, LLC.,
       6                 :            :              2019-2021 Triad National Security, LLC.
       7                 :            :              All rights reserved. See the LICENSE file for details.
       8                 :            :   \brief     Functions for computing internal surface integrals of a system
       9                 :            :      of PDEs in DG methods
      10                 :            :   \details   This file contains functionality for computing internal surface
      11                 :            :      integrals of a system of PDEs used in discontinuous Galerkin methods for
      12                 :            :      various orders of numerical representation.
      13                 :            : */
      14                 :            : // *****************************************************************************
      15                 :            : 
      16                 :            : #include <array>
      17                 :            : 
      18                 :            : #include "Surface.hpp"
      19                 :            : #include "Vector.hpp"
      20                 :            : #include "Quadrature.hpp"
      21                 :            : #include "Reconstruction.hpp"
      22                 :            : #include "Integrate/SolidTerms.hpp"
      23                 :            : #include "Inciter/InputDeck/InputDeck.hpp"
      24                 :            : #include "MultiMat/MiscMultiMatFns.hpp"
      25                 :            : #include "EoS/GetMatProp.hpp"
      26                 :            : 
      27                 :            : namespace inciter {
      28                 :            : extern ctr::InputDeck g_inputdeck;
      29                 :            : }
      30                 :            : 
      31                 :            : namespace tk {
      32                 :            : 
      33                 :            : void
      34                 :      65205 : surfInt( const bool pref,
      35                 :            :          std::size_t nmat,
      36                 :            :          const std::vector< inciter::EOS >& mat_blk,
      37                 :            :          real t,
      38                 :            :          const std::size_t ndof,
      39                 :            :          const std::size_t rdof,
      40                 :            :          const std::vector< std::size_t >& inpoel,
      41                 :            :          const std::vector< std::size_t >& /*solidx*/,
      42                 :            :          const UnsMesh::Coords& coord,
      43                 :            :          const inciter::FaceData& fd,
      44                 :            :          const Fields& geoFace,
      45                 :            :          const Fields& geoElem,
      46                 :            :          const RiemannFluxFn& flux,
      47                 :            :          const VelFn& vel,
      48                 :            :          const Fields& U,
      49                 :            :          const Fields& P,
      50                 :            :          const std::vector< std::size_t >& ndofel,
      51                 :            :          const tk::real /*dt*/,
      52                 :            :          Fields& R,
      53                 :            :          std::vector< std::vector< tk::real > >& riemannDeriv,
      54                 :            :          int intsharp )
      55                 :            : // *****************************************************************************
      56                 :            : //  Compute internal surface flux integrals
      57                 :            : //! \param[in] pref Indicator for p-adaptive algorithm
      58                 :            : //! \param[in] nmat Number of materials in this PDE system
      59                 :            : //! \param[in] mat_blk EOS material block
      60                 :            : //! \param[in] t Physical time
      61                 :            : //! \param[in] ndof Maximum number of degrees of freedom
      62                 :            : //! \param[in] rdof Maximum number of reconstructed degrees of freedom
      63                 :            : //! \param[in] inpoel Element-node connectivity
      64                 :            : // //! \param[in] solidx Material index indicator
      65                 :            : //! \param[in] coord Array of nodal coordinates
      66                 :            : //! \param[in] fd Face connectivity and boundary conditions object
      67                 :            : //! \param[in] geoFace Face geometry array
      68                 :            : //! \param[in] geoElem Element geometry array
      69                 :            : //! \param[in] flux Riemann flux function to use
      70                 :            : //! \param[in] vel Function to use to query prescribed velocity (if any)
      71                 :            : //! \param[in] U Solution vector at recent time step
      72                 :            : //! \param[in] P Vector of primitives at recent time step
      73                 :            : //! \param[in] ndofel Vector of local number of degrees of freedom
      74                 :            : // //! \param[in] dt Delta time
      75                 :            : //! \param[in,out] R Right-hand side vector computed
      76                 :            : //! \param[in,out] riemannDeriv Derivatives of partial-pressures and velocities
      77                 :            : //!   computed from the Riemann solver for use in the non-conservative terms.
      78                 :            : //!   These derivatives are used only for multi-material hydro and unused for
      79                 :            : //!   single-material compflow and linear transport.
      80                 :            : //! \param[in] intsharp Interface compression tag, an optional argument, with
      81                 :            : //!   default 0, so that it is unused for single-material and transport.
      82                 :            : // *****************************************************************************
      83                 :            : {
      84                 :      65205 :   const auto& esuf = fd.Esuf();
      85                 :      65205 :   const auto& inpofa = fd.Inpofa();
      86                 :            : 
      87                 :      65205 :   const auto& cx = coord[0];
      88                 :      65205 :   const auto& cy = coord[1];
      89                 :      65205 :   const auto& cz = coord[2];
      90                 :            : 
      91                 :      65205 :   auto ncomp = U.nprop()/rdof;
      92                 :      65205 :   auto nprim = P.nprop()/rdof;
      93                 :            : 
      94                 :            :   //// Determine if we have solids in our problem
      95                 :            :   //bool haveSolid = inciter::haveSolid(nmat, solidx);
      96                 :            : 
      97                 :            :   //Assert( (nmat==1 ? riemannDeriv.empty() : true), "Non-empty Riemann "
      98                 :            :   //        "derivative vector for single material compflow" );
      99                 :            : 
     100                 :            :   // compute internal surface flux integrals
     101         [ +  + ]:   29323230 :   for (auto f=fd.Nbfac(); f<esuf.size()/2; ++f)
     102                 :            :   {
     103 [ +  - ][ +  - ]:   29258025 :     Assert( esuf[2*f] > -1 && esuf[2*f+1] > -1, "Interior element detected "
         [ -  - ][ -  - ]
                 [ -  - ]
     104                 :            :             "as -1" );
     105                 :            : 
     106                 :   29258025 :     std::size_t el = static_cast< std::size_t >(esuf[2*f]);
     107                 :   29258025 :     std::size_t er = static_cast< std::size_t >(esuf[2*f+1]);
     108                 :            : 
     109         [ +  - ]:   29258025 :     auto ng_l = tk::NGfa(ndofel[el]);
     110         [ +  - ]:   29258025 :     auto ng_r = tk::NGfa(ndofel[er]);
     111                 :            : 
     112                 :            :     // When the number of gauss points for the left and right element are
     113                 :            :     // different, choose the larger ng
     114                 :   29258025 :     auto ng = std::max( ng_l, ng_r );
     115                 :            : 
     116                 :            :     // arrays for quadrature points
     117                 :   58516050 :     std::array< std::vector< real >, 2 > coordgp;
     118                 :   58516050 :     std::vector< real > wgp;
     119                 :            : 
     120         [ +  - ]:   29258025 :     coordgp[0].resize( ng );
     121         [ +  - ]:   29258025 :     coordgp[1].resize( ng );
     122         [ +  - ]:   29258025 :     wgp.resize( ng );
     123                 :            : 
     124                 :            :     // get quadrature point weights and coordinates for triangle
     125         [ +  - ]:   29258025 :     GaussQuadratureTri( ng, coordgp, wgp );
     126                 :            : 
     127                 :            :     // Extract the element coordinates
     128                 :            :     std::array< std::array< tk::real, 3>, 4 > coordel_l {{
     129                 :   87774075 :       {{ cx[ inpoel[4*el  ] ], cy[ inpoel[4*el  ] ], cz[ inpoel[4*el  ] ] }},
     130                 :   87774075 :       {{ cx[ inpoel[4*el+1] ], cy[ inpoel[4*el+1] ], cz[ inpoel[4*el+1] ] }},
     131                 :   87774075 :       {{ cx[ inpoel[4*el+2] ], cy[ inpoel[4*el+2] ], cz[ inpoel[4*el+2] ] }},
     132                 :  263322225 :       {{ cx[ inpoel[4*el+3] ], cy[ inpoel[4*el+3] ], cz[ inpoel[4*el+3] ] }} }};
     133                 :            : 
     134                 :            :     std::array< std::array< tk::real, 3>, 4 > coordel_r {{
     135                 :   87774075 :       {{ cx[ inpoel[4*er  ] ], cy[ inpoel[4*er  ] ], cz[ inpoel[4*er  ] ] }},
     136                 :   87774075 :       {{ cx[ inpoel[4*er+1] ], cy[ inpoel[4*er+1] ], cz[ inpoel[4*er+1] ] }},
     137                 :   87774075 :       {{ cx[ inpoel[4*er+2] ], cy[ inpoel[4*er+2] ], cz[ inpoel[4*er+2] ] }},
     138                 :  263322225 :       {{ cx[ inpoel[4*er+3] ], cy[ inpoel[4*er+3] ], cz[ inpoel[4*er+3] ] }} }};
     139                 :            : 
     140                 :            :     // Compute the determinant of Jacobian matrix
     141                 :            :     auto detT_l =
     142                 :   29258025 :       Jacobian( coordel_l[0], coordel_l[1], coordel_l[2], coordel_l[3] );
     143                 :            :     auto detT_r =
     144                 :   29258025 :       Jacobian( coordel_r[0], coordel_r[1], coordel_r[2], coordel_r[3] );
     145                 :            : 
     146                 :            :     // Extract the face coordinates
     147                 :            :     std::array< std::array< tk::real, 3>, 3 > coordfa {{
     148                 :   87774075 :       {{ cx[ inpofa[3*f  ] ], cy[ inpofa[3*f  ] ], cz[ inpofa[3*f  ] ] }},
     149                 :   87774075 :       {{ cx[ inpofa[3*f+1] ], cy[ inpofa[3*f+1] ], cz[ inpofa[3*f+1] ] }},
     150                 :  175548150 :       {{ cx[ inpofa[3*f+2] ], cy[ inpofa[3*f+2] ], cz[ inpofa[3*f+2] ] }} }};
     151                 :            : 
     152                 :            :     std::array< real, 3 >
     153 [ +  - ][ +  - ]:   29258025 :       fn{{ geoFace(f,1), geoFace(f,2), geoFace(f,3) }};
                 [ +  - ]
     154                 :            : 
     155                 :            :     // Gaussian quadrature
     156         [ +  + ]:   85754727 :     for (std::size_t igp=0; igp<ng; ++igp)
     157                 :            :     {
     158                 :            :       // Compute the coordinates of quadrature point at physical domain
     159         [ +  - ]:   56496702 :       auto gp = eval_gp( igp, coordfa, coordgp );
     160                 :            : 
     161                 :            :       // In order to determine the high-order solution from the left and right
     162                 :            :       // elements at the surface quadrature points, the basis functions from
     163                 :            :       // the left and right elements are needed. For this, a transformation to
     164                 :            :       // the reference coordinates is necessary, since the basis functions are
     165                 :            :       // defined on the reference tetrahedron only.
     166                 :            :       // The transformation relations are shown below:
     167                 :            :       //  xi   = Jacobian( coordel[0], gp, coordel[2], coordel[3] ) / detT
     168                 :            :       //  eta  = Jacobian( coordel[0], coordel[2], gp, coordel[3] ) / detT
     169                 :            :       //  zeta = Jacobian( coordel[0], coordel[2], coordel[3], gp ) / detT
     170                 :            : 
     171                 :            :       // If an rDG method is set up (P0P1), then, currently we compute the P1
     172                 :            :       // basis functions and solutions by default. This implies that P0P1 is
     173                 :            :       // unsupported in the p-adaptive DG (PDG). This is a workaround until we
     174                 :            :       // have rdofel, which is needed to distinguish between ndofs and rdofs per
     175                 :            :       // element for pDG.
     176                 :            :       std::size_t dof_el, dof_er;
     177         [ +  + ]:   56496702 :       if (rdof > ndof)
     178                 :            :       {
     179                 :     697050 :         dof_el = rdof;
     180                 :     697050 :         dof_er = rdof;
     181                 :            :       }
     182                 :            :       else
     183                 :            :       {
     184                 :   55799652 :         dof_el = ndofel[el];
     185                 :   55799652 :         dof_er = ndofel[er];
     186                 :            :       }
     187                 :            : 
     188                 :            :       // For multi-material p-adaptive simulation, when dofel = 1, p0p1 is
     189                 :            :       // applied and ndof for solution evaluation should be 4
     190 [ +  + ][ -  + ]:   56496702 :       if(ncomp > 5 && pref) {
     191         [ -  - ]:          0 :         if(dof_el == 1)
     192                 :          0 :           dof_el = 4;
     193         [ -  - ]:          0 :         if(dof_er == 1)
     194                 :          0 :           dof_er = 4;
     195                 :            :       }
     196                 :            : 
     197                 :            :       std::array< tk::real, 3> ref_gp_l{
     198                 :   56496702 :         Jacobian( coordel_l[0], gp, coordel_l[2], coordel_l[3] ) / detT_l,
     199                 :   56496702 :         Jacobian( coordel_l[0], coordel_l[1], gp, coordel_l[3] ) / detT_l,
     200                 :  112993404 :         Jacobian( coordel_l[0], coordel_l[1], coordel_l[2], gp ) / detT_l };
     201                 :            :       std::array< tk::real, 3> ref_gp_r{
     202                 :   56496702 :         Jacobian( coordel_r[0], gp, coordel_r[2], coordel_r[3] ) / detT_r,
     203                 :   56496702 :         Jacobian( coordel_r[0], coordel_r[1], gp, coordel_r[3] ) / detT_r,
     204                 :  112993404 :         Jacobian( coordel_r[0], coordel_r[1], coordel_r[2], gp ) / detT_r };
     205                 :            : 
     206                 :            :       //Compute the basis functions
     207         [ +  - ]:  112993404 :       auto B_l = eval_basis( dof_el, ref_gp_l[0], ref_gp_l[1], ref_gp_l[2] );
     208         [ +  - ]:  112993404 :       auto B_r = eval_basis( dof_er, ref_gp_r[0], ref_gp_r[1], ref_gp_r[2] );
     209                 :            : 
     210         [ +  - ]:   56496702 :       auto wt = wgp[igp] * geoFace(f,0);
     211                 :            : 
     212                 :  112993404 :       std::array< std::vector< real >, 2 > state;
     213                 :            : 
     214         [ +  - ]:  112993404 :       state[0] = evalPolynomialSol(mat_blk, intsharp, ncomp, nprim, rdof,
     215                 :   56496702 :         nmat, el, dof_el, inpoel, coord, geoElem, ref_gp_l, B_l, U, P);
     216         [ +  - ]:  112993404 :       state[1] = evalPolynomialSol(mat_blk, intsharp, ncomp, nprim, rdof,
     217                 :   56496702 :         nmat, er, dof_er, inpoel, coord, geoElem, ref_gp_r, B_r, U, P);
     218                 :            : 
     219 [ -  + ][ -  - ]:   56496702 :       Assert( state[0].size() == ncomp+nprim, "Incorrect size for "
         [ -  - ][ -  - ]
     220                 :            :               "appended boundary state vector" );
     221 [ -  + ][ -  - ]:   56496702 :       Assert( state[1].size() == ncomp+nprim, "Incorrect size for "
         [ -  - ][ -  - ]
     222                 :            :               "appended boundary state vector" );
     223                 :            : 
     224                 :            :       // evaluate prescribed velocity (if any)
     225         [ +  - ]:  112993404 :       auto v = vel( ncomp, gp[0], gp[1], gp[2], t );
     226                 :            : 
     227                 :            :       // compute flux
     228         [ +  - ]:  112993404 :       auto fl = flux( mat_blk, fn, state, v );
     229                 :            : 
     230                 :            :       // Add the surface integration term to the rhs
     231         [ +  - ]:   56496702 :       update_rhs_fa( ncomp, nmat, ndof, ndofel[el], ndofel[er], wt, fn,
     232                 :            :                      el, er, fl, B_l, B_r, R, riemannDeriv );
     233                 :            :     }
     234                 :            :   }
     235                 :      65205 : }
     236                 :            : 
     237                 :            : void
     238                 :   56496702 : update_rhs_fa( ncomp_t ncomp,
     239                 :            :                std::size_t nmat,
     240                 :            :                const std::size_t ndof,
     241                 :            :                const std::size_t ndof_l,
     242                 :            :                const std::size_t ndof_r,
     243                 :            :                const tk::real wt,
     244                 :            :                const std::array< tk::real, 3 >& fn,
     245                 :            :                const std::size_t el,
     246                 :            :                const std::size_t er,
     247                 :            :                const std::vector< tk::real >& fl,
     248                 :            :                const std::vector< tk::real >& B_l,
     249                 :            :                const std::vector< tk::real >& B_r,
     250                 :            :                Fields& R,
     251                 :            :                std::vector< std::vector< tk::real > >& riemannDeriv )
     252                 :            : // *****************************************************************************
     253                 :            : //  Update the rhs by adding the surface integration term
     254                 :            : //! \param[in] ncomp Number of scalar components in this PDE system
     255                 :            : //! \param[in] nmat Number of materials in this PDE system
     256                 :            : //! \param[in] ndof Maximum number of degrees of freedom
     257                 :            : //! \param[in] ndof_l Number of degrees of freedom for left element
     258                 :            : //! \param[in] ndof_r Number of degrees of freedom for right element
     259                 :            : //! \param[in] wt Weight of gauss quadrature point
     260                 :            : //! \param[in] fn Face/Surface normal
     261                 :            : //! \param[in] el Left element index
     262                 :            : //! \param[in] er Right element index
     263                 :            : //! \param[in] fl Surface flux
     264                 :            : //! \param[in] B_l Basis function for the left element
     265                 :            : //! \param[in] B_r Basis function for the right element
     266                 :            : //! \param[in,out] R Right-hand side vector computed
     267                 :            : //! \param[in,out] riemannDeriv Derivatives of partial-pressures and velocities
     268                 :            : //!   computed from the Riemann solver for use in the non-conservative terms.
     269                 :            : //!   These derivatives are used only for multi-material hydro and unused for
     270                 :            : //!   single-material compflow and linear transport.
     271                 :            : // *****************************************************************************
     272                 :            : {
     273                 :            :   // following lines commented until rdofel is made available.
     274                 :            :   //Assert( B_l.size() == ndof_l, "Size mismatch" );
     275                 :            :   //Assert( B_r.size() == ndof_r, "Size mismatch" );
     276                 :            : 
     277                 :            :   using inciter::newSolidsAccFn;
     278                 :            : 
     279                 :            :   const auto& solidx =
     280                 :   56496702 :     inciter::g_inputdeck.get< tag::matidxmap, tag::solidx >();
     281                 :            : 
     282         [ +  + ]:  241047402 :   for (ncomp_t c=0; c<ncomp; ++c)
     283                 :            :   {
     284                 :  184550700 :     auto mark = c*ndof;
     285                 :  184550700 :     R(el, mark) -= wt * fl[c];
     286                 :  184550700 :     R(er, mark) += wt * fl[c];
     287                 :            : 
     288         [ +  + ]:  184550700 :     if(ndof_l > 1)          //DG(P1)
     289                 :            :     {
     290                 :  116695980 :       R(el, mark+1) -= wt * fl[c] * B_l[1];
     291                 :  116695980 :       R(el, mark+2) -= wt * fl[c] * B_l[2];
     292                 :  116695980 :       R(el, mark+3) -= wt * fl[c] * B_l[3];
     293                 :            :     }
     294                 :            : 
     295         [ +  + ]:  184550700 :     if(ndof_r > 1)          //DG(P1)
     296                 :            :     {
     297                 :  116692335 :       R(er, mark+1) += wt * fl[c] * B_r[1];
     298                 :  116692335 :       R(er, mark+2) += wt * fl[c] * B_r[2];
     299                 :  116692335 :       R(er, mark+3) += wt * fl[c] * B_r[3];
     300                 :            :     }
     301                 :            : 
     302         [ +  + ]:  184550700 :     if(ndof_l > 4)          //DG(P2)
     303                 :            :     {
     304                 :   47881710 :       R(el, mark+4) -= wt * fl[c] * B_l[4];
     305                 :   47881710 :       R(el, mark+5) -= wt * fl[c] * B_l[5];
     306                 :   47881710 :       R(el, mark+6) -= wt * fl[c] * B_l[6];
     307                 :   47881710 :       R(el, mark+7) -= wt * fl[c] * B_l[7];
     308                 :   47881710 :       R(el, mark+8) -= wt * fl[c] * B_l[8];
     309                 :   47881710 :       R(el, mark+9) -= wt * fl[c] * B_l[9];
     310                 :            :     }
     311                 :            : 
     312         [ +  + ]:  184550700 :     if(ndof_r > 4)          //DG(P2)
     313                 :            :     {
     314                 :   47875320 :       R(er, mark+4) += wt * fl[c] * B_r[4];
     315                 :   47875320 :       R(er, mark+5) += wt * fl[c] * B_r[5];
     316                 :   47875320 :       R(er, mark+6) += wt * fl[c] * B_r[6];
     317                 :   47875320 :       R(er, mark+7) += wt * fl[c] * B_r[7];
     318                 :   47875320 :       R(er, mark+8) += wt * fl[c] * B_r[8];
     319                 :   47875320 :       R(er, mark+9) += wt * fl[c] * B_r[9];
     320                 :            :     }
     321                 :            :   }
     322                 :            : 
     323                 :            :   // Prep for non-conservative terms in multimat
     324         [ +  + ]:   56496702 :   if (fl.size() > ncomp)
     325                 :            :   {
     326                 :            :     // Gradients of partial pressures
     327         [ +  + ]:   18678705 :     for (std::size_t k=0; k<nmat; ++k)
     328                 :            :     {
     329         [ +  + ]:   52266480 :       for (std::size_t idir=0; idir<3; ++idir)
     330                 :            :       {
     331                 :   39199860 :         riemannDeriv[3*k+idir][el] += wt * fl[ncomp+k] * fn[idir];
     332                 :   39199860 :         riemannDeriv[3*k+idir][er] -= wt * fl[ncomp+k] * fn[idir];
     333                 :            :       }
     334                 :            :     }
     335                 :            : 
     336                 :            :     // Divergence of velocity multiples basis fucntion( d(uB) / dx )
     337         [ +  + ]:   19244250 :     for(std::size_t idof = 0; idof < ndof_l; idof++) {
     338                 :   13632165 :       riemannDeriv[3*nmat+idof][el] += wt * fl[ncomp+nmat] * B_l[idof];
     339                 :            :     }
     340         [ +  + ]:   19244250 :     for(std::size_t idof = 0; idof < ndof_r; idof++) {
     341                 :   13632165 :       riemannDeriv[3*nmat+idof][er] -= wt * fl[ncomp+nmat] * B_r[idof];
     342                 :            :     }
     343                 :            : 
     344                 :            :     // Divergence of asigma: d(asig_ij)/dx_j
     345         [ +  + ]:   18678705 :     for (std::size_t k=0; k<nmat; ++k)
     346         [ -  + ]:   13066620 :       if (solidx[k] > 0)
     347                 :            :       {
     348                 :          0 :         std::size_t mark = ncomp+nmat+1+3*(solidx[k]-1);
     349                 :            : 
     350         [ -  - ]:          0 :         for (std::size_t i=0; i<3; ++i)
     351                 :            :         {
     352                 :          0 :           riemannDeriv[3*nmat+ndof+3*(solidx[k]-1)+i][el] -=
     353                 :          0 :             wt * fl[mark+i];
     354                 :          0 :           riemannDeriv[3*nmat+ndof+3*(solidx[k]-1)+i][er] +=
     355                 :          0 :             wt * fl[mark+i];
     356                 :            :         }
     357                 :            :       }
     358                 :            :   }
     359                 :   56496702 : }
     360                 :            : 
     361                 :            : void
     362                 :       1668 : surfIntFV(
     363                 :            :   std::size_t nmat,
     364                 :            :   const std::vector< inciter::EOS >& mat_blk,
     365                 :            :   real t,
     366                 :            :   const std::size_t rdof,
     367                 :            :   const std::vector< std::size_t >& inpoel,
     368                 :            :   const UnsMesh::Coords& coord,
     369                 :            :   const inciter::FaceData& fd,
     370                 :            :   const Fields& geoFace,
     371                 :            :   const Fields& geoElem,
     372                 :            :   const RiemannFluxFn& flux,
     373                 :            :   const VelFn& vel,
     374                 :            :   const Fields& U,
     375                 :            :   const Fields& P,
     376                 :            :   const std::vector< int >& srcFlag,
     377                 :            :   Fields& R,
     378                 :            :   int intsharp )
     379                 :            : // *****************************************************************************
     380                 :            : //  Compute internal surface flux integrals for second order FV
     381                 :            : //! \param[in] nmat Number of materials in this PDE system
     382                 :            : //! \param[in] t Physical time
     383                 :            : //! \param[in] rdof Maximum number of reconstructed degrees of freedom
     384                 :            : //! \param[in] inpoel Element-node connectivity
     385                 :            : //! \param[in] coord Array of nodal coordinates
     386                 :            : //! \param[in] fd Face connectivity and boundary conditions object
     387                 :            : //! \param[in] geoFace Face geometry array
     388                 :            : //! \param[in] geoElem Element geometry array
     389                 :            : //! \param[in] flux Riemann flux function to use
     390                 :            : //! \param[in] vel Function to use to query prescribed velocity (if any)
     391                 :            : //! \param[in] U Solution vector at recent time step
     392                 :            : //! \param[in] P Vector of primitives at recent time step
     393                 :            : //! \param[in] srcFlag Whether the energy source was added
     394                 :            : //! \param[in,out] R Right-hand side vector computed
     395                 :            : //! \param[in] intsharp Interface compression tag, an optional argument, with
     396                 :            : //!   default 0, so that it is unused for single-material and transport.
     397                 :            : // *****************************************************************************
     398                 :            : {
     399                 :       1668 :   const auto& esuf = fd.Esuf();
     400                 :            : 
     401                 :       1668 :   const auto& cx = coord[0];
     402                 :       1668 :   const auto& cy = coord[1];
     403                 :       1668 :   const auto& cz = coord[2];
     404                 :            : 
     405                 :       1668 :   auto ncomp = U.nprop()/rdof;
     406                 :       1668 :   auto nprim = P.nprop()/rdof;
     407                 :            : 
     408                 :            :   // compute internal surface flux integrals
     409         [ +  + ]:     557508 :   for (auto f=fd.Nbfac(); f<esuf.size()/2; ++f)
     410                 :            :   {
     411 [ +  - ][ +  - ]:     555840 :     Assert( esuf[2*f] > -1 && esuf[2*f+1] > -1, "Interior element detected "
         [ -  - ][ -  - ]
                 [ -  - ]
     412                 :            :             "as -1" );
     413                 :            : 
     414                 :     555840 :     std::size_t el = static_cast< std::size_t >(esuf[2*f]);
     415                 :     555840 :     std::size_t er = static_cast< std::size_t >(esuf[2*f+1]);
     416                 :            : 
     417                 :            :     // Extract the element coordinates
     418                 :            :     std::array< std::array< tk::real, 3>, 4 > coordel_l {{
     419                 :    1667520 :       {{ cx[ inpoel[4*el  ] ], cy[ inpoel[4*el  ] ], cz[ inpoel[4*el  ] ] }},
     420                 :    1667520 :       {{ cx[ inpoel[4*el+1] ], cy[ inpoel[4*el+1] ], cz[ inpoel[4*el+1] ] }},
     421                 :    1667520 :       {{ cx[ inpoel[4*el+2] ], cy[ inpoel[4*el+2] ], cz[ inpoel[4*el+2] ] }},
     422                 :    5002560 :       {{ cx[ inpoel[4*el+3] ], cy[ inpoel[4*el+3] ], cz[ inpoel[4*el+3] ] }} }};
     423                 :            : 
     424                 :            :     std::array< std::array< tk::real, 3>, 4 > coordel_r {{
     425                 :    1667520 :       {{ cx[ inpoel[4*er  ] ], cy[ inpoel[4*er  ] ], cz[ inpoel[4*er  ] ] }},
     426                 :    1667520 :       {{ cx[ inpoel[4*er+1] ], cy[ inpoel[4*er+1] ], cz[ inpoel[4*er+1] ] }},
     427                 :    1667520 :       {{ cx[ inpoel[4*er+2] ], cy[ inpoel[4*er+2] ], cz[ inpoel[4*er+2] ] }},
     428                 :    5002560 :       {{ cx[ inpoel[4*er+3] ], cy[ inpoel[4*er+3] ], cz[ inpoel[4*er+3] ] }} }};
     429                 :            : 
     430                 :            :     // Compute the determinant of Jacobian matrix
     431                 :            :     auto detT_l =
     432                 :     555840 :       Jacobian( coordel_l[0], coordel_l[1], coordel_l[2], coordel_l[3] );
     433                 :            :     auto detT_r =
     434                 :     555840 :       Jacobian( coordel_r[0], coordel_r[1], coordel_r[2], coordel_r[3] );
     435                 :            : 
     436                 :            :     // face normal
     437 [ +  - ][ +  - ]:     555840 :     std::array< real, 3 > fn{{geoFace(f,1), geoFace(f,2), geoFace(f,3)}};
                 [ +  - ]
     438                 :            : 
     439                 :            :     // face centroid
     440 [ +  - ][ +  - ]:     555840 :     std::array< real, 3 > gp{{geoFace(f,4), geoFace(f,5), geoFace(f,6)}};
                 [ +  - ]
     441                 :            : 
     442                 :            :     // In order to determine the high-order solution from the left and right
     443                 :            :     // elements at the surface quadrature points, the basis functions from
     444                 :            :     // the left and right elements are needed. For this, a transformation to
     445                 :            :     // the reference coordinates is necessary, since the basis functions are
     446                 :            :     // defined on the reference tetrahedron only.
     447                 :            :     // The transformation relations are shown below:
     448                 :            :     //  xi   = Jacobian( coordel[0], gp, coordel[2], coordel[3] ) / detT
     449                 :            :     //  eta  = Jacobian( coordel[0], coordel[2], gp, coordel[3] ) / detT
     450                 :            :     //  zeta = Jacobian( coordel[0], coordel[2], coordel[3], gp ) / detT
     451                 :            : 
     452                 :            :     std::array< tk::real, 3> ref_gp_l{
     453                 :     555840 :       Jacobian( coordel_l[0], gp, coordel_l[2], coordel_l[3] ) / detT_l,
     454                 :     555840 :       Jacobian( coordel_l[0], coordel_l[1], gp, coordel_l[3] ) / detT_l,
     455                 :    1111680 :       Jacobian( coordel_l[0], coordel_l[1], coordel_l[2], gp ) / detT_l };
     456                 :            :     std::array< tk::real, 3> ref_gp_r{
     457                 :     555840 :       Jacobian( coordel_r[0], gp, coordel_r[2], coordel_r[3] ) / detT_r,
     458                 :     555840 :       Jacobian( coordel_r[0], coordel_r[1], gp, coordel_r[3] ) / detT_r,
     459                 :    1111680 :       Jacobian( coordel_r[0], coordel_r[1], coordel_r[2], gp ) / detT_r };
     460                 :            : 
     461                 :            :     //Compute the basis functions
     462         [ +  - ]:    1111680 :     auto B_l = eval_basis( rdof, ref_gp_l[0], ref_gp_l[1], ref_gp_l[2] );
     463         [ +  - ]:    1111680 :     auto B_r = eval_basis( rdof, ref_gp_r[0], ref_gp_r[1], ref_gp_r[2] );
     464                 :            : 
     465                 :    1111680 :     std::array< std::vector< real >, 2 > state;
     466                 :            : 
     467         [ +  - ]:    1111680 :     state[0] = evalFVSol(mat_blk, intsharp, ncomp, nprim, rdof,
     468                 :    1111680 :       nmat, el, inpoel, coord, geoElem, ref_gp_l, B_l, U, P, srcFlag[el]);
     469         [ +  - ]:    1111680 :     state[1] = evalFVSol(mat_blk, intsharp, ncomp, nprim, rdof,
     470                 :    1111680 :       nmat, er, inpoel, coord, geoElem, ref_gp_r, B_r, U, P, srcFlag[er]);
     471                 :            : 
     472                 :            :     //safeReco(rdof, nmat, el, er, U, state);
     473                 :            : 
     474 [ -  + ][ -  - ]:     555840 :     Assert( state[0].size() == ncomp+nprim, "Incorrect size for "
         [ -  - ][ -  - ]
     475                 :            :             "appended boundary state vector" );
     476 [ -  + ][ -  - ]:     555840 :     Assert( state[1].size() == ncomp+nprim, "Incorrect size for "
         [ -  - ][ -  - ]
     477                 :            :             "appended boundary state vector" );
     478                 :            : 
     479                 :            :     // evaluate prescribed velocity (if any)
     480         [ +  - ]:    1111680 :     auto v = vel( ncomp, gp[0], gp[1], gp[2], t );
     481                 :            : 
     482                 :            :     // compute flux
     483         [ +  - ]:    1111680 :     auto fl = flux( mat_blk, fn, state, v );
     484                 :            : 
     485                 :            :     // compute non-conservative terms
     486         [ +  - ]:    1111680 :     std::vector< tk::real > var_riemann(nmat+1, 0.0);
     487         [ +  + ]:    2327200 :     for (std::size_t k=0; k<nmat+1; ++k) var_riemann[k] = fl[ncomp+k];
     488                 :            : 
     489         [ +  - ]:    1111680 :     auto ncf_l = nonConservativeIntFV(nmat, rdof, el, fn, U, P, var_riemann);
     490         [ +  - ]:    1111680 :     auto ncf_r = nonConservativeIntFV(nmat, rdof, er, fn, U, P, var_riemann);
     491                 :            : 
     492                 :            :     // Add the surface integration term to the rhs
     493         [ +  + ]:    5869920 :     for (ncomp_t c=0; c<ncomp; ++c)
     494                 :            :     {
     495 [ +  - ][ +  - ]:    5314080 :       R(el, c) -= geoFace(f,0) * (fl[c] - ncf_l[c]);
     496 [ +  - ][ +  - ]:    5314080 :       R(er, c) += geoFace(f,0) * (fl[c] - ncf_r[c]);
     497                 :            :     }
     498                 :            :   }
     499                 :       1668 : }
     500                 :            : 
     501                 :            : void
     502                 :          0 : surfIntViscousFV(
     503                 :            :   std::size_t nmat,
     504                 :            :   const std::vector< inciter::EOS >& mat_blk,
     505                 :            :   const std::size_t rdof,
     506                 :            :   const std::vector< std::size_t >& inpoel,
     507                 :            :   const UnsMesh::Coords& coord,
     508                 :            :   const inciter::FaceData& fd,
     509                 :            :   const Fields& geoFace,
     510                 :            :   const Fields& geoElem,
     511                 :            :   const Fields& U,
     512                 :            :   const Fields& P,
     513                 :            :   const Fields& T,
     514                 :            :   const std::vector< int >& srcFlag,
     515                 :            :   Fields& R,
     516                 :            :   int intsharp )
     517                 :            : // *****************************************************************************
     518                 :            : //  Compute internal surface viscous flux integrals for second order FV
     519                 :            : //! \param[in] nmat Number of materials in this PDE system
     520                 :            : //! \param[in] mat_blk Material EOS block
     521                 :            : //! \param[in] rdof Maximum number of reconstructed degrees of freedom
     522                 :            : //! \param[in] inpoel Element-node connectivity
     523                 :            : //! \param[in] coord Array of nodal coordinates
     524                 :            : //! \param[in] fd Face connectivity and boundary conditions object
     525                 :            : //! \param[in] geoFace Face geometry array
     526                 :            : //! \param[in] geoElem Element geometry array
     527                 :            : //! \param[in] U Solution vector at recent time step
     528                 :            : //! \param[in] P Vector of primitives at recent time step
     529                 :            : //! \param[in] T Vector of temperatures at recent time step
     530                 :            : //! \param[in] srcFlag Whether the energy source was added
     531                 :            : //! \param[in,out] R Right-hand side vector computed
     532                 :            : //! \param[in] intsharp Interface compression tag, an optional argument, with
     533                 :            : //!   default 0, so that it is unused for single-material and transport.
     534                 :            : // *****************************************************************************
     535                 :            : {
     536                 :            :   using inciter::velocityDofIdx;
     537                 :            : 
     538                 :          0 :   const auto& esuf = fd.Esuf();
     539                 :            : 
     540                 :          0 :   const auto& cx = coord[0];
     541                 :          0 :   const auto& cy = coord[1];
     542                 :          0 :   const auto& cz = coord[2];
     543                 :            : 
     544                 :          0 :   auto ncomp = U.nprop()/rdof;
     545                 :          0 :   auto nprim = P.nprop()/rdof;
     546                 :            : 
     547                 :            :   // compute internal surface flux integrals
     548         [ -  - ]:          0 :   for (auto f=fd.Nbfac(); f<esuf.size()/2; ++f)
     549                 :            :   {
     550 [ -  - ][ -  - ]:          0 :     Assert( esuf[2*f] > -1 && esuf[2*f+1] > -1, "Interior element detected "
         [ -  - ][ -  - ]
                 [ -  - ]
     551                 :            :             "as -1" );
     552                 :            : 
     553                 :          0 :     std::size_t el = static_cast< std::size_t >(esuf[2*f]);
     554                 :          0 :     std::size_t er = static_cast< std::size_t >(esuf[2*f+1]);
     555                 :            : 
     556                 :            :     // Extract the element coordinates
     557                 :            :     std::array< std::array< tk::real, 3>, 4 > coordel_l {{
     558                 :          0 :       {{ cx[ inpoel[4*el  ] ], cy[ inpoel[4*el  ] ], cz[ inpoel[4*el  ] ] }},
     559                 :          0 :       {{ cx[ inpoel[4*el+1] ], cy[ inpoel[4*el+1] ], cz[ inpoel[4*el+1] ] }},
     560                 :          0 :       {{ cx[ inpoel[4*el+2] ], cy[ inpoel[4*el+2] ], cz[ inpoel[4*el+2] ] }},
     561                 :          0 :       {{ cx[ inpoel[4*el+3] ], cy[ inpoel[4*el+3] ], cz[ inpoel[4*el+3] ] }} }};
     562                 :            : 
     563                 :            :     std::array< std::array< tk::real, 3>, 4 > coordel_r {{
     564                 :          0 :       {{ cx[ inpoel[4*er  ] ], cy[ inpoel[4*er  ] ], cz[ inpoel[4*er  ] ] }},
     565                 :          0 :       {{ cx[ inpoel[4*er+1] ], cy[ inpoel[4*er+1] ], cz[ inpoel[4*er+1] ] }},
     566                 :          0 :       {{ cx[ inpoel[4*er+2] ], cy[ inpoel[4*er+2] ], cz[ inpoel[4*er+2] ] }},
     567                 :          0 :       {{ cx[ inpoel[4*er+3] ], cy[ inpoel[4*er+3] ], cz[ inpoel[4*er+3] ] }} }};
     568                 :            : 
     569                 :            :     // Compute the determinant of Jacobian matrix
     570                 :            :     auto detT_l =
     571                 :          0 :       Jacobian( coordel_l[0], coordel_l[1], coordel_l[2], coordel_l[3] );
     572                 :            :     auto detT_r =
     573                 :          0 :       Jacobian( coordel_r[0], coordel_r[1], coordel_r[2], coordel_r[3] );
     574                 :            : 
     575                 :            :     // face normal
     576 [ -  - ][ -  - ]:          0 :     std::array< real, 3 > fn{{geoFace(f,1), geoFace(f,2), geoFace(f,3)}};
                 [ -  - ]
     577                 :            : 
     578                 :            :     // face centroid
     579 [ -  - ][ -  - ]:          0 :     std::array< real, 3 > gp{{geoFace(f,4), geoFace(f,5), geoFace(f,6)}};
                 [ -  - ]
     580                 :            : 
     581                 :            :     // In order to determine the high-order solution from the left and right
     582                 :            :     // elements at the surface quadrature points, the basis functions from
     583                 :            :     // the left and right elements are needed. For this, a transformation to
     584                 :            :     // the reference coordinates is necessary, since the basis functions are
     585                 :            :     // defined on the reference tetrahedron only.
     586                 :            :     // The transformation relations are shown below:
     587                 :            :     //  xi   = Jacobian( coordel[0], gp, coordel[2], coordel[3] ) / detT
     588                 :            :     //  eta  = Jacobian( coordel[0], coordel[2], gp, coordel[3] ) / detT
     589                 :            :     //  zeta = Jacobian( coordel[0], coordel[2], coordel[3], gp ) / detT
     590                 :            : 
     591                 :            :     std::array< tk::real, 3> ref_gp_l{
     592                 :          0 :       Jacobian( coordel_l[0], gp, coordel_l[2], coordel_l[3] ) / detT_l,
     593                 :          0 :       Jacobian( coordel_l[0], coordel_l[1], gp, coordel_l[3] ) / detT_l,
     594                 :          0 :       Jacobian( coordel_l[0], coordel_l[1], coordel_l[2], gp ) / detT_l };
     595                 :            :     std::array< tk::real, 3> ref_gp_r{
     596                 :          0 :       Jacobian( coordel_r[0], gp, coordel_r[2], coordel_r[3] ) / detT_r,
     597                 :          0 :       Jacobian( coordel_r[0], coordel_r[1], gp, coordel_r[3] ) / detT_r,
     598                 :          0 :       Jacobian( coordel_r[0], coordel_r[1], coordel_r[2], gp ) / detT_r };
     599                 :            : 
     600                 :            :     //Compute the basis functions
     601         [ -  - ]:          0 :     auto B_l = eval_basis( rdof, ref_gp_l[0], ref_gp_l[1], ref_gp_l[2] );
     602         [ -  - ]:          0 :     auto B_r = eval_basis( rdof, ref_gp_r[0], ref_gp_r[1], ref_gp_r[2] );
     603                 :            : 
     604                 :          0 :     std::array< std::vector< real >, 2 > state;
     605                 :            : 
     606         [ -  - ]:          0 :     state[0] = evalFVSol(mat_blk, intsharp, ncomp, nprim, rdof,
     607                 :          0 :       nmat, el, inpoel, coord, geoElem, ref_gp_l, B_l, U, P, srcFlag[el]);
     608         [ -  - ]:          0 :     state[1] = evalFVSol(mat_blk, intsharp, ncomp, nprim, rdof,
     609                 :          0 :       nmat, er, inpoel, coord, geoElem, ref_gp_r, B_r, U, P, srcFlag[er]);
     610                 :            : 
     611 [ -  - ][ -  - ]:          0 :     Assert( state[0].size() == ncomp+nprim, "Incorrect size for "
         [ -  - ][ -  - ]
     612                 :            :             "appended boundary state vector" );
     613 [ -  - ][ -  - ]:          0 :     Assert( state[1].size() == ncomp+nprim, "Incorrect size for "
         [ -  - ][ -  - ]
     614                 :            :             "appended boundary state vector" );
     615                 :            : 
     616                 :            :     // cell averaged state for computing the diffusive flux
     617                 :          0 :     std::array< std::vector< real >, 2 > cellAvgState;
     618         [ -  - ]:          0 :     std::vector< tk::real > Bcc(rdof, 0.0);
     619                 :          0 :     Bcc[0] = 1.0;
     620                 :            : 
     621         [ -  - ]:          0 :     cellAvgState[0] = evalFVSol(mat_blk, 0, ncomp, nprim, rdof,
     622                 :            :       nmat, el, inpoel, coord, geoElem, {{0.25, 0.25, 0.25}}, Bcc, U, P,
     623                 :          0 :       srcFlag[el]);
     624         [ -  - ]:          0 :     cellAvgState[1] = evalFVSol(mat_blk, 0, ncomp, nprim, rdof,
     625                 :            :       nmat, er, inpoel, coord, geoElem, {{0.25, 0.25, 0.25}}, Bcc, U, P,
     626                 :          0 :       srcFlag[er]);
     627                 :            : 
     628 [ -  - ][ -  - ]:          0 :     Assert( cellAvgState[0].size() == ncomp+nprim, "Incorrect size for "
         [ -  - ][ -  - ]
     629                 :            :             "appended cell-averaged state vector" );
     630 [ -  - ][ -  - ]:          0 :     Assert( cellAvgState[1].size() == ncomp+nprim, "Incorrect size for "
         [ -  - ][ -  - ]
     631                 :            :             "appended cell-averaged state vector" );
     632                 :            : 
     633                 :            :     std::array< std::vector< real >, 2 > cellAvgT{{
     634 [ -  - ][ -  - ]:          0 :       std::vector<real>(nmat), std::vector<real>(nmat) }};
     635         [ -  - ]:          0 :     for (std::size_t k=0; k<nmat; ++k) {
     636         [ -  - ]:          0 :       cellAvgT[0][k] = T(el, k*rdof);
     637         [ -  - ]:          0 :       cellAvgT[1][k] = T(er, k*rdof);
     638                 :            :     }
     639                 :            : 
     640                 :            :     std::array< std::array< real, 3 >, 2 > centroids{{
     641         [ -  - ]:          0 :       {{geoElem(el,1), geoElem(el,2), geoElem(el,3)}},
     642 [ -  - ][ -  - ]:          0 :       {{geoElem(er,1), geoElem(er,2), geoElem(er,3)}} }};
         [ -  - ][ -  - ]
                 [ -  - ]
     643                 :            : 
     644                 :            :     // Numerical viscous flux
     645                 :            :     // -------------------------------------------------------------------------
     646                 :            : 
     647                 :            :     // 1. Get spatial gradient from Dubiner dofs
     648                 :            :     auto jacInv_l =
     649                 :          0 :       tk::inverseJacobian( coordel_l[0], coordel_l[1], coordel_l[2], coordel_l[3] );
     650         [ -  - ]:          0 :     auto dBdx_l = tk::eval_dBdx_p1( rdof, jacInv_l );
     651                 :            :     auto jacInv_r =
     652                 :          0 :       tk::inverseJacobian( coordel_r[0], coordel_r[1], coordel_r[2], coordel_r[3] );
     653         [ -  - ]:          0 :     auto dBdx_r = tk::eval_dBdx_p1( rdof, jacInv_r );
     654                 :            : 
     655                 :            :     // 2. Average du_i/dx_j
     656                 :            :     std::array< std::array< real, 3 >, 3 > dudx;
     657         [ -  - ]:          0 :     for (std::size_t i=0; i<3; ++i)
     658         [ -  - ]:          0 :       for (std::size_t j=0; j<3; ++j)
     659                 :          0 :         dudx[i][j] = 0.5 * (
     660         [ -  - ]:          0 :             dBdx_l[j][1] * P(el, velocityDofIdx(nmat,i,rdof,1))
     661         [ -  - ]:          0 :           + dBdx_l[j][2] * P(el, velocityDofIdx(nmat,i,rdof,2))
     662         [ -  - ]:          0 :           + dBdx_l[j][3] * P(el, velocityDofIdx(nmat,i,rdof,3))
     663         [ -  - ]:          0 :           + dBdx_r[j][1] * P(er, velocityDofIdx(nmat,i,rdof,1))
     664         [ -  - ]:          0 :           + dBdx_r[j][2] * P(er, velocityDofIdx(nmat,i,rdof,2))
     665         [ -  - ]:          0 :           + dBdx_r[j][3] * P(er, velocityDofIdx(nmat,i,rdof,3)) );
     666                 :            : 
     667                 :            :     // 3. average dT/dx_j
     668                 :            :     std::vector< std::array< real, 3 > > dTdx(nmat,
     669         [ -  - ]:          0 :       std::array< real, 3 >{{0, 0, 0}});
     670         [ -  - ]:          0 :     for (std::size_t k=0; k<nmat; ++k) {
     671                 :          0 :       auto mark = k*rdof;
     672         [ -  - ]:          0 :       for (std::size_t j=0; j<3; ++j) {
     673                 :          0 :         dTdx[k][j] = 0.5 * (
     674         [ -  - ]:          0 :             dBdx_l[j][1] * T(el, mark+1)
     675         [ -  - ]:          0 :           + dBdx_l[j][2] * T(el, mark+2)
     676         [ -  - ]:          0 :           + dBdx_l[j][3] * T(el, mark+3)
     677         [ -  - ]:          0 :           + dBdx_r[j][1] * T(er, mark+1)
     678         [ -  - ]:          0 :           + dBdx_r[j][2] * T(er, mark+2)
     679         [ -  - ]:          0 :           + dBdx_r[j][3] * T(er, mark+3) );
     680                 :            :       }
     681                 :            :     }
     682                 :            : 
     683                 :            :     // 4. Compute flux
     684                 :            :     auto fl = modifiedGradientViscousFlux(nmat, ncomp, fn, centroids, state,
     685         [ -  - ]:          0 :       cellAvgState, cellAvgT, dudx, dTdx);
     686                 :            : 
     687                 :            :     // -------------------------------------------------------------------------
     688                 :            : 
     689                 :            :     // Add the surface integration term to the rhs
     690         [ -  - ]:          0 :     for (ncomp_t c=0; c<ncomp; ++c)
     691                 :            :     {
     692 [ -  - ][ -  - ]:          0 :       R(el, c) += geoFace(f,0) * fl[c];
     693 [ -  - ][ -  - ]:          0 :       R(er, c) -= geoFace(f,0) * fl[c];
     694                 :            :     }
     695                 :            :   }
     696                 :          0 : }
     697                 :            : 
     698                 :            : std::vector< real >
     699                 :          0 : modifiedGradientViscousFlux(
     700                 :            :   std::size_t nmat,
     701                 :            :   std::size_t ncomp,
     702                 :            :   const std::array< tk::real, 3 >& fn,
     703                 :            :   const std::array< std::array< tk::real, 3 >, 2 >& centroids,
     704                 :            :   const std::array< std::vector< tk::real >, 2 >& state,
     705                 :            :   const std::array< std::vector< tk::real >, 2 >& cellAvgState,
     706                 :            :   const std::array< std::vector< tk::real >, 2 >& cellAvgT,
     707                 :            :   const std::array< std::array< real, 3 >, 3 > dudx,
     708                 :            :   const std::vector< std::array< real, 3 > >& dTdx )
     709                 :            : // *****************************************************************************
     710                 :            : //  Compute the viscous fluxes from the left and right states
     711                 :            : //! \param[in] nmat Number of materials
     712                 :            : //! \param[in] ncomp Number of component equations in the PDE system
     713                 :            : //! \param[in] fn Face/Surface normal
     714                 :            : //! \param[in] centroids Left and right cell centroids
     715                 :            : //! \param[in] state Left and right unknown/state vector
     716                 :            : //! \param[in] cellAvgState Left and right cell-averaged unknown/state vector
     717                 :            : //! \param[in] cellAvgT Left and right cell-averaged temperature vector
     718                 :            : //! \param[in] dudx Average velocity gradient tensor
     719                 :            : //! \param[in] dTdx Average temperature gradient tensor
     720                 :            : //! \return Numerical viscous flux using the Modified Gradient approach.
     721                 :            : //! \details The average gradient is modified according to Weiss et al. to
     722                 :            : //!   obtain a stable discretization (average results in unstable central
     723                 :            : //!   central difference).
     724                 :            : //!   Ref: Weiss, J. M., Maruszewski, J. P., & Smith, W. A. (1999). Implicit
     725                 :            : //!   solution of preconditioned Navier-Stokes equations using algebraic
     726                 :            : //!   multigrid. AIAA journal, 37(1), 29-36.
     727                 :            : // *****************************************************************************
     728                 :            : {
     729                 :            :   using inciter::velocityDofIdx;
     730                 :            :   using inciter::volfracDofIdx;
     731                 :            :   using inciter::momentumIdx;
     732                 :            :   using inciter::velocityIdx;
     733                 :            :   using inciter::volfracIdx;
     734                 :            :   using inciter::energyIdx;
     735                 :            : 
     736         [ -  - ]:          0 :   std::vector< real > fl(ncomp, 0);
     737                 :            : 
     738                 :            :   // 1. Modify the average gradient
     739                 :            :   std::array< real, 3 > r_f{{
     740                 :          0 :     centroids[1][0] - centroids[0][0],
     741                 :          0 :     centroids[1][1] - centroids[0][1],
     742                 :          0 :     centroids[1][2] - centroids[0][2] }};
     743                 :          0 :   real r_mag = std::sqrt(tk::dot(r_f, r_f));
     744         [ -  - ]:          0 :   for (std::size_t i=0; i<3; ++i)
     745                 :          0 :     r_f[i] /= r_mag;
     746                 :            : 
     747                 :            :   // velocity gradient
     748                 :          0 :   auto dudx_m = dudx;
     749         [ -  - ]:          0 :   for (std::size_t i=0; i<3; ++i)
     750         [ -  - ]:          0 :     for (std::size_t j=0; j<3; ++j)
     751                 :          0 :       dudx_m[i][j] -= ( tk::dot(dudx_m[i], r_f) -
     752                 :          0 :         (cellAvgState[1][ncomp+velocityIdx(nmat,i)]
     753                 :          0 :         - cellAvgState[0][ncomp+velocityIdx(nmat,i)])/r_mag ) * r_f[j];
     754                 :            :   // temperature gradient
     755         [ -  - ]:          0 :   auto dTdx_m = dTdx;
     756         [ -  - ]:          0 :   for (std::size_t k=0; k<nmat; ++k) {
     757         [ -  - ]:          0 :     for (std::size_t j=0; j<3; ++j)
     758                 :          0 :       dTdx_m[k][j] -= ( tk::dot(dTdx_m[k], r_f) -
     759                 :          0 :         (cellAvgT[1][k] - cellAvgT[0][k])/r_mag ) * r_f[j];
     760                 :            :   }
     761                 :            : 
     762                 :            :   // 2. Compute viscous stress tensor
     763                 :            :   std::array< real, 6 > tau;
     764                 :          0 :   real mu(0.0);
     765 [ -  - ][ -  - ]:          0 :   std::vector< real > alLR(nmat, 0), conduct_mat(nmat, 0);
     766         [ -  - ]:          0 :   for (std::size_t k=0; k<nmat; ++k)
     767                 :          0 :     alLR[k] = 0.5*( state[0][volfracIdx(nmat,k)] + state[1][volfracIdx(nmat,k)] );
     768         [ -  - ]:          0 :   for (std::size_t k=0; k<nmat; ++k) {
     769         [ -  - ]:          0 :     mu += alLR[k] * inciter::getmatprop< tag::mu >(k);
     770         [ -  - ]:          0 :     conduct_mat[k] = inciter::getmatprop< tag::mu >(k) *
     771 [ -  - ][ -  - ]:          0 :       inciter::getmatprop< tag::cv >(k) * inciter::getmatprop< tag::gamma >(k)
     772                 :          0 :       / 0.71;
     773                 :            :   }
     774                 :            : 
     775                 :          0 :   tau[0] = mu * ( 4.0 * dudx_m[0][0] - 2.0*(dudx_m[1][1] + dudx_m[2][2]) ) / 3.0;
     776                 :          0 :   tau[1] = mu * ( 4.0 * dudx_m[1][1] - 2.0*(dudx_m[0][0] + dudx_m[2][2]) ) / 3.0;
     777                 :          0 :   tau[2] = mu * ( 4.0 * dudx_m[2][2] - 2.0*(dudx_m[0][0] + dudx_m[1][1]) ) / 3.0;
     778                 :          0 :   tau[3] = mu * ( dudx_m[0][1] + dudx_m[1][0] );
     779                 :          0 :   tau[4] = mu * ( dudx_m[0][2] + dudx_m[2][0] );
     780                 :          0 :   tau[5] = mu * ( dudx_m[1][2] + dudx_m[2][1] );
     781                 :            : 
     782                 :            :   // 3. Compute viscous flux terms
     783         [ -  - ]:          0 :   for (std::size_t i=0; i<3; ++i)
     784         [ -  - ]:          0 :     for (std::size_t j=0; j<3; ++j)
     785                 :          0 :       fl[momentumIdx(nmat, i)] += tau[inciter::stressCmp[i][j]] * fn[j];
     786                 :            : 
     787         [ -  - ]:          0 :   std::vector< std::array< real, 3 > > energyFlux(nmat, {{0.0, 0.0, 0.0}});
     788                 :            :   std::array< real, 3 > uAvg{{
     789                 :          0 :     0.5*(state[0][ncomp+velocityIdx(nmat,0)] + state[1][ncomp+velocityIdx(nmat,0)]),
     790                 :          0 :     0.5*(state[0][ncomp+velocityIdx(nmat,1)] + state[1][ncomp+velocityIdx(nmat,1)]),
     791                 :          0 :     0.5*(state[0][ncomp+velocityIdx(nmat,2)] + state[1][ncomp+velocityIdx(nmat,2)])
     792                 :          0 :     }};
     793                 :            : 
     794         [ -  - ]:          0 :   for (std::size_t k=0; k<nmat; ++k) {
     795         [ -  - ]:          0 :     for (std::size_t j=0; j<3; ++j)
     796         [ -  - ]:          0 :       for (std::size_t i=0; i<3; ++i)
     797                 :          0 :         energyFlux[k][j] += uAvg[i] * tau[inciter::stressCmp[i][j]] +
     798                 :          0 :           conduct_mat[k] * dTdx_m[k][j];
     799                 :            :   }
     800                 :            : 
     801         [ -  - ]:          0 :   for (std::size_t k=0; k<nmat; ++k) {
     802                 :          0 :     fl[energyIdx(nmat, k)] = alLR[k]
     803                 :          0 :       * tk::dot(energyFlux[k], fn);
     804                 :            :   }
     805                 :            : 
     806                 :          0 :   return fl;
     807                 :            : }
     808                 :            : 
     809                 :            : } // tk::

Generated by: LCOV version 1.14