LCOV - code coverage report
Current view: top level - src/materials - NavierStokesMaterial.C (source / functions) Hit Total Coverage
Test: idaholab/moose navier_stokes: 9fc4b0 Lines: 141 144 97.9 %
Date: 2025-08-14 10:14:56 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : // Navier-Stokes includes
      11             : #include "NavierStokesMaterial.h"
      12             : #include "NS.h"
      13             : 
      14             : // FluidProperties includes
      15             : #include "IdealGasFluidProperties.h"
      16             : 
      17             : // MOOSE includes
      18             : #include "Assembly.h"
      19             : #include "MooseMesh.h"
      20             : 
      21             : #include "libmesh/quadrature.h"
      22             : 
      23             : namespace nms = NS;
      24             : 
      25             : InputParameters
      26          85 : NavierStokesMaterial::validParams()
      27             : {
      28          85 :   InputParameters params = Material::validParams();
      29             : 
      30          85 :   params.addClassDescription(
      31             :       "This is the base class of all materials should use if you are trying to "
      32             :       "use the Navier-Stokes Kernels.");
      33          85 :   params.addRequiredCoupledVar(nms::velocity_x, "x-velocity");
      34          85 :   params.addCoupledVar(nms::velocity_y, "y-velocity"); // only required in >= 2D
      35          85 :   params.addCoupledVar(nms::velocity_z, "z-velocity"); // only required in 3D
      36             : 
      37          85 :   params.addRequiredCoupledVar(nms::temperature, "temperature");
      38          85 :   params.addRequiredCoupledVar(nms::specific_total_enthalpy, "specific total enthalpy");
      39             : 
      40          85 :   params.addRequiredCoupledVar(nms::density, "density");
      41          85 :   params.addRequiredCoupledVar(nms::momentum_x, "x-momentum");
      42          85 :   params.addCoupledVar(nms::momentum_y, "y-momentum"); // only required in >= 2D
      43          85 :   params.addCoupledVar(nms::momentum_z, "z-momentum"); // only required in 3D
      44          85 :   params.addRequiredCoupledVar(nms::total_energy_density, "energy");
      45         170 :   params.addRequiredParam<UserObjectName>("fluid_properties",
      46             :                                           "The name of the user object for fluid properties");
      47          85 :   return params;
      48           0 : }
      49             : 
      50          66 : NavierStokesMaterial::NavierStokesMaterial(const InputParameters & parameters)
      51             :   : Material(parameters),
      52         132 :     _mesh_dimension(_mesh.dimension()),
      53          66 :     _grad_u(coupledGradient(nms::velocity_x)),
      54          66 :     _grad_v(_mesh_dimension >= 2 ? coupledGradient(nms::velocity_y) : _grad_zero),
      55          66 :     _grad_w(_mesh_dimension == 3 ? coupledGradient(nms::velocity_z) : _grad_zero),
      56             : 
      57          66 :     _viscous_stress_tensor(declareProperty<RealTensorValue>("viscous_stress_tensor")),
      58          66 :     _thermal_conductivity(declareProperty<Real>("thermal_conductivity")),
      59             : 
      60             :     // Declared here but _not_ calculated here
      61             :     // (See e.g. derived class, bighorn/include/materials/FluidTC1.h)
      62          66 :     _dynamic_viscosity(declareProperty<Real>("dynamic_viscosity")),
      63             : 
      64             :     // The momentum components of the inviscid flux Jacobians.
      65          66 :     _calA(declareProperty<std::vector<RealTensorValue>>("calA")),
      66             : 
      67             :     // "Velocity column" matrices
      68          66 :     _calC(declareProperty<std::vector<RealTensorValue>>("calC")),
      69             : 
      70             :     // Energy equation inviscid flux matrices, "cal E_{kl}" in the notes.
      71          66 :     _calE(declareProperty<std::vector<std::vector<RealTensorValue>>>("calE")),
      72          66 :     _vel_grads({&_grad_u, &_grad_v, &_grad_w}),
      73             : 
      74             :     // Coupled solution values needed for computing SUPG stabilization terms
      75          66 :     _u_vel(coupledValue(nms::velocity_x)),
      76          66 :     _v_vel(_mesh.dimension() >= 2 ? coupledValue(nms::velocity_y) : _zero),
      77          66 :     _w_vel(_mesh.dimension() == 3 ? coupledValue(nms::velocity_z) : _zero),
      78             : 
      79          66 :     _temperature(coupledValue(nms::temperature)),
      80          66 :     _specific_total_enthalpy(coupledValue(nms::specific_total_enthalpy)),
      81             : 
      82             :     // Coupled solution values
      83          66 :     _rho(coupledValue(nms::density)),
      84          66 :     _rho_u(coupledValue(nms::momentum_x)),
      85          66 :     _rho_v(_mesh.dimension() >= 2 ? coupledValue(nms::momentum_y) : _zero),
      86          66 :     _rho_w(_mesh.dimension() == 3 ? coupledValue(nms::momentum_z) : _zero),
      87          66 :     _rho_et(coupledValue(nms::total_energy_density)),
      88             : 
      89             :     // Time derivative values
      90          66 :     _drho_dt(coupledDot(nms::density)),
      91          66 :     _drhou_dt(coupledDot(nms::momentum_x)),
      92          66 :     _drhov_dt(_mesh.dimension() >= 2 ? coupledDot(nms::momentum_y) : _zero),
      93          66 :     _drhow_dt(_mesh.dimension() == 3 ? coupledDot(nms::momentum_z) : _zero),
      94          66 :     _drhoE_dt(coupledDot(nms::total_energy_density)),
      95             : 
      96             :     // Gradients
      97          66 :     _grad_rho(coupledGradient(nms::density)),
      98          66 :     _grad_rho_u(coupledGradient(nms::momentum_x)),
      99          66 :     _grad_rho_v(_mesh.dimension() >= 2 ? coupledGradient(nms::momentum_y) : _grad_zero),
     100          66 :     _grad_rho_w(_mesh.dimension() == 3 ? coupledGradient(nms::momentum_z) : _grad_zero),
     101          66 :     _grad_rho_et(coupledGradient(nms::total_energy_density)),
     102             : 
     103             :     // Material properties for stabilization
     104          66 :     _hsupg(declareProperty<Real>("hsupg")),
     105          66 :     _tauc(declareProperty<Real>("tauc")),
     106          66 :     _taum(declareProperty<Real>("taum")),
     107          66 :     _taue(declareProperty<Real>("taue")),
     108          66 :     _strong_residuals(declareProperty<std::vector<Real>>("strong_residuals")),
     109         132 :     _fp(getUserObject<IdealGasFluidProperties>("fluid_properties"))
     110             : {
     111          66 : }
     112             : 
     113             : /**
     114             :  * Must be called _after_ the child class computes dynamic_viscosity.
     115             :  */
     116             : void
     117      526848 : NavierStokesMaterial::computeProperties()
     118             : {
     119     2370816 :   for (unsigned int qp = 0; qp < _qrule->n_points(); ++qp)
     120             :   {
     121             :     /******* Viscous Stress Tensor *******/
     122             :     // Technically... this _is_ the transpose (since we are loading these by rows)
     123             :     // But it doesn't matter....
     124     1843968 :     RealTensorValue grad_outer_u(_grad_u[qp], _grad_v[qp], _grad_w[qp]);
     125             : 
     126     1843968 :     grad_outer_u += grad_outer_u.transpose();
     127             : 
     128             :     Real div_vel = 0.0;
     129     7375872 :     for (unsigned int i = 0; i < 3; ++i)
     130     5531904 :       div_vel += (*_vel_grads[i])[qp](i);
     131             : 
     132             :     // Add diagonal terms
     133     7375872 :     for (unsigned int i = 0; i < 3; ++i)
     134     5531904 :       grad_outer_u(i, i) -= 2.0 / 3.0 * div_vel;
     135             : 
     136     1843968 :     grad_outer_u *= _dynamic_viscosity[qp];
     137             : 
     138     1843968 :     _viscous_stress_tensor[qp] = grad_outer_u;
     139             : 
     140             :     // Tabulated values of thermal conductivity vs. Temperature for air (k increases slightly with
     141             :     // T):
     142             :     // T (K)    k (W/m-K)
     143             :     // 273      0.0243
     144             :     // 373      0.0314
     145             :     // 473      0.0386
     146             :     // 573      0.0454
     147             :     // 673      0.0515
     148             : 
     149             :     // Pr = (mu * cp) / k  ==>  k = (mu * cp) / Pr = (mu * gamma * cv) / Pr.
     150             :     // TODO: We are using a fixed value of the Prandtl number which is
     151             :     // valid for air, it may or may not depend on temperature?  Since
     152             :     // this is a property of the fluid, it could possibly be moved to
     153             :     // the FluidProperties module...
     154             :     const Real Pr = 0.71;
     155     1843968 :     _thermal_conductivity[qp] = (_dynamic_viscosity[qp] * _fp.cp()) / Pr;
     156             : 
     157             :     // Compute stabilization parameters:
     158             : 
     159             :     // .) Compute SUPG element length scale.
     160     1843968 :     computeHSUPG(qp);
     161             :     // Moose::out << "_hsupg[" << qp << "]=" << _hsupg[qp] << std::endl;
     162             : 
     163             :     // .) Compute SUPG parameter values.  (Must call this after computeHSUPG())
     164     1843968 :     computeTau(qp);
     165             :     // Moose::out << "_tauc[" << qp << "]=" << _tauc[qp] << ", ";
     166             :     // Moose::out << "_taum[" << qp << "]=" << _taum[qp] << ", ";
     167             :     // Moose::out << "_taue[" << qp << "]=" << _taue[qp] << std::endl;
     168             : 
     169             :     // .) Compute strong residual values.
     170     1843968 :     computeStrongResiduals(qp);
     171             :     // Moose::out << "_strong_residuals[" << qp << "]=";
     172             :     // for (unsigned i=0; i<_strong_residuals[qp].size(); ++i)
     173             :     //   Moose::out << _strong_residuals[qp][i] << " ";
     174             :     // Moose::out << std::endl;
     175             :   }
     176      526848 : }
     177             : 
     178             : void
     179     1843968 : NavierStokesMaterial::computeHSUPG(unsigned int qp)
     180             : {
     181             :   // // Grab reference to linear Lagrange finite element object pointer,
     182             :   // // currently this is always a linear Lagrange element, so this might need to
     183             :   // // be generalized if we start working with higher-order elements...
     184             :   // FEBase*& fe(_assembly.getFE(FEType(), _current_elem->dim()));
     185             :   //
     186             :   // // Grab references to FE object's mapping data from the _subproblem's FE object
     187             :   // const std::vector<Real> & dxidx(fe->get_dxidx());
     188             :   // const std::vector<Real> & dxidy(fe->get_dxidy());
     189             :   // const std::vector<Real> & dxidz(fe->get_dxidz());
     190             :   // const std::vector<Real> & detadx(fe->get_detadx());
     191             :   // const std::vector<Real> & detady(fe->get_detady());
     192             :   // const std::vector<Real> & detadz(fe->get_detadz());
     193             :   // const std::vector<Real> & dzetadx(fe->get_dzetadx()); // Empty in 2D
     194             :   // const std::vector<Real> & dzetady(fe->get_dzetady()); // Empty in 2D
     195             :   // const std::vector<Real> & dzetadz(fe->get_dzetadz()); // Empty in 2D
     196             :   //
     197             :   // // Bounds checking on element data
     198             :   // mooseAssert(qp < dxidx.size(), "Insufficient data in dxidx array!");
     199             :   // mooseAssert(qp < dxidy.size(), "Insufficient data in dxidy array!");
     200             :   // mooseAssert(qp < dxidz.size(), "Insufficient data in dxidz array!");
     201             :   //
     202             :   // mooseAssert(qp < detadx.size(), "Insufficient data in detadx array!");
     203             :   // mooseAssert(qp < detady.size(), "Insufficient data in detady array!");
     204             :   // mooseAssert(qp < detadz.size(), "Insufficient data in detadz array!");
     205             :   //
     206             :   // if (_mesh_dimension == 3)
     207             :   // {
     208             :   //   mooseAssert(qp < dzetadx.size(), "Insufficient data in dzetadx array!");
     209             :   //   mooseAssert(qp < dzetady.size(), "Insufficient data in dzetady array!");
     210             :   //   mooseAssert(qp < dzetadz.size(), "Insufficient data in dzetadz array!");
     211             :   // }
     212             :   //
     213             :   // // The velocity vector at this quadrature point.
     214             :   // RealVectorValue U(_u_vel[qp],_v_vel[qp],_w_vel[qp]);
     215             :   //
     216             :   // // Pull out element inverse map values at the current qp into a little dense matrix
     217             :   // Real dxi_dx[3][3] = {{0.,0.,0.}, {0.,0.,0.}, {0.,0.,0.}};
     218             :   //
     219             :   // dxi_dx[0][0] = dxidx[qp];  dxi_dx[0][1] = dxidy[qp];
     220             :   // dxi_dx[1][0] = detadx[qp]; dxi_dx[1][1] = detady[qp];
     221             :   //
     222             :   // // OK to access third entries on 2D elements if LIBMESH_DIM==3, though they
     223             :   // // may be zero...
     224             :   // if (LIBMESH_DIM == 3)
     225             :   // {
     226             :   //   /**/             /**/               dxi_dx[0][2] = dxidz[qp];
     227             :   //   /**/             /**/               dxi_dx[1][2] = detadz[qp];
     228             :   // }
     229             :   //
     230             :   // // The last row of entries available only for 3D elements.
     231             :   // if (_mesh_dimension == 3)
     232             :   // {
     233             :   //   dxi_dx[2][0] = dzetadx[qp];   dxi_dx[2][1] = dzetady[qp];   dxi_dx[2][2] = dzetadz[qp];
     234             :   // }
     235             :   //
     236             :   // // Construct the g_ij = d(xi_k)/d(x_j) * d(xi_k)/d(x_i) matrix
     237             :   // // from Ben and Bova's paper by summing over k...
     238             :   // Real g[3][3] = {{0.,0.,0.}, {0.,0.,0.}, {0.,0.,0.}};
     239             :   // for (unsigned int i = 0; i < 3; ++i)
     240             :   //   for (unsigned int j = 0; j < 3; ++j)
     241             :   //     for (unsigned int k = 0; k < 3; ++k)
     242             :   //       g[i][j] += dxi_dx[k][j] * dxi_dx[k][i];
     243             :   //
     244             :   // // Compute the denominator of the h_supg term: U * (g) * U
     245             :   // Real denom = 0.;
     246             :   // for (unsigned int i = 0; i < 3; ++i)
     247             :   //   for (unsigned int j = 0; j < 3; ++j)
     248             :   //     denom += U(j) * g[i][j] * U(i);
     249             :   //
     250             :   // // Compute h_supg.  Some notes:
     251             :   // // .) The 2 coefficient in this term should be a 1 if we are using tets/triangles.
     252             :   // // .) The denominator will be identically zero only if the velocity
     253             :   // //    is identically zero, in which case we can't divide by it.
     254             :   // if (denom != 0.0)
     255             :   //   _hsupg[qp] = 2.* sqrt( U.norm_sq() / denom );
     256             :   // else
     257             :   //   _hsupg[qp] = 0.;
     258             : 
     259             :   // Simple (and fast) implementation: Just use hmin for the element!
     260     1843968 :   _hsupg[qp] = _current_elem->hmin();
     261     1843968 : }
     262             : 
     263             : void
     264     1843968 : NavierStokesMaterial::computeTau(unsigned int qp)
     265             : {
     266             :   Real velmag =
     267     1843968 :       std::sqrt(_u_vel[qp] * _u_vel[qp] + _v_vel[qp] * _v_vel[qp] + _w_vel[qp] * _w_vel[qp]);
     268             : 
     269             :   // Moose::out << "velmag=" << velmag << std::endl;
     270             : 
     271             :   // Make sure temperature >= 0 before trying to take sqrt
     272             :   // if (_temperature[qp] < 0.)
     273             :   // {
     274             :   //   Moose::err << "Negative temperature "
     275             :   //             << _temperature[qp]
     276             :   //             << " found at quadrature point "
     277             :   //             << qp
     278             :   //             << ", element "
     279             :   //             << _current_elem->id()
     280             :   //             << std::endl;
     281             :   //   mooseError("Can't continue, would be nice to throw an exception here?");
     282             :   // }
     283             : 
     284             :   // The speed of sound for an ideal gas, sqrt(gamma * R * T).  Not needed unless
     285             :   // we want to use a form of Tau that requires it.
     286             :   // Real soundspeed = _fp.c_from_v_e(_specific_volume[_qp], _internal_energy[_qp]);
     287             : 
     288             :   // If velmag == 0, then _hsupg should be zero as well.  Then tau
     289             :   // will have only the time-derivative contribution (or zero, if we
     290             :   // are not including dt terms in our taus!)  Note that using the
     291             :   // time derivative contribution in this way assumes we are solving
     292             :   // unsteady, and guarantees *some* stabilization is added even when
     293             :   // u -> 0 in certain regions of the flow.
     294     1843968 :   if (velmag == 0.)
     295             :   {
     296             :     // 1.) Tau without dt terms
     297             :     // _tauc[qp] = 0.;
     298             :     // _taum[qp] = 0.;
     299             :     // _taue[qp] = 0.;
     300             : 
     301             :     // 2.) Tau *with* dt terms
     302           0 :     _tauc[qp] = _taum[qp] = _taue[qp] = 0.5 * _dt;
     303             :   }
     304             :   else
     305             :   {
     306             :     // The element length parameter, squared
     307     1843968 :     Real h2 = _hsupg[qp] * _hsupg[qp];
     308             : 
     309             :     // The viscosity-based term
     310     1843968 :     Real visc_term = _dynamic_viscosity[qp] / _rho[qp] / h2;
     311             : 
     312             :     // The thermal conductivity-based term, cp = gamma * cv
     313     1843968 :     Real k_term = _thermal_conductivity[qp] / _rho[qp] / _fp.cp() / h2;
     314             : 
     315             :     // 1a.) Standard compressible flow tau.  Does not account for low Mach number
     316             :     // limit.
     317             :     //    _tauc[qp] = _hsupg[qp] / (velmag + soundspeed);
     318             : 
     319             :     // 1b.) Inspired by Hauke, the sum of the compressible and incompressible tauc.
     320             :     //    _tauc[qp] =
     321             :     //      _hsupg[qp] / (velmag + soundspeed) +
     322             :     //      _hsupg[qp] / (velmag);
     323             : 
     324             :     // 1c.) From Wong 2001.  This tau is O(M^2) for small M.  At small M,
     325             :     // tauc dominates the inverse square sums and basically makes
     326             :     // taum=taue=tauc.  However, all my flows occur at low Mach numbers,
     327             :     // so there would basically never be any stabilization...
     328             :     // _tauc[qp] = (_hsupg[qp] * velmag) / (velmag*velmag + soundspeed*soundspeed);
     329             : 
     330             :     // For use with option "1",
     331             :     // (tau_c)^{-2}
     332             :     //    Real taucm2 = 1./_tauc[qp]/_tauc[qp];
     333             :     //    _taum[qp] = 1. / std::sqrt(taucm2 + visc_term*visc_term);
     334             :     //    _taue[qp] = 1. / std::sqrt(taucm2 + k_term*k_term);
     335             : 
     336             :     // 2.) Tau with timestep dependence (guarantees stabilization even
     337             :     // in zero-velocity limit) incorporated via the "r-switch" method,
     338             :     // with r=2.
     339     1843968 :     Real sqrt_term = 4. / _dt / _dt + velmag * velmag / h2;
     340             : 
     341             :     // For use with option "2", i.e. the option that uses dt in the definition of tau
     342     1843968 :     _tauc[qp] = 1. / std::sqrt(sqrt_term);
     343     1843968 :     _taum[qp] = 1. / std::sqrt(sqrt_term + visc_term * visc_term);
     344     1843968 :     _taue[qp] = 1. / std::sqrt(sqrt_term + k_term * k_term);
     345             :   }
     346             : 
     347             :   // Debugging
     348             :   // Moose::out << "_tauc[" << qp << "]=" << _tauc[qp] << std::endl;
     349             :   // Moose::out << "_hsupg[" << qp << "]=" << _hsupg[qp] << std::endl;
     350             :   // Moose::out << "velmag[" << qp << "]=" << velmag << std::endl;
     351     1843968 : }
     352             : 
     353             : void
     354     1843968 : NavierStokesMaterial::computeStrongResiduals(unsigned int qp)
     355             : {
     356             :   // Create storage at this qp for the strong residuals of all the equations.
     357             :   // In 2D, the value for the z-velocity equation will just be zero.
     358     1843968 :   _strong_residuals[qp].resize(5);
     359             : 
     360             :   // The timestep is stored in the Problem object, which can be accessed through
     361             :   // the parent pointer of the SubProblem.  Don't need this if we are not
     362             :   // approximating time derivatives ourselves.
     363             :   // Real dt = _subproblem.parent()->dt();
     364             :   // Moose::out << "dt=" << dt << std::endl;
     365             : 
     366             :   // Vector object for the velocity
     367     1843968 :   RealVectorValue vel(_u_vel[qp], _v_vel[qp], _w_vel[qp]);
     368             : 
     369             :   // A VectorValue object containing all zeros.  Makes it easier to
     370             :   // construct type tensor objects
     371             :   RealVectorValue zero(0., 0., 0.);
     372             : 
     373             :   // Velocity vector magnitude squared
     374             :   Real velmag2 = vel.norm_sq();
     375             : 
     376             :   // Debugging: How large are the time derivative parts of the strong residuals?
     377             :   //  Moose::out << "drho_dt=" << _drho_dt
     378             :   //            << ", drhou_dt=" << _drhou_dt
     379             :   //            << ", drhov_dt=" << _drhov_dt
     380             :   //            << ", drhow_dt=" << _drhow_dt
     381             :   //            << ", drhoE_dt=" << _drhoE_dt
     382             :   //            << std::endl;
     383             : 
     384             :   // Momentum divergence
     385     1843968 :   Real divU = _grad_rho_u[qp](0) + _grad_rho_v[qp](1) + _grad_rho_w[qp](2);
     386             : 
     387             :   // Enough space to hold three space dimensions of velocity components at each qp,
     388             :   // regardless of what dimension we are actually running in.
     389     1843968 :   _calC[qp].resize(3);
     390             : 
     391             :   // Explicitly zero the calC
     392     7375872 :   for (unsigned int i = 0; i < 3; ++i)
     393     5531904 :     _calC[qp][i].zero();
     394             : 
     395             :   // x-column matrix
     396     1843968 :   _calC[qp][0](0, 0) = _u_vel[qp];
     397     1843968 :   _calC[qp][0](1, 0) = _v_vel[qp];
     398     1843968 :   _calC[qp][0](2, 0) = _w_vel[qp];
     399             : 
     400             :   // y-column matrix
     401     1843968 :   _calC[qp][1](0, 1) = _u_vel[qp];
     402     1843968 :   _calC[qp][1](1, 1) = _v_vel[qp];
     403     1843968 :   _calC[qp][1](2, 1) = _w_vel[qp];
     404             : 
     405             :   // z-column matrix (this assumes LIBMESH_DIM==3!)
     406     1843968 :   _calC[qp][2](0, 2) = _u_vel[qp];
     407     1843968 :   _calC[qp][2](1, 2) = _v_vel[qp];
     408     1843968 :   _calC[qp][2](2, 2) = _w_vel[qp];
     409             : 
     410             :   // The matrix S can be computed from any of the calC via calC_1*calC_1^T
     411     1843968 :   RealTensorValue calS = _calC[qp][0] * _calC[qp][0].transpose();
     412             : 
     413             :   // Enough space to hold five (=n_sd + 2) 3*3 calA matrices at this qp, regarless of dimension
     414     1843968 :   _calA[qp].resize(5);
     415             : 
     416             :   // 0.) _calA_0 = diag( (gam - 1)/2*|u|^2 ) - S
     417     1843968 :   _calA[qp][0].zero(); // zero this calA entry
     418     1843968 :   _calA[qp][0](0, 0) = _calA[qp][0](1, 1) = _calA[qp][0](2, 2) =
     419     1843968 :       0.5 * (_fp.gamma() - 1.0) * velmag2; // set diag. entries
     420             :   _calA[qp][0] -= calS;
     421             : 
     422     7375872 :   for (unsigned int m = 1; m <= 3; ++m)
     423             :   {
     424             :     // Use m_local when indexing into matrices and vectors
     425     5531904 :     unsigned int m_local = m - 1;
     426             : 
     427             :     // For m=1,2,3, calA_m = C_m + C_m^T + diag( (1.-gam)*u_m )
     428     5531904 :     _calA[qp][m].zero(); // zero this calA entry
     429     5531904 :     _calA[qp][m](0, 0) = _calA[qp][m](1, 1) = _calA[qp][m](2, 2) =
     430     5531904 :         (1. - _fp.gamma()) * vel(m_local);          // set diag. entries
     431     5531904 :     _calA[qp][m] += _calC[qp][m_local];             // Note: use m_local for indexing into _calC!
     432     5531904 :     _calA[qp][m] += _calC[qp][m_local].transpose(); // Note: use m_local for indexing into _calC!
     433             :   }
     434             : 
     435             :   // 4.) calA_4 = diag(gam - 1)
     436     1843968 :   _calA[qp][4].zero(); // zero this calA entry
     437     1843968 :   _calA[qp][4](0, 0) = _calA[qp][4](1, 1) = _calA[qp][4](2, 2) = (_fp.gamma() - 1.0);
     438             : 
     439             :   // Enough space to hold the 3*5 "cal E" matrices which comprise the inviscid flux term
     440             :   // of the energy equation.  See notes for additional details
     441     1843968 :   _calE[qp].resize(3); // Three rows, 5 entries in each row
     442             : 
     443     7375872 :   for (unsigned int k = 0; k < 3; ++k)
     444             :   {
     445             :     // Make enough room to store all 5 E matrices for this k
     446     5531904 :     _calE[qp][k].resize(5);
     447             : 
     448             :     // Store and reuse the velocity column transpose matrix for the
     449             :     // current value of k.
     450     5531904 :     RealTensorValue Ck_T = _calC[qp][k].transpose();
     451             : 
     452             :     // E_{k0} (density gradient term)
     453     5531904 :     _calE[qp][k][0].zero();
     454     5531904 :     _calE[qp][k][0] = (0.5 * (_fp.gamma() - 1.0) * velmag2 - _specific_total_enthalpy[qp]) * Ck_T;
     455             : 
     456    22127616 :     for (unsigned int m = 1; m <= 3; ++m)
     457             :     {
     458             :       // Use m_local when indexing into matrices and vectors
     459    16595712 :       unsigned int m_local = m - 1;
     460             : 
     461             :       // E_{km} (momentum gradient terms)
     462    16595712 :       _calE[qp][k][m].zero();
     463    16595712 :       _calE[qp][k][m](k, m_local) = _specific_total_enthalpy[qp];  // H * D_{km}
     464    33191424 :       _calE[qp][k][m] += (1. - _fp.gamma()) * vel(m_local) * Ck_T; // (1-gam) * u_m * C_k^T
     465             :     }
     466             : 
     467             :     // E_{k4} (energy gradient term)
     468     5531904 :     _calE[qp][k][4].zero();
     469     5531904 :     _calE[qp][k][4] = _fp.gamma() * Ck_T;
     470             :   }
     471             : 
     472             :   // Compute the sum over ell of: A_ell grad(U_ell), store in DenseVector or Gradient object?
     473             :   // The gradient object might be more useful, since we are multiplying by VariableGradient
     474             :   // (which is a MooseArray of RealGradients) objects?
     475     1843968 :   RealVectorValue mom_resid = _calA[qp][0] * _grad_rho[qp] + _calA[qp][1] * _grad_rho_u[qp] +
     476     1843968 :                               _calA[qp][2] * _grad_rho_v[qp] + _calA[qp][3] * _grad_rho_w[qp] +
     477     1843968 :                               _calA[qp][4] * _grad_rho_et[qp];
     478             : 
     479             :   // No matrices/vectors for the energy residual strong form... just write it out like
     480             :   // the mass equation residual.  See "Momentum SUPG terms prop. to energy residual"
     481             :   // section of the notes.
     482             :   Real energy_resid =
     483     1843968 :       (0.5 * (_fp.gamma() - 1.0) * velmag2 - _specific_total_enthalpy[qp]) * (vel * _grad_rho[qp]) +
     484     3687936 :       _specific_total_enthalpy[qp] * divU +
     485     1843968 :       (1. - _fp.gamma()) * (vel(0) * (vel * _grad_rho_u[qp]) + vel(1) * (vel * _grad_rho_v[qp]) +
     486     1843968 :                             vel(2) * (vel * _grad_rho_w[qp])) +
     487     1843968 :       _fp.gamma() * (vel * _grad_rho_et[qp]);
     488             : 
     489             :   // Now for the actual residual values...
     490             : 
     491             :   // The density strong-residual
     492     1843968 :   _strong_residuals[qp][0] = _drho_dt[qp] + divU;
     493             : 
     494             :   // The x-momentum strong-residual, viscous terms neglected.
     495             :   // TODO: If we want to add viscous contributions back in, should this kernel
     496             :   // not inherit from NSViscousFluxBase so it can get tau values?  This would
     497             :   // also involve shape function second derivative values.
     498     1843968 :   _strong_residuals[qp][1] = _drhou_dt[qp] + mom_resid(0);
     499             : 
     500             :   // The y-momentum strong residual, viscous terms neglected.
     501     1843968 :   _strong_residuals[qp][2] = _drhov_dt[qp] + mom_resid(1);
     502             : 
     503             :   // The z-momentum strong residual, viscous terms neglected.
     504     1843968 :   if (_mesh_dimension == 3)
     505           0 :     _strong_residuals[qp][3] = _drhow_dt[qp] + mom_resid(2);
     506             :   else
     507     1843968 :     _strong_residuals[qp][3] = 0.;
     508             : 
     509             :   // The energy equation strong residual
     510     1843968 :   _strong_residuals[qp][4] = _drhoE_dt[qp] + energy_resid;
     511     1843968 : }

Generated by: LCOV version 1.14