Quinoa all test code coverage report
Current view: top level - PDE - Reconstruction.cpp (source / functions) Hit Total Coverage
Commit: -128-NOTFOUND Lines: 212 374 56.7 %
Date: 2025-05-30 09:21:53 Functions: 7 12 58.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 151 408 37.0 %

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

Generated by: LCOV version 1.14