Quinoa all test code coverage report
Current view: top level - PDE - Reconstruction.cpp (source / functions) Hit Total Coverage
Commit: -128-NOTFOUND Lines: 238 400 59.5 %
Date: 2025-12-04 16:13:45 Functions: 7 12 58.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 154 406 37.9 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/PDE/Reconstruction.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     Reconstruction for reconstructed discontinuous Galerkin methods
       9                 :            :   \details   This file contains functions that reconstruct an "n"th order
      10                 :            :     polynomial to an "n+1"th order polynomial using a least-squares
      11                 :            :     reconstruction procedure.
      12                 :            : */
      13                 :            : // *****************************************************************************
      14                 :            : 
      15                 :            : #include <array>
      16                 :            : #include <vector>
      17                 :            : #include <iostream>
      18                 :            : #include <iomanip>
      19                 :            : 
      20                 :            : #include "Vector.hpp"
      21                 :            : #include "Around.hpp"
      22                 :            : #include "Base/HashMapReducer.hpp"
      23                 :            : #include "Reconstruction.hpp"
      24                 :            : #include "Inciter/Options/PDE.hpp"
      25                 :            : #include "MultiMat/MultiMatIndexing.hpp"
      26                 :            : #include "Inciter/InputDeck/InputDeck.hpp"
      27                 :            : #include "Limiter.hpp"
      28                 :            : #include "Integrate/Quadrature.hpp"
      29                 :            : 
      30                 :            : namespace inciter {
      31                 :            : extern ctr::InputDeck g_inputdeck;
      32                 :            : }
      33                 :            : 
      34                 :            : namespace tk {
      35                 :            : 
      36                 :            : void
      37                 :    2894560 : recoLeastSqExtStencil(
      38                 :            :   std::size_t rdof,
      39                 :            :   std::size_t e,
      40                 :            :   const std::map< std::size_t, std::vector< std::size_t > >& esup,
      41                 :            :   const std::vector< std::size_t >& inpoel,
      42                 :            :   const Fields& geoElem,
      43                 :            :   Fields& W,
      44                 :            :   const std::vector< std::size_t >& varList )
      45                 :            : // *****************************************************************************
      46                 :            : //  \brief Reconstruct the second-order solution using least-squares approach
      47                 :            : //    from an extended stencil involving the node-neighbors
      48                 :            : //! \param[in] rdof Maximum number of reconstructed degrees of freedom
      49                 :            : //! \param[in] e Element whoes solution is being reconstructed
      50                 :            : //! \param[in] esup Elements surrounding points
      51                 :            : //! \param[in] inpoel Element-node connectivity
      52                 :            : //! \param[in] geoElem Element geometry array
      53                 :            : //! \param[in,out] W Solution vector to be reconstructed at recent time step
      54                 :            : //! \param[in] varList List of indices in W, that need to be reconstructed
      55                 :            : //! \details A second-order (piecewise linear) solution polynomial is obtained
      56                 :            : //!   from the first-order (piecewise constant) FV solutions by using a
      57                 :            : //!   least-squares (LS) reconstruction process. This LS reconstruction function
      58                 :            : //!   using the nodal-neighbors of a cell, to get an overdetermined system of
      59                 :            : //!   equations for the derivatives of the solution. This overdetermined system
      60                 :            : //!   is solved in the least-squares sense using the normal equations approach.
      61                 :            : // *****************************************************************************
      62                 :            : {
      63                 :            :   // Element centroid
      64         [ +  - ]:    2894560 :   auto ex = geoElem(e,1);
      65         [ +  - ]:    2894560 :   auto ey = geoElem(e,2);
      66         [ +  - ]:    2894560 :   auto ez = geoElem(e,3);
      67                 :            : 
      68                 :    2894560 :   tk::real m_xx = 0.0, m_xy = 0.0, m_xz = 0.0,
      69                 :    2894560 :            m_yy = 0.0, m_yz = 0.0, m_zz = 0.0;
      70                 :            : 
      71                 :            :   // RHS for each variable in varList
      72                 :    2894560 :   auto nvar = varList.size();
      73         [ +  - ]:    5789120 :   std::vector< std::array< tk::real,3 > > rhs(nvar);
      74         [ +  + ]:   15281860 :   for (auto& r : rhs) r = {{0.0, 0.0, 0.0}};
      75                 :            : 
      76                 :            :   // Cache P0 of the target cell for all variables (used for all neighbors)
      77         [ +  - ]:    5789120 :   std::vector< tk::real > w0(nvar);
      78         [ +  + ]:   15281860 :   for (std::size_t iv=0; iv<nvar; ++iv) {
      79                 :   12387300 :     auto c = varList[iv];
      80                 :   12387300 :     auto mark = c*rdof;
      81         [ +  - ]:   12387300 :     w0[iv] = W(e, mark + 0);
      82                 :            :   }
      83                 :            : 
      84                 :            :   // Build LHS and accumulate RHS (neighbor outer loop)
      85         [ +  + ]:   14472800 :   for (std::size_t lp=0; lp<4; ++lp) {
      86                 :   11578240 :     auto p = inpoel[4*e + lp];
      87         [ +  - ]:   11578240 :     auto& pesup = cref_find(esup, p);
      88                 :            : 
      89         [ +  + ]:  192571840 :     for (auto er : pesup) {
      90         [ +  - ]:  180993600 :       auto dx = geoElem(er,1) - ex;
      91         [ +  - ]:  180993600 :       auto dy = geoElem(er,2) - ey;
      92         [ +  - ]:  180993600 :       auto dz = geoElem(er,3) - ez;
      93                 :            : 
      94                 :            :       // LHS (use symmetry)
      95                 :  180993600 :       m_xx += dx*dx;
      96                 :  180993600 :       m_xy += dx*dy;
      97                 :  180993600 :       m_xz += dx*dz;
      98                 :  180993600 :       m_yy += dy*dy;
      99                 :  180993600 :       m_yz += dy*dz;
     100                 :  180993600 :       m_zz += dz*dz;
     101                 :            : 
     102                 :            :       // RHS for all variables
     103         [ +  + ]:  957705300 :       for (std::size_t iv=0; iv<nvar; ++iv) {
     104                 :  776711700 :         auto c = varList[iv];
     105                 :  776711700 :         auto mark = c*rdof;
     106         [ +  - ]:  776711700 :         auto dW = W(er, mark + 0) - w0[iv];
     107                 :  776711700 :         rhs[iv][0] += dx * dW;
     108                 :  776711700 :         rhs[iv][1] += dy * dW;
     109                 :  776711700 :         rhs[iv][2] += dz * dW;
     110                 :            :       }
     111                 :            :     }
     112                 :            :   }
     113                 :            : 
     114                 :            :   // Form full symmetric 3×3 and factor once (reused for all RHS)
     115                 :            :   std::array<std::array<tk::real,3>,3> A {{
     116                 :            :     {{ m_xx, m_xy, m_xz }},
     117                 :            :     {{ m_xy, m_yy, m_yz }},
     118                 :            :     {{ m_xz, m_yz, m_zz }}
     119                 :    2894560 :   }};
     120                 :            :   std::array<std::array<tk::real,3>,3> L;
     121         [ +  - ]:    2894560 :   chol3x3(A, L);
     122                 :            : 
     123                 :            :   // Solve for and update the P1 dofs with the reconstructioned gradients.
     124                 :            :   // Since this reconstruction does not affect the cell-averaged solution,
     125                 :            :   // W(e,mark+0) is unchanged.
     126         [ +  + ]:   15281860 :   for (std::size_t iv=0; iv<nvar; ++iv) {
     127                 :   12387300 :     auto c = varList[iv];
     128                 :   12387300 :     auto mark = c*rdof;
     129                 :   12387300 :     auto ux = solve_chol3x3(L, rhs[iv]);
     130                 :            : 
     131         [ +  - ]:   12387300 :     W(e, mark + 1) = ux[0];
     132         [ +  - ]:   12387300 :     W(e, mark + 2) = ux[1];
     133         [ +  - ]:   12387300 :     W(e, mark + 3) = ux[2];
     134                 :            :   }
     135                 :    2894560 : }
     136                 :            : 
     137                 :            : void
     138                 :    2894560 : transform_P0P1( std::size_t rdof,
     139                 :            :                 std::size_t e,
     140                 :            :                 const std::vector< std::size_t >& inpoel,
     141                 :            :                 const UnsMesh::Coords& coord,
     142                 :            :                 Fields& W,
     143                 :            :                 const std::vector< std::size_t >& varList )
     144                 :            : // *****************************************************************************
     145                 :            : //  Transform the reconstructed P1-derivatives to the Dubiner dofs
     146                 :            : //! \param[in] rdof Total number of reconstructed dofs
     147                 :            : //! \param[in] e Element for which reconstruction is being calculated
     148                 :            : //! \param[in] inpoel Element-node connectivity
     149                 :            : //! \param[in] coord Array of nodal coordinates
     150                 :            : //! \param[in,out] W Second-order reconstructed vector which gets transformed to
     151                 :            : //!   the Dubiner reference space
     152                 :            : //! \param[in] varList List of indices in W, that need to be reconstructed
     153                 :            : //! \details Since the DG solution (and the primitive quantities) are assumed to
     154                 :            : //!   be stored in the Dubiner space, this transformation from Taylor
     155                 :            : //!   coefficients to Dubiner coefficients is necessary.
     156                 :            : // *****************************************************************************
     157                 :            : {
     158                 :    2894560 :   const auto& cx = coord[0];
     159                 :    2894560 :   const auto& cy = coord[1];
     160                 :    2894560 :   const auto& cz = coord[2];
     161                 :            : 
     162                 :            :   // Extract the element coordinates
     163                 :            :   std::array< std::array< real, 3>, 4 > coordel {{
     164                 :    8683680 :     {{ cx[ inpoel[4*e  ] ], cy[ inpoel[4*e  ] ], cz[ inpoel[4*e  ] ] }},
     165                 :    8683680 :     {{ cx[ inpoel[4*e+1] ], cy[ inpoel[4*e+1] ], cz[ inpoel[4*e+1] ] }},
     166                 :    8683680 :     {{ cx[ inpoel[4*e+2] ], cy[ inpoel[4*e+2] ], cz[ inpoel[4*e+2] ] }},
     167                 :    8683680 :     {{ cx[ inpoel[4*e+3] ], cy[ inpoel[4*e+3] ], cz[ inpoel[4*e+3] ] }}
     168                 :   31840160 :   }};
     169                 :            : 
     170                 :            :   auto jacInv =
     171                 :    2894560 :     tk::inverseJacobian( coordel[0], coordel[1], coordel[2], coordel[3] );
     172                 :            : 
     173                 :            :   // Compute the derivatives of basis function for DG(P1)
     174         [ +  - ]:    5789120 :   auto dBdx = tk::eval_dBdx_p1( rdof, jacInv );
     175                 :            : 
     176         [ +  + ]:   15281860 :   for (std::size_t i=0; i<varList.size(); ++i)
     177                 :            :   {
     178                 :   12387300 :     auto mark = varList[i]*rdof;
     179                 :            : 
     180                 :            :     // solve system using Cramer's rule
     181                 :   37161900 :     auto ux = tk::cramer( {{ {{dBdx[0][1], dBdx[0][2], dBdx[0][3]}},
     182                 :   37161900 :                              {{dBdx[1][1], dBdx[1][2], dBdx[1][3]}},
     183                 :   37161900 :                              {{dBdx[2][1], dBdx[2][2], dBdx[2][3]}} }},
     184         [ +  - ]:   12387300 :                           {{ W(e,mark+1),
     185                 :   24774600 :                              W(e,mark+2),
     186 [ +  - ][ +  - ]:  123873000 :                              W(e,mark+3) }} );
     187                 :            : 
     188                 :            :     // replace physical derivatives with transformed dofs
     189         [ +  - ]:   12387300 :     W(e,mark+1) = ux[0];
     190         [ +  - ]:   12387300 :     W(e,mark+2) = ux[1];
     191         [ +  - ]:   12387300 :     W(e,mark+3) = ux[2];
     192                 :            :   }
     193                 :    2894560 : }
     194                 :            : 
     195                 :            : void
     196                 :    6757100 : THINCReco( std::size_t rdof,
     197                 :            :            std::size_t nmat,
     198                 :            :            std::size_t e,
     199                 :            :            const std::vector< std::size_t >& inpoel,
     200                 :            :            const UnsMesh::Coords& coord,
     201                 :            :            const Fields& geoElem,
     202                 :            :            const std::array< real, 3 >& ref_xp,
     203                 :            :            const Fields& U,
     204                 :            :            const Fields& P,
     205                 :            :            bool intInd,
     206                 :            :            const std::vector< std::size_t >& matInt,
     207                 :            :            [[maybe_unused]] const std::vector< real >& vfmin,
     208                 :            :            [[maybe_unused]] const std::vector< real >& vfmax,
     209                 :            :            std::vector< real >& state )
     210                 :            : // *****************************************************************************
     211                 :            : //  Compute THINC reconstructions at quadrature point for multi-material flows
     212                 :            : //! \param[in] rdof Total number of reconstructed dofs
     213                 :            : //! \param[in] nmat Total number of materials
     214                 :            : //! \param[in] e Element for which interface reconstruction is being calculated
     215                 :            : //! \param[in] inpoel Element-node connectivity
     216                 :            : //! \param[in] coord Array of nodal coordinates
     217                 :            : //! \param[in] geoElem Element geometry array
     218                 :            : //! \param[in] ref_xp Quadrature point in reference space
     219                 :            : //! \param[in] U Solution vector
     220                 :            : //! \param[in] P Vector of primitives
     221                 :            : //! \param[in] intInd Boolean which indicates if the element contains a
     222                 :            : //!   material interface
     223                 :            : //! \param[in] matInt Array indicating which material has an interface
     224                 :            : //! \param[in] vfmin Vector containing min volume fractions for each material
     225                 :            : //!   in this cell
     226                 :            : //! \param[in] vfmax Vector containing max volume fractions for each material
     227                 :            : //!   in this cell
     228                 :            : //! \param[in,out] state Unknown/state vector at quadrature point, modified
     229                 :            : //!   if near interfaces using THINC
     230                 :            : //! \details This function is an interface for the multimat PDEs that use the
     231                 :            : //!   algebraic multi-material THINC reconstruction. This particular function
     232                 :            : //!   should only be called for multimat.
     233                 :            : // *****************************************************************************
     234                 :            : {
     235                 :            :   using inciter::volfracDofIdx;
     236                 :            :   using inciter::densityDofIdx;
     237                 :            :   using inciter::momentumDofIdx;
     238                 :            :   using inciter::energyDofIdx;
     239                 :            :   using inciter::pressureDofIdx;
     240                 :            :   using inciter::velocityDofIdx;
     241                 :            :   using inciter::deformDofIdx;
     242                 :            :   using inciter::stressDofIdx;
     243                 :            :   using inciter::volfracIdx;
     244                 :            :   using inciter::densityIdx;
     245                 :            :   using inciter::momentumIdx;
     246                 :            :   using inciter::energyIdx;
     247                 :            :   using inciter::pressureIdx;
     248                 :            :   using inciter::velocityIdx;
     249                 :            :   using inciter::deformIdx;
     250                 :            :   using inciter::stressIdx;
     251                 :            : 
     252                 :            :   auto bparam = inciter::g_inputdeck.get< tag::multimat,
     253                 :    6757100 :     tag::intsharp_param >();
     254                 :    6757100 :   const auto ncomp = U.nprop()/rdof;
     255                 :            :   const auto& solidx = inciter::g_inputdeck.get< tag::matidxmap,
     256                 :    6757100 :     tag::solidx >();
     257                 :            : 
     258                 :            :   // Step-1: Perform THINC reconstruction
     259                 :            :   // create a vector of volume-fractions and pass it to the THINC function
     260         [ +  - ]:   13514200 :   std::vector< real > alSol(rdof*nmat, 0.0);
     261         [ +  - ]:   13514200 :   std::vector< real > alReco(nmat, 0.0);
     262         [ +  + ]:   20271300 :   for (std::size_t k=0; k<nmat; ++k) {
     263                 :   13514200 :     auto mark = k*rdof;
     264         [ +  + ]:   67571000 :     for (std::size_t i=0; i<rdof; ++i) {
     265         [ +  - ]:   54056800 :       alSol[mark+i] = U(e, volfracDofIdx(nmat,k,rdof,i));
     266                 :            :     }
     267                 :            :     // initialize with TVD reconstructions which will be modified if near
     268                 :            :     // material interface
     269                 :   13514200 :     alReco[k] = state[volfracIdx(nmat,k)];
     270                 :            :   }
     271 [ +  - ][ +  - ]:    6757100 :   THINCFunction(rdof, nmat, e, inpoel, coord, ref_xp, geoElem(e,0), bparam,
     272                 :            :     alSol, intInd, matInt, alReco);
     273                 :            : 
     274                 :            :   // check reconstructed volfracs for positivity
     275                 :    6757100 :   bool neg_vf = false;
     276         [ +  + ]:   20271300 :   for (std::size_t k=0; k<nmat; ++k) {
     277 [ -  + ][ -  - ]:   13514200 :     if (alReco[k] < 1e-16 && matInt[k] > 0) neg_vf = true;
                 [ -  + ]
     278                 :            :   }
     279         [ +  + ]:   20271300 :   for (std::size_t k=0; k<nmat; ++k) {
     280         [ -  + ]:   13514200 :     if (neg_vf) {
     281 [ -  - ][ -  - ]:          0 :       std::cout << "Material-id:        " << k << std::endl;
                 [ -  - ]
     282 [ -  - ][ -  - ]:          0 :       std::cout << "Volume-fraction:    " << std::setprecision(18) << alReco[k]
                 [ -  - ]
     283         [ -  - ]:          0 :         << std::endl;
     284 [ -  - ][ -  - ]:          0 :       std::cout << "Cell-avg vol-frac:  " << std::setprecision(18) <<
     285 [ -  - ][ -  - ]:          0 :         U(e,volfracDofIdx(nmat,k,rdof,0)) << std::endl;
                 [ -  - ]
     286 [ -  - ][ -  - ]:          0 :       std::cout << "Material-interface? " << intInd << std::endl;
                 [ -  - ]
     287 [ -  - ][ -  - ]:          0 :       std::cout << "Mat-k-involved?     " << matInt[k] << std::endl;
                 [ -  - ]
     288                 :            :     }
     289                 :            :   }
     290 [ -  + ][ -  - ]:    6757100 :   if (neg_vf) Throw("Material has negative volume fraction after THINC "
         [ -  - ][ -  - ]
     291                 :            :     "reconstruction.");
     292                 :            : 
     293                 :            :   // Step-2: Perform consistent reconstruction on other conserved quantities
     294         [ +  + ]:    6757100 :   if (intInd)
     295                 :            :   {
     296                 :     239692 :     auto rhobCC(0.0), rhobHO(0.0);
     297         [ +  + ]:     719076 :     for (std::size_t k=0; k<nmat; ++k)
     298                 :            :     {
     299         [ +  - ]:     479384 :       auto alCC = U(e, volfracDofIdx(nmat,k,rdof,0));
     300                 :     479384 :       alCC = std::max(1e-14, alCC);
     301                 :            : 
     302         [ +  - ]:     479384 :       if (matInt[k])
     303                 :            :       {
     304                 :     479384 :         state[volfracIdx(nmat,k)] = alReco[k];
     305                 :     958768 :         state[densityIdx(nmat,k)] = alReco[k]
     306         [ +  - ]:     479384 :           * U(e, densityDofIdx(nmat,k,rdof,0))/alCC;
     307                 :     958768 :         state[energyIdx(nmat,k)] = alReco[k]
     308         [ +  - ]:     479384 :           * U(e, energyDofIdx(nmat,k,rdof,0))/alCC;
     309                 :     958768 :         state[ncomp+pressureIdx(nmat,k)] = alReco[k]
     310         [ +  - ]:     479384 :           * P(e, pressureDofIdx(nmat,k,rdof,0))/alCC;
     311         [ -  + ]:     479384 :         if (solidx[k] > 0) {
     312         [ -  - ]:          0 :           for (std::size_t i=0; i<3; ++i)
     313         [ -  - ]:          0 :             for (std::size_t j=0; j<3; ++j)
     314                 :          0 :               state[deformIdx(nmat,solidx[k],i,j)] =
     315         [ -  - ]:          0 :                 U(e, deformDofIdx(nmat,solidx[k],i,j,rdof,0));
     316                 :            : 
     317         [ -  - ]:          0 :           for (std::size_t i=0; i<6; ++i)
     318                 :          0 :             state[ncomp+stressIdx(nmat,solidx[k],i)] = alReco[k]
     319         [ -  - ]:          0 :               * P(e, stressDofIdx(nmat,solidx[k],i,rdof,0))/alCC;
     320                 :            :         }
     321                 :            :       }
     322                 :            : 
     323         [ +  - ]:     479384 :       rhobCC += U(e, densityDofIdx(nmat,k,rdof,0));
     324                 :     479384 :       rhobHO += state[densityIdx(nmat,k)];
     325                 :            :     }
     326                 :            : 
     327                 :            :     // consistent reconstruction for bulk momentum
     328         [ +  + ]:     958768 :     for (std::size_t i=0; i<3; ++i)
     329                 :            :     {
     330                 :     719076 :       state[momentumIdx(nmat,i)] = rhobHO
     331         [ +  - ]:     719076 :         * U(e, momentumDofIdx(nmat,i,rdof,0))/rhobCC;
     332                 :     719076 :       state[ncomp+velocityIdx(nmat,i)] =
     333         [ +  - ]:     719076 :         P(e, velocityDofIdx(nmat,i,rdof,0));
     334                 :            :     }
     335                 :            :   }
     336                 :    6757100 : }
     337                 :            : 
     338                 :            : void
     339                 :          0 : THINCRecoTransport( std::size_t rdof,
     340                 :            :                     std::size_t,
     341                 :            :                     std::size_t e,
     342                 :            :                     const std::vector< std::size_t >& inpoel,
     343                 :            :                     const UnsMesh::Coords& coord,
     344                 :            :                     const Fields& geoElem,
     345                 :            :                     const std::array< real, 3 >& ref_xp,
     346                 :            :                     const Fields& U,
     347                 :            :                     const Fields&,
     348                 :            :                     [[maybe_unused]] const std::vector< real >& vfmin,
     349                 :            :                     [[maybe_unused]] const std::vector< real >& vfmax,
     350                 :            :                     std::vector< real >& state )
     351                 :            : // *****************************************************************************
     352                 :            : //  Compute THINC reconstructions at quadrature point for transport
     353                 :            : //! \param[in] rdof Total number of reconstructed dofs
     354                 :            : //! \param[in] e Element for which interface reconstruction is being calculated
     355                 :            : //! \param[in] inpoel Element-node connectivity
     356                 :            : //! \param[in] coord Array of nodal coordinates
     357                 :            : //! \param[in] geoElem Element geometry array
     358                 :            : //! \param[in] ref_xp Quadrature point in reference space
     359                 :            : //! \param[in] U Solution vector
     360                 :            : //! \param[in] vfmin Vector containing min volume fractions for each material
     361                 :            : //!   in this cell
     362                 :            : //! \param[in] vfmax Vector containing max volume fractions for each material
     363                 :            : //!   in this cell
     364                 :            : //! \param[in,out] state Unknown/state vector at quadrature point, modified
     365                 :            : //!   if near interfaces using THINC
     366                 :            : //! \details This function is an interface for the transport PDEs that use the
     367                 :            : //!   algebraic multi-material THINC reconstruction. This particular function
     368                 :            : //!   should only be called for transport.
     369                 :            : // *****************************************************************************
     370                 :            : {
     371                 :            :   auto bparam = inciter::g_inputdeck.get< tag::transport,
     372                 :          0 :     tag::intsharp_param >();
     373                 :          0 :   auto ncomp = U.nprop()/rdof;
     374                 :            : 
     375                 :            :   // interface detection
     376         [ -  - ]:          0 :   std::vector< std::size_t > matInt(ncomp, 0);
     377         [ -  - ]:          0 :   std::vector< tk::real > alAvg(ncomp, 0.0);
     378         [ -  - ]:          0 :   for (std::size_t k=0; k<ncomp; ++k)
     379         [ -  - ]:          0 :     alAvg[k] = U(e, k*rdof);
     380         [ -  - ]:          0 :   auto intInd = inciter::interfaceIndicator(ncomp, alAvg, matInt);
     381                 :            : 
     382                 :            :   // create a vector of volume-fractions and pass it to the THINC function
     383         [ -  - ]:          0 :   std::vector< real > alSol(rdof*ncomp, 0.0);
     384                 :            :   // initialize with TVD reconstructions (modified if near interface)
     385         [ -  - ]:          0 :   auto alReco = state;
     386         [ -  - ]:          0 :   for (std::size_t k=0; k<ncomp; ++k) {
     387                 :          0 :     auto mark = k*rdof;
     388         [ -  - ]:          0 :     for (std::size_t i=0; i<rdof; ++i) {
     389         [ -  - ]:          0 :       alSol[mark+i] = U(e,mark+i);
     390                 :            :     }
     391                 :            :   }
     392 [ -  - ][ -  - ]:          0 :   THINCFunction(rdof, ncomp, e, inpoel, coord, ref_xp, geoElem(e,0), bparam,
     393                 :            :     alSol, intInd, matInt, alReco);
     394                 :            : 
     395         [ -  - ]:          0 :   state = alReco;
     396                 :          0 : }
     397                 :            : 
     398                 :            : void
     399                 :          0 : THINCFunction_old( std::size_t rdof,
     400                 :            :                std::size_t nmat,
     401                 :            :                std::size_t e,
     402                 :            :                const std::vector< std::size_t >& inpoel,
     403                 :            :                const UnsMesh::Coords& coord,
     404                 :            :                const std::array< real, 3 >& ref_xp,
     405                 :            :                real vol,
     406                 :            :                real bparam,
     407                 :            :                const std::vector< real >& alSol,
     408                 :            :                bool intInd,
     409                 :            :                const std::vector< std::size_t >& matInt,
     410                 :            :                std::vector< real >& alReco )
     411                 :            : // *****************************************************************************
     412                 :            : //  Old version of the Multi-Medium THINC reconstruction function
     413                 :            : //! \param[in] rdof Total number of reconstructed dofs
     414                 :            : //! \param[in] nmat Total number of materials
     415                 :            : //! \param[in] e Element for which interface reconstruction is being calculated
     416                 :            : //! \param[in] inpoel Element-node connectivity
     417                 :            : //! \param[in] coord Array of nodal coordinates
     418                 :            : //! \param[in] ref_xp Quadrature point in reference space
     419                 :            : //! \param[in] vol Element volume
     420                 :            : //! \param[in] bparam User specified Beta for THINC, from the input file
     421                 :            : //! \param[in] alSol Volume fraction solution vector for element e
     422                 :            : //! \param[in] intInd Interface indicator, true if e is interface element
     423                 :            : //! \param[in] matInt Vector indicating materials which constitute interface
     424                 :            : //! \param[in,out] alReco Unknown/state vector at quadrature point, which gets
     425                 :            : //!   modified if near interface using MM-THINC
     426                 :            : //! \details This function computes the interface reconstruction using the
     427                 :            : //!   algebraic multi-material THINC reconstruction for each material at the
     428                 :            : //!   given (ref_xp) quadrature point. This function is based on the following:
     429                 :            : //!   Pandare A. K., Waltz J., & Bakosi J. (2021) Multi-Material Hydrodynamics
     430                 :            : //!   with Algebraic Sharp Interface Capturing. Computers & Fluids,
     431                 :            : //!   doi: https://doi.org/10.1016/j.compfluid.2020.104804.
     432                 :            : //!   This function will be removed after the newer version (see
     433                 :            : //!   THINCFunction_new) is sufficiently tested.
     434                 :            : // *****************************************************************************
     435                 :            : {
     436                 :            :   auto min_al = inciter::g_inputdeck.get< tag::multimat,
     437                 :          0 :     tag::min_volumefrac >();
     438                 :            : 
     439                 :            :   // determine number of materials with interfaces in this cell
     440                 :          0 :   auto epsl(1e-4), epsh(1e-1), bred(1.25), bmod(bparam);
     441                 :          0 :   std::size_t nIntMat(0);
     442         [ -  - ]:          0 :   for (std::size_t k=0; k<nmat; ++k)
     443                 :            :   {
     444                 :          0 :     auto alk = alSol[k*rdof];
     445         [ -  - ]:          0 :     if (alk > epsl)
     446                 :            :     {
     447                 :          0 :       ++nIntMat;
     448 [ -  - ][ -  - ]:          0 :       if ((alk > epsl) && (alk < epsh))
     449                 :          0 :         bmod = std::min(bmod,
     450                 :          0 :           (alk-epsl)/(epsh-epsl) * (bred - bparam) + bparam);
     451         [ -  - ]:          0 :       else if (alk > epsh)
     452                 :          0 :         bmod = bred;
     453                 :            :     }
     454                 :            :   }
     455                 :            : 
     456         [ -  - ]:          0 :   if (nIntMat > 2) bparam = bmod;
     457                 :            : 
     458                 :            :   // compression parameter
     459                 :          0 :   auto beta = bparam/std::cbrt(6.0*vol);
     460                 :            : 
     461         [ -  - ]:          0 :   if (intInd)
     462                 :            :   {
     463                 :            :     // 1. Get unit normals to material interface
     464                 :            : 
     465                 :            :     // Compute Jacobian matrix for converting Dubiner dofs to derivatives
     466                 :          0 :     const auto& cx = coord[0];
     467                 :          0 :     const auto& cy = coord[1];
     468                 :          0 :     const auto& cz = coord[2];
     469                 :            : 
     470                 :            :     std::array< std::array< real, 3>, 4 > coordel {{
     471                 :          0 :       {{ cx[ inpoel[4*e  ] ], cy[ inpoel[4*e  ] ], cz[ inpoel[4*e  ] ] }},
     472                 :          0 :       {{ cx[ inpoel[4*e+1] ], cy[ inpoel[4*e+1] ], cz[ inpoel[4*e+1] ] }},
     473                 :          0 :       {{ cx[ inpoel[4*e+2] ], cy[ inpoel[4*e+2] ], cz[ inpoel[4*e+2] ] }},
     474                 :          0 :       {{ cx[ inpoel[4*e+3] ], cy[ inpoel[4*e+3] ], cz[ inpoel[4*e+3] ] }}
     475                 :          0 :     }};
     476                 :            : 
     477                 :            :     auto jacInv =
     478                 :          0 :       tk::inverseJacobian( coordel[0], coordel[1], coordel[2], coordel[3] );
     479                 :            : 
     480         [ -  - ]:          0 :     auto dBdx = tk::eval_dBdx_p1( rdof, jacInv );
     481                 :            : 
     482                 :            :     std::array< real, 3 > nInt;
     483         [ -  - ]:          0 :     std::vector< std::array< real, 3 > > ref_n(nmat, {{0.0, 0.0, 0.0}});
     484                 :            : 
     485                 :            :     // Get normals
     486         [ -  - ]:          0 :     for (std::size_t k=0; k<nmat; ++k)
     487                 :            :     {
     488                 :            :       // Get derivatives from moments in Dubiner space
     489         [ -  - ]:          0 :       for (std::size_t i=0; i<3; ++i)
     490                 :          0 :         nInt[i] = dBdx[i][1] * alSol[k*rdof+1]
     491                 :          0 :           + dBdx[i][2] * alSol[k*rdof+2]
     492                 :          0 :           + dBdx[i][3] * alSol[k*rdof+3];
     493                 :            : 
     494                 :          0 :       auto nMag = std::sqrt(tk::dot(nInt, nInt)) + 1e-14;
     495                 :            : 
     496         [ -  - ]:          0 :       for (std::size_t i=0; i<3; ++i)
     497                 :          0 :         nInt[i] /= nMag;
     498                 :            : 
     499                 :            :       // project interface normal onto local/reference coordinate system
     500         [ -  - ]:          0 :       for (std::size_t i=0; i<3; ++i)
     501                 :            :       {
     502                 :            :         std::array< real, 3 > axis{
     503                 :          0 :           coordel[i+1][0]-coordel[0][0],
     504                 :          0 :           coordel[i+1][1]-coordel[0][1],
     505                 :          0 :           coordel[i+1][2]-coordel[0][2] };
     506                 :          0 :         ref_n[k][i] = tk::dot(nInt, axis);
     507                 :            :       }
     508                 :            :     }
     509                 :            : 
     510                 :            :     // 2. Reconstruct volume fractions using THINC
     511                 :          0 :     auto max_lim = 1.0 - (static_cast<tk::real>(nmat-1)*min_al);
     512                 :          0 :     auto min_lim = min_al;
     513                 :          0 :     auto sum_inter(0.0), sum_non_inter(0.0);
     514         [ -  - ]:          0 :     for (std::size_t k=0; k<nmat; ++k)
     515                 :            :     {
     516         [ -  - ]:          0 :       if (matInt[k])
     517                 :            :       {
     518                 :            :         // get location of material interface (volume fraction 0.5) from the
     519                 :            :         // assumed tanh volume fraction distribution, and cell-averaged
     520                 :            :         // volume fraction
     521                 :          0 :         auto alCC(alSol[k*rdof]);
     522                 :          0 :         auto Ac(0.0), Bc(0.0), Qc(0.0);
     523                 :          0 :         if ((std::abs(ref_n[k][0]) > std::abs(ref_n[k][1]))
     524 [ -  - ][ -  - ]:          0 :           && (std::abs(ref_n[k][0]) > std::abs(ref_n[k][2])))
                 [ -  - ]
     525                 :            :         {
     526                 :          0 :           Ac = std::exp(0.5*beta*ref_n[k][0]);
     527                 :          0 :           Bc = std::exp(0.5*beta*(ref_n[k][1]+ref_n[k][2]));
     528                 :          0 :           Qc = std::exp(0.5*beta*ref_n[k][0]*(2.0*alCC-1.0));
     529                 :            :         }
     530                 :          0 :         else if ((std::abs(ref_n[k][1]) > std::abs(ref_n[k][0]))
     531 [ -  - ][ -  - ]:          0 :           && (std::abs(ref_n[k][1]) > std::abs(ref_n[k][2])))
                 [ -  - ]
     532                 :            :         {
     533                 :          0 :           Ac = std::exp(0.5*beta*ref_n[k][1]);
     534                 :          0 :           Bc = std::exp(0.5*beta*(ref_n[k][0]+ref_n[k][2]));
     535                 :          0 :           Qc = std::exp(0.5*beta*ref_n[k][1]*(2.0*alCC-1.0));
     536                 :            :         }
     537                 :            :         else
     538                 :            :         {
     539                 :          0 :           Ac = std::exp(0.5*beta*ref_n[k][2]);
     540                 :          0 :           Bc = std::exp(0.5*beta*(ref_n[k][0]+ref_n[k][1]));
     541                 :          0 :           Qc = std::exp(0.5*beta*ref_n[k][2]*(2.0*alCC-1.0));
     542                 :            :         }
     543                 :          0 :         auto d = std::log((1.0-Ac*Qc) / (Ac*Bc*(Qc-Ac))) / (2.0*beta);
     544                 :            : 
     545                 :            :         // THINC reconstruction
     546                 :          0 :         auto al_c = 0.5 * (1.0 + std::tanh(beta*(tk::dot(ref_n[k], ref_xp) + d)));
     547                 :            : 
     548                 :          0 :         alReco[k] = std::min(max_lim, std::max(min_lim, al_c));
     549                 :            : 
     550                 :          0 :         sum_inter += alReco[k];
     551                 :            :       } else
     552                 :            :       {
     553                 :          0 :         sum_non_inter += alReco[k];
     554                 :            :       }
     555                 :            :       // else, if this material does not have an interface close-by, the TVD
     556                 :            :       // reconstructions must be used for state variables. This is ensured by
     557                 :            :       // initializing the alReco vector as the TVD state.
     558                 :            :     }
     559                 :            : 
     560                 :            :     // Rescale volume fractions of interface-materials to ensure unit sum
     561                 :          0 :     auto sum_rest = 1.0 - sum_non_inter;
     562         [ -  - ]:          0 :     for (std::size_t k=0; k<nmat; ++k)
     563         [ -  - ]:          0 :       if(matInt[k])
     564                 :          0 :         alReco[k] = alReco[k] * sum_rest / sum_inter;
     565                 :            :   }
     566                 :          0 : }
     567                 :            : 
     568                 :            : void
     569                 :    6757100 : THINCFunction( std::size_t rdof,
     570                 :            :                std::size_t nmat,
     571                 :            :                std::size_t e,
     572                 :            :                const std::vector< std::size_t >& inpoel,
     573                 :            :                const UnsMesh::Coords& coord,
     574                 :            :                const std::array< real, 3 >& ref_xp,
     575                 :            :                real vol,
     576                 :            :                real bparam,
     577                 :            :                const std::vector< real >& alSol,
     578                 :            :                bool intInd,
     579                 :            :                const std::vector< std::size_t >& matInt,
     580                 :            :                std::vector< real >& alReco )
     581                 :            : // *****************************************************************************
     582                 :            : //  Multi-Medium THINC reconstruction function for volume fractions
     583                 :            : //! \param[in] rdof Total number of reconstructed dofs
     584                 :            : //! \param[in] nmat Total number of materials
     585                 :            : //! \param[in] e Element for which interface reconstruction is being calculated
     586                 :            : //! \param[in] inpoel Element-node connectivity
     587                 :            : //! \param[in] coord Array of nodal coordinates
     588                 :            : //! \param[in] ref_xp Quadrature point in reference space
     589                 :            : //! \param[in] vol Element volume
     590                 :            : //! \param[in] bparam User specified Beta for THINC, from the input file
     591                 :            : //! \param[in] alSol Volume fraction solution vector for element e
     592                 :            : //! \param[in] intInd Interface indicator, true if e is interface element
     593                 :            : //! \param[in] matInt Vector indicating materials which constitute interface
     594                 :            : //! \param[in,out] alReco Unknown/state vector at quadrature point, which gets
     595                 :            : //!   modified if near interface using MM-THINC
     596                 :            : //! \details This function computes the interface reconstruction using the
     597                 :            : //!   algebraic multi-material THINC reconstruction for each material at the
     598                 :            : //!   given (ref_xp) quadrature point. This function succeeds the older version
     599                 :            : //!   of the mm-THINC (see THINCFunction_old).
     600                 :            : // *****************************************************************************
     601                 :            : {
     602                 :            :   auto min_al = inciter::g_inputdeck.get< tag::multimat,
     603                 :    6757100 :     tag::min_volumefrac >();
     604                 :            : 
     605                 :            :   // compression parameter
     606                 :    6757100 :   auto beta = bparam/std::cbrt(6.0*vol);
     607                 :            : 
     608                 :            :   // If the cell is not material interface, return this function
     609         [ +  + ]:    6757100 :   if (not intInd) return;
     610                 :            : 
     611                 :            :   // If the cell is material interface, THINC reconstruction is applied
     612                 :            :   // Step 1. Get unit normals to material interface
     613                 :            :   // -------------------------------------------------------------------------
     614                 :            : 
     615                 :            :   // Compute Jacobian matrix for converting Dubiner dofs to derivatives
     616                 :     239692 :   const auto& cx = coord[0];
     617                 :     239692 :   const auto& cy = coord[1];
     618                 :     239692 :   const auto& cz = coord[2];
     619                 :            : 
     620                 :            :   std::array< std::array< real, 3>, 4 > coordel {{
     621                 :     719076 :     {{ cx[ inpoel[4*e  ] ], cy[ inpoel[4*e  ] ], cz[ inpoel[4*e  ] ] }},
     622                 :     719076 :     {{ cx[ inpoel[4*e+1] ], cy[ inpoel[4*e+1] ], cz[ inpoel[4*e+1] ] }},
     623                 :     719076 :     {{ cx[ inpoel[4*e+2] ], cy[ inpoel[4*e+2] ], cz[ inpoel[4*e+2] ] }},
     624                 :     719076 :     {{ cx[ inpoel[4*e+3] ], cy[ inpoel[4*e+3] ], cz[ inpoel[4*e+3] ] }}
     625                 :    2636612 :   }};
     626                 :            : 
     627                 :            :   auto jacInv =
     628                 :     239692 :     tk::inverseJacobian( coordel[0], coordel[1], coordel[2], coordel[3] );
     629                 :            : 
     630         [ +  - ]:     239692 :   auto dBdx = tk::eval_dBdx_p1( rdof, jacInv );
     631                 :            : 
     632                 :            :   std::array< real, 3 > nInt;
     633                 :     239692 :   std::array< real, 3 > ref_n{0.0, 0.0, 0.0};
     634                 :     239692 :   auto almax(0.0);
     635                 :     239692 :   std::size_t kmax(0);
     636                 :            : 
     637                 :            :   // Determine index of material present in majority
     638         [ +  + ]:     719076 :   for (std::size_t k=0; k<nmat; ++k)
     639                 :            :   {
     640                 :     479384 :     auto alk = alSol[k*rdof];
     641         [ +  - ]:     479384 :     if (alk > almax)
     642                 :            :     {
     643                 :     479384 :       almax = alk;
     644                 :     479384 :       kmax = k;
     645                 :            :     }
     646                 :            :   }
     647                 :            : 
     648                 :            :   // Get normals of material present in majority
     649                 :            :   // Get derivatives from moments in Dubiner space
     650         [ +  + ]:     958768 :   for (std::size_t i=0; i<3; ++i)
     651                 :    1438152 :     nInt[i] = dBdx[i][1] * alSol[kmax*rdof+1]
     652                 :     719076 :       + dBdx[i][2] * alSol[kmax*rdof+2]
     653                 :     719076 :       + dBdx[i][3] * alSol[kmax*rdof+3];
     654                 :            : 
     655                 :     239692 :   auto nMag = std::sqrt(tk::dot(nInt, nInt)) + 1e-14;
     656                 :            : 
     657         [ +  + ]:     958768 :   for (std::size_t i=0; i<3; ++i)
     658                 :     719076 :     nInt[i] /= nMag;
     659                 :            : 
     660                 :            :   // project interface normal onto local/reference coordinate system
     661         [ +  + ]:     958768 :   for (std::size_t i=0; i<3; ++i)
     662                 :            :   {
     663                 :            :     std::array< real, 3 > axis{
     664                 :     719076 :       coordel[i+1][0]-coordel[0][0],
     665                 :     719076 :       coordel[i+1][1]-coordel[0][1],
     666                 :    1438152 :       coordel[i+1][2]-coordel[0][2] };
     667                 :     719076 :     ref_n[i] = tk::dot(nInt, axis);
     668                 :            :   }
     669                 :            : 
     670                 :            :   // Step 2. Reconstruct volume fraction of majority material using THINC
     671                 :            :   // -------------------------------------------------------------------------
     672                 :            : 
     673                 :     239692 :   auto al_max = 1.0 - (static_cast<tk::real>(nmat-1)*min_al);
     674                 :     239692 :   auto al_min = min_al;
     675                 :     239692 :   auto alsum(0.0);
     676                 :            :   // get location of material interface (volume fraction 0.5) from the
     677                 :            :   // assumed tanh volume fraction distribution, and cell-averaged
     678                 :            :   // volume fraction
     679                 :     239692 :   auto alCC(alSol[kmax*rdof]);
     680                 :     239692 :   auto Ac(0.0), Bc(0.0), Qc(0.0);
     681                 :     239692 :   if ((std::abs(ref_n[0]) > std::abs(ref_n[1]))
     682 [ +  + ][ +  + ]:     239692 :     && (std::abs(ref_n[0]) > std::abs(ref_n[2])))
                 [ +  + ]
     683                 :            :   {
     684                 :      96141 :     Ac = std::exp(0.5*beta*ref_n[0]);
     685                 :      96141 :     Bc = std::exp(0.5*beta*(ref_n[1]+ref_n[2]));
     686                 :      96141 :     Qc = std::exp(0.5*beta*ref_n[0]*(2.0*alCC-1.0));
     687                 :            :   }
     688                 :     143551 :   else if ((std::abs(ref_n[1]) > std::abs(ref_n[0]))
     689 [ +  + ][ +  + ]:     143551 :     && (std::abs(ref_n[1]) > std::abs(ref_n[2])))
                 [ +  + ]
     690                 :            :   {
     691                 :     106223 :     Ac = std::exp(0.5*beta*ref_n[1]);
     692                 :     106223 :     Bc = std::exp(0.5*beta*(ref_n[0]+ref_n[2]));
     693                 :     106223 :     Qc = std::exp(0.5*beta*ref_n[1]*(2.0*alCC-1.0));
     694                 :            :   }
     695                 :            :   else
     696                 :            :   {
     697                 :      37328 :     Ac = std::exp(0.5*beta*ref_n[2]);
     698                 :      37328 :     Bc = std::exp(0.5*beta*(ref_n[0]+ref_n[1]));
     699                 :      37328 :     Qc = std::exp(0.5*beta*ref_n[2]*(2.0*alCC-1.0));
     700                 :            :   }
     701                 :     239692 :   auto d = std::log((1.0-Ac*Qc) / (Ac*Bc*(Qc-Ac))) / (2.0*beta);
     702                 :            : 
     703                 :            :   // THINC reconstruction
     704                 :     239692 :   auto al_c = 0.5 * (1.0 + std::tanh(beta*(tk::dot(ref_n, ref_xp) + d)));
     705                 :            : 
     706                 :     239692 :   alReco[kmax] = std::min(al_max, std::max(al_min, al_c));
     707                 :     239692 :   alsum += alReco[kmax];
     708                 :            : 
     709                 :            :   // if this material does not have an interface close-by, the TVD
     710                 :            :   // reconstructions must be used for state variables. This is ensured by
     711                 :            :   // initializing the alReco vector as the TVD state.
     712         [ +  + ]:     719076 :   for (std::size_t k=0; k<nmat; ++k) {
     713         [ -  + ]:     479384 :     if (!matInt[k]) {
     714                 :          0 :       alsum += alReco[k];
     715                 :            :     }
     716                 :            :   }
     717                 :            : 
     718                 :            :   // Step 3. Do multimaterial cell corrections
     719                 :            :   // -------------------------------------------------------------------------
     720                 :            : 
     721                 :            :   // distribute remaining volume to rest of materials
     722                 :     239692 :   auto sum_left = 1.0 - alsum;
     723                 :     239692 :   real den = 0.0;
     724         [ +  + ]:     719076 :   for (std::size_t k=0; k<nmat; ++k) {
     725 [ +  - ][ +  + ]:     479384 :     if (matInt[k] && k != kmax) {
                 [ +  + ]
     726                 :     239692 :       auto mark = k * rdof;
     727                 :     239692 :       alReco[k] = sum_left * alSol[mark];
     728                 :     239692 :       den += alSol[mark];
     729                 :            :     }
     730                 :            :   }
     731                 :            :   // the distributed volfracs might be below al_min, correct that
     732                 :     239692 :   real err = 0.0;
     733         [ +  + ]:     719076 :   for (std::size_t k=0; k<nmat; ++k) {
     734 [ +  - ][ +  + ]:     479384 :     if (matInt[k] && k != kmax) {
                 [ +  + ]
     735                 :     239692 :       alReco[k] /= den;
     736         [ -  + ]:     239692 :       if (alReco[k] < al_min) {
     737                 :          0 :         err += al_min - alReco[k];
     738                 :          0 :         alReco[k] = al_min;
     739                 :            :       }
     740                 :            :     }
     741                 :            :   }
     742                 :            : 
     743                 :            :   // balance out errors
     744                 :     239692 :   alReco[kmax] -= err;
     745                 :            : }
     746                 :            : 
     747                 :            : void
     748                 :          0 : computeTemperaturesFV(
     749                 :            :   const std::vector< inciter::EOS >& mat_blk,
     750                 :            :   std::size_t nmat,
     751                 :            :   const std::vector< std::size_t >& inpoel,
     752                 :            :   const tk::UnsMesh::Coords& coord,
     753                 :            :   const tk::Fields& geoElem,
     754                 :            :   const tk::Fields& unk,
     755                 :            :   const tk::Fields& prim,
     756                 :            :   const std::vector< int >& srcFlag,
     757                 :            :   tk::Fields& T )
     758                 :            : // *****************************************************************************
     759                 :            : //  Compute the temperatures based on FV conserved quantities
     760                 :            : //! \param[in] mat_blk EOS material block
     761                 :            : //! \param[in] nmat Number of materials in this PDE system
     762                 :            : //! \param[in] inpoel Element-node connectivity
     763                 :            : //! \param[in] coord Array of nodal coordinates
     764                 :            : //! \param[in] geoElem Element geometry array
     765                 :            : //! \param[in] unk Array of conservative variables
     766                 :            : //! \param[in] prim Array of primitive variables
     767                 :            : //! \param[in] srcFlag Whether the energy source was added
     768                 :            : //! \param[in,out] T Array of material temperature dofs
     769                 :            : //! \details This function computes the dofs of material temperatures based on
     770                 :            : //!   conservative quantities from an FV scheme, using EOS calls. It uses the
     771                 :            : //!   weak form m_{ij} T_i = \int T_{EOS}(rho, rhoE, u) B_j.
     772                 :            : // *****************************************************************************
     773                 :            : {
     774                 :          0 :   const auto rdof = inciter::g_inputdeck.get< tag::rdof >();
     775                 :          0 :   std::size_t ncomp = unk.nprop()/rdof;
     776                 :          0 :   std::size_t nprim = prim.nprop()/rdof;
     777                 :            :   const auto intsharp = inciter::g_inputdeck.get< tag::multimat,
     778                 :          0 :     tag::intsharp >();
     779                 :          0 :   auto nelem = unk.nunk();
     780                 :            : 
     781                 :          0 :   auto L = tk::massMatrixDubiner();
     782                 :            : 
     783         [ -  - ]:          0 :   for (std::size_t e=0; e<nelem; ++e) {
     784         [ -  - ]:          0 :     auto vole = geoElem(e,0);
     785                 :            : 
     786         [ -  - ]:          0 :     std::vector< tk::real > R(nmat*rdof, 0.0);
     787                 :            : 
     788                 :          0 :     std::size_t ng = 11;
     789                 :            : 
     790                 :            :     // Arrays for quadrature points
     791                 :          0 :     std::array< std::vector< tk::real >, 3 > coordgp;
     792                 :          0 :     std::vector< tk::real > wgp;
     793                 :            : 
     794         [ -  - ]:          0 :     coordgp[0].resize( ng );
     795         [ -  - ]:          0 :     coordgp[1].resize( ng );
     796         [ -  - ]:          0 :     coordgp[2].resize( ng );
     797         [ -  - ]:          0 :     wgp.resize( ng );
     798                 :            : 
     799         [ -  - ]:          0 :     tk::GaussQuadratureTet( ng, coordgp, wgp );
     800                 :            : 
     801                 :            :     // Loop over quadrature points in element e
     802         [ -  - ]:          0 :     for (std::size_t igp=0; igp<ng; ++igp) {
     803                 :            :       // Compute the basis function
     804                 :          0 :       auto B = tk::eval_basis( rdof, coordgp[0][igp], coordgp[1][igp],
     805         [ -  - ]:          0 :                                coordgp[2][igp] );
     806                 :            : 
     807                 :          0 :       auto w = wgp[igp] * vole;
     808                 :            : 
     809                 :            :       // Evaluate the solution at quadrature point
     810                 :            :       auto state = evalFVSol(mat_blk, intsharp, ncomp, nprim, rdof,
     811                 :            :         nmat, e, inpoel, coord, geoElem,
     812                 :          0 :         {{coordgp[0][igp], coordgp[1][igp], coordgp[2][igp]}}, B, unk, prim,
     813         [ -  - ]:          0 :         srcFlag[e]);
     814                 :            : 
     815                 :            :       // Velocity vector at quadrature point
     816                 :            :       std::array< tk::real, 3 >
     817                 :          0 :         vel{ state[ncomp+inciter::velocityIdx(nmat, 0)],
     818                 :          0 :              state[ncomp+inciter::velocityIdx(nmat, 1)],
     819                 :          0 :              state[ncomp+inciter::velocityIdx(nmat, 2)] };
     820                 :            : 
     821                 :            :       // Evaluate the right-hand-side vector (for temperature)
     822         [ -  - ]:          0 :       for(std::size_t k=0; k<nmat; k++) {
     823         [ -  - ]:          0 :         auto tk = mat_blk[k].compute< inciter::EOS::temperature >(
     824                 :          0 :           state[inciter::densityIdx(nmat, k)], vel[0], vel[1], vel[2],
     825                 :          0 :           state[inciter::energyIdx(nmat, k)],
     826                 :          0 :           state[inciter::volfracIdx(nmat, k)] );
     827                 :          0 :         auto mark = k * rdof;
     828         [ -  - ]:          0 :         for(std::size_t idof=0; idof<rdof; idof++)
     829                 :          0 :           R[mark+idof] += w * tk * B[idof];
     830                 :            :       }
     831                 :            :     }
     832                 :            : 
     833                 :            :     // Update the high order dofs of the temperature
     834         [ -  - ]:          0 :     for(std::size_t k=0; k<nmat; k++) {
     835                 :          0 :       auto mark = k * rdof;
     836         [ -  - ]:          0 :       for(std::size_t idof=1; idof<rdof; idof++)
     837         [ -  - ]:          0 :         T(e, mark+idof) = R[mark+idof] / (vole*L[idof]);
     838                 :            :     }
     839                 :            :   }
     840                 :          0 : }
     841                 :            : 
     842                 :            : std::vector< tk::real >
     843                 :   92378342 : evalPolynomialSol( const std::vector< inciter::EOS >& mat_blk,
     844                 :            :                    int intsharp,
     845                 :            :                    std::size_t ncomp,
     846                 :            :                    std::size_t nprim,
     847                 :            :                    std::size_t rdof,
     848                 :            :                    std::size_t nmat,
     849                 :            :                    std::size_t e,
     850                 :            :                    std::size_t dof_e,
     851                 :            :                    const std::vector< std::size_t >& inpoel,
     852                 :            :                    const UnsMesh::Coords& coord,
     853                 :            :                    const Fields& geoElem,
     854                 :            :                    const std::array< real, 3 >& ref_gp,
     855                 :            :                    const std::vector< real >& B,
     856                 :            :                    const Fields& U,
     857                 :            :                    const Fields& P )
     858                 :            : // *****************************************************************************
     859                 :            : //  Evaluate polynomial solution at quadrature point
     860                 :            : //! \param[in] mat_blk EOS material block
     861                 :            : //! \param[in] intsharp Interface reconstruction indicator
     862                 :            : //! \param[in] ncomp Number of components in the PDE system
     863                 :            : //! \param[in] nprim Number of primitive quantities
     864                 :            : //! \param[in] rdof Total number of reconstructed dofs
     865                 :            : //! \param[in] nmat Total number of materials
     866                 :            : //! \param[in] e Element for which polynomial solution is being evaluated
     867                 :            : //! \param[in] dof_e Degrees of freedom for element
     868                 :            : //! \param[in] inpoel Element-node connectivity
     869                 :            : //! \param[in] coord Array of nodal coordinates
     870                 :            : //! \param[in] geoElem Element geometry array
     871                 :            : //! \param[in] ref_gp Quadrature point in reference space
     872                 :            : //! \param[in] B Basis function at given quadrature point
     873                 :            : //! \param[in] U Solution vector
     874                 :            : //! \param[in] P Vector of primitives
     875                 :            : //! \return High-order unknown/state vector at quadrature point, modified
     876                 :            : //!   if near interfaces using THINC
     877                 :            : // *****************************************************************************
     878                 :            : {
     879                 :   92378342 :   std::vector< real > state;
     880                 :  184756684 :   std::vector< real > sprim;
     881                 :            : 
     882         [ +  - ]:   92378342 :   state = eval_state( ncomp, rdof, dof_e, e, U, B );
     883         [ +  - ]:   92378342 :   sprim = eval_state( nprim, rdof, dof_e, e, P, B );
     884                 :            : 
     885                 :            :   // interface detection
     886         [ +  - ]:  184756684 :   std::vector< std::size_t > matInt(nmat, 0);
     887                 :   92378342 :   bool intInd(false);
     888         [ +  + ]:   92378342 :   if (nmat > 1) {
     889         [ +  - ]:   21687110 :     std::vector< tk::real > alAvg(nmat, 0.0);
     890         [ +  + ]:   70611090 :     for (std::size_t k=0; k<nmat; ++k)
     891         [ +  - ]:   48923980 :       alAvg[k] = U(e, inciter::volfracDofIdx(nmat,k,rdof,0));
     892         [ +  - ]:   21687110 :     intInd = inciter::interfaceIndicator(nmat, alAvg, matInt);
     893                 :            :   }
     894                 :            : 
     895                 :            :   // consolidate primitives into state vector
     896         [ +  - ]:   92378342 :   state.insert(state.end(), sprim.begin(), sprim.end());
     897                 :            : 
     898         [ +  + ]:   92378342 :   if (intsharp > 0)
     899                 :            :   {
     900 [ +  - ][ +  - ]:   12411000 :     std::vector< tk::real > vfmax(nmat, 0.0), vfmin(nmat, 0.0);
     901                 :            : 
     902                 :            :     // Until the appropriate setup for activating THINC with Transport
     903                 :            :     // is ready, the following two chunks of code will need to be commented
     904                 :            :     // for using THINC with Transport
     905                 :            :     //for (std::size_t k=0; k<nmat; ++k) {
     906                 :            :     //  vfmin[k] = VolFracMax(el, 2*k, 0);
     907                 :            :     //  vfmax[k] = VolFracMax(el, 2*k+1, 0);
     908                 :            :     //}
     909         [ +  - ]:    6205500 :     tk::THINCReco(rdof, nmat, e, inpoel, coord, geoElem,
     910                 :            :       ref_gp, U, P, intInd, matInt, vfmin, vfmax, state);
     911                 :            : 
     912                 :            :     // Until the appropriate setup for activating THINC with Transport
     913                 :            :     // is ready, the following lines will need to be uncommented for
     914                 :            :     // using THINC with Transport
     915                 :            :     //tk::THINCRecoTransport(rdof, nmat, el, inpoel, coord,
     916                 :            :     //  geoElem, ref_gp_l, U, P, vfmin, vfmax, state[0]);
     917                 :            :   }
     918                 :            : 
     919                 :            :   // physical constraints
     920         [ +  - ]:   92378342 :   enforcePhysicalConstraints(mat_blk, ncomp, nmat, state);
     921                 :            : 
     922                 :  184756684 :   return state;
     923                 :            : }
     924                 :            : 
     925                 :            : std::vector< tk::real >
     926                 :    1091856 : evalFVSol( const std::vector< inciter::EOS >& mat_blk,
     927                 :            :            int intsharp,
     928                 :            :            std::size_t ncomp,
     929                 :            :            std::size_t nprim,
     930                 :            :            std::size_t rdof,
     931                 :            :            std::size_t nmat,
     932                 :            :            std::size_t e,
     933                 :            :            const std::vector< std::size_t >& inpoel,
     934                 :            :            const UnsMesh::Coords& coord,
     935                 :            :            const Fields& geoElem,
     936                 :            :            const std::array< real, 3 >& ref_gp,
     937                 :            :            const std::vector< real >& B,
     938                 :            :            const Fields& U,
     939                 :            :            const Fields& P,
     940                 :            :            int srcFlag )
     941                 :            : // *****************************************************************************
     942                 :            : //  Evaluate second-order FV solution at quadrature point
     943                 :            : //! \param[in] mat_blk EOS material block
     944                 :            : //! \param[in] intsharp Interface reconstruction indicator
     945                 :            : //! \param[in] ncomp Number of components in the PDE system
     946                 :            : //! \param[in] nprim Number of primitive quantities
     947                 :            : //! \param[in] rdof Total number of reconstructed dofs
     948                 :            : //! \param[in] nmat Total number of materials
     949                 :            : //! \param[in] e Element for which polynomial solution is being evaluated
     950                 :            : //! \param[in] inpoel Element-node connectivity
     951                 :            : //! \param[in] coord Array of nodal coordinates
     952                 :            : //! \param[in] geoElem Element geometry array
     953                 :            : //! \param[in] ref_gp Quadrature point in reference space
     954                 :            : //! \param[in] B Basis function at given quadrature point
     955                 :            : //! \param[in] U Solution vector
     956                 :            : //! \param[in] P Vector of primitives
     957                 :            : //! \param[in] srcFlag Whether the energy source was added to element e
     958                 :            : //! \return High-order unknown/state vector at quadrature point, modified
     959                 :            : //!   if near interfaces using THINC
     960                 :            : // *****************************************************************************
     961                 :            : {
     962                 :            :   auto min_al = inciter::g_inputdeck.get< tag::multimat,
     963                 :    1091856 :     tag::min_volumefrac >();
     964                 :            : 
     965                 :            :   using inciter::pressureIdx;
     966                 :            :   using inciter::velocityIdx;
     967                 :            :   using inciter::volfracIdx;
     968                 :            :   using inciter::densityIdx;
     969                 :            :   using inciter::energyIdx;
     970                 :            :   using inciter::momentumIdx;
     971                 :            : 
     972                 :    1091856 :   std::vector< real > state;
     973                 :    2183712 :   std::vector< real > sprim;
     974                 :            : 
     975         [ +  - ]:    1091856 :   state = eval_state( ncomp, rdof, rdof, e, U, B );
     976         [ +  - ]:    1091856 :   sprim = eval_state( nprim, rdof, rdof, e, P, B );
     977                 :            : 
     978                 :            :   // interface detection so that eos is called on the appropriate quantities
     979         [ +  - ]:    2183712 :   std::vector< std::size_t > matInt(nmat, 0);
     980         [ +  - ]:    2183712 :   std::vector< tk::real > alAvg(nmat, 0.0);
     981         [ +  + ]:    3512624 :   for (std::size_t k=0; k<nmat; ++k)
     982         [ +  - ]:    2420768 :     alAvg[k] = U(e, inciter::volfracDofIdx(nmat,k,rdof,0));
     983         [ +  - ]:    1091856 :   auto intInd = inciter::interfaceIndicator(nmat, alAvg, matInt);
     984                 :            : 
     985                 :            :   std::array< tk::real, 3 > vel{{
     986                 :    1091856 :     sprim[velocityIdx(nmat,0)],
     987                 :    1091856 :     sprim[velocityIdx(nmat,1)],
     988                 :    2183712 :     sprim[velocityIdx(nmat,2)] }};
     989                 :            : 
     990                 :            :   // get mat-energy from reconstructed mat-pressure
     991                 :    1091856 :   auto rhob(0.0);
     992         [ +  + ]:    3512624 :   for (std::size_t k=0; k<nmat; ++k) {
     993                 :    2420768 :     auto alk = state[volfracIdx(nmat,k)];
     994         [ +  + ]:    2420768 :     if (matInt[k]) {
     995                 :      95028 :       alk = std::max(std::min(alk, 1.0-static_cast<tk::real>(nmat-1)*min_al),
     996                 :      95028 :         min_al);
     997                 :            :     }
     998                 :    2420768 :     state[energyIdx(nmat,k)] =
     999         [ +  - ]:    4841536 :       mat_blk[k].compute< inciter::EOS::totalenergy >(
    1000                 :    2420768 :       state[densityIdx(nmat,k)], vel[0],
    1001                 :    2420768 :       vel[1], vel[2],
    1002                 :    2420768 :       sprim[pressureIdx(nmat,k)], alk);
    1003                 :    2420768 :     rhob += state[densityIdx(nmat,k)];
    1004                 :            :   }
    1005                 :            :   // get momentum from reconstructed velocity and bulk density
    1006         [ +  + ]:    4367424 :   for (std::size_t i=0; i<3; ++i) {
    1007                 :    3275568 :     state[momentumIdx(nmat,i)] = rhob * vel[i];
    1008                 :            :   }
    1009                 :            : 
    1010                 :            :   // consolidate primitives into state vector
    1011         [ +  - ]:    1091856 :   state.insert(state.end(), sprim.begin(), sprim.end());
    1012                 :            : 
    1013 [ +  + ][ +  - ]:    1091856 :   if (intsharp > 0 && srcFlag == 0)
    1014                 :            :   {
    1015 [ +  - ][ +  - ]:    1103200 :     std::vector< tk::real > vfmax(nmat, 0.0), vfmin(nmat, 0.0);
    1016                 :            : 
    1017         [ +  - ]:     551600 :     tk::THINCReco(rdof, nmat, e, inpoel, coord, geoElem,
    1018                 :            :       ref_gp, U, P, intInd, matInt, vfmin, vfmax, state);
    1019                 :            :   }
    1020                 :            : 
    1021                 :            :   // physical constraints
    1022         [ +  - ]:    1091856 :   enforcePhysicalConstraints(mat_blk, ncomp, nmat, state);
    1023                 :            : 
    1024                 :    2183712 :   return state;
    1025                 :            : }
    1026                 :            : 
    1027                 :            : void
    1028                 :   93470198 : enforcePhysicalConstraints(
    1029                 :            :   const std::vector< inciter::EOS >& mat_blk,
    1030                 :            :   std::size_t ncomp,
    1031                 :            :   std::size_t nmat,
    1032                 :            :   std::vector< tk::real >& state )
    1033                 :            : // *****************************************************************************
    1034                 :            : //  Enforce physical constraints on state at quadrature point
    1035                 :            : //! \param[in] mat_blk EOS material block
    1036                 :            : //! \param[in] ncomp Number of components in the PDE system
    1037                 :            : //! \param[in] nmat Total number of materials
    1038                 :            : //! \param[in,out] state state at quadrature point
    1039                 :            : // *****************************************************************************
    1040                 :            : {
    1041                 :   93470198 :   auto myPDE = inciter::g_inputdeck.get< tag::pde >();
    1042                 :            : 
    1043                 :            :   // unfortunately have to query PDEType here. alternative will potentially
    1044                 :            :   // require refactor that passes PDEType from DGPDE to this level.
    1045         [ +  + ]:   93470198 :   if (myPDE == inciter::ctr::PDEType::MULTIMAT) {
    1046                 :            :     using inciter::pressureIdx;
    1047                 :            :     using inciter::volfracIdx;
    1048                 :            :     using inciter::densityIdx;
    1049                 :            : 
    1050         [ +  + ]:   74123714 :     for (std::size_t k=0; k<nmat; ++k) {
    1051                 :   51344748 :       state[ncomp+pressureIdx(nmat,k)] = constrain_pressure( mat_blk,
    1052                 :   51344748 :         state[ncomp+pressureIdx(nmat,k)], state[densityIdx(nmat,k)],
    1053                 :   51344748 :         state[volfracIdx(nmat,k)], k );
    1054                 :            :     }
    1055                 :            :   }
    1056                 :            :   else if (myPDE == inciter::ctr::PDEType::MULTISPECIES) {
    1057                 :            :     // TODO: consider clipping temperature here
    1058                 :            :   }
    1059                 :   93470198 : }
    1060                 :            : 
    1061                 :            : void
    1062                 :          0 : safeReco( std::size_t rdof,
    1063                 :            :           std::size_t nmat,
    1064                 :            :           std::size_t el,
    1065                 :            :           int er,
    1066                 :            :           const Fields& U,
    1067                 :            :           std::array< std::vector< real >, 2 >& state )
    1068                 :            : // *****************************************************************************
    1069                 :            : //  Compute safe reconstructions near material interfaces
    1070                 :            : //! \param[in] rdof Total number of reconstructed dofs
    1071                 :            : //! \param[in] nmat Total number of material is PDE system
    1072                 :            : //! \param[in] el Element on the left-side of face
    1073                 :            : //! \param[in] er Element on the right-side of face
    1074                 :            : //! \param[in] U Solution vector at recent time-stage
    1075                 :            : //! \param[in,out] state Second-order reconstructed state, at cell-face, that
    1076                 :            : //!   is being modified for safety
    1077                 :            : //! \details When the consistent limiting is applied, there is a possibility
    1078                 :            : //!   that the material densities and energies violate TVD bounds. This function
    1079                 :            : //!   enforces the TVD bounds locally
    1080                 :            : // *****************************************************************************
    1081                 :            : {
    1082                 :            :   using inciter::densityIdx;
    1083                 :            :   using inciter::energyIdx;
    1084                 :            :   using inciter::densityDofIdx;
    1085                 :            :   using inciter::energyDofIdx;
    1086                 :            : 
    1087 [ -  - ][ -  - ]:          0 :   if (er < 0) Throw("safe limiting cannot be called for boundary cells");
         [ -  - ][ -  - ]
    1088                 :            : 
    1089                 :          0 :   auto eR = static_cast< std::size_t >(er);
    1090                 :            : 
    1091                 :            :   // define a lambda for the safe limiting
    1092                 :          0 :   auto safeLimit = [&]( std::size_t c, real ul, real ur )
    1093                 :            :   {
    1094                 :            :     // find min/max at the face
    1095                 :          0 :     auto uMin = std::min(ul, ur);
    1096                 :          0 :     auto uMax = std::max(ul, ur);
    1097                 :            : 
    1098                 :            :     // left-state limiting
    1099                 :          0 :     state[0][c] = std::min(uMax, std::max(uMin, state[0][c]));
    1100                 :            : 
    1101                 :            :     // right-state limiting
    1102                 :          0 :     state[1][c] = std::min(uMax, std::max(uMin, state[1][c]));
    1103                 :          0 :   };
    1104                 :            : 
    1105         [ -  - ]:          0 :   for (std::size_t k=0; k<nmat; ++k)
    1106                 :            :   {
    1107                 :          0 :     real ul(0.0), ur(0.0);
    1108                 :            : 
    1109                 :            :     // Density
    1110                 :            :     // establish left- and right-hand states
    1111         [ -  - ]:          0 :     ul = U(el, densityDofIdx(nmat, k, rdof, 0));
    1112         [ -  - ]:          0 :     ur = U(eR, densityDofIdx(nmat, k, rdof, 0));
    1113                 :            : 
    1114                 :            :     // limit reconstructed density
    1115         [ -  - ]:          0 :     safeLimit(densityIdx(nmat,k), ul, ur);
    1116                 :            : 
    1117                 :            :     // Energy
    1118                 :            :     // establish left- and right-hand states
    1119         [ -  - ]:          0 :     ul = U(el, energyDofIdx(nmat, k, rdof, 0));
    1120         [ -  - ]:          0 :     ur = U(eR, energyDofIdx(nmat, k, rdof, 0));
    1121                 :            : 
    1122                 :            :     // limit reconstructed energy
    1123         [ -  - ]:          0 :     safeLimit(energyIdx(nmat,k), ul, ur);
    1124                 :            :   }
    1125                 :          0 : }
    1126                 :            : 
    1127                 :            : } // tk::

Generated by: LCOV version 1.14