LCOV - code coverage report
Current view: top level - src/kernels - ConservativeAdvection.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 99 110 90.0 %
Date: 2025-07-17 01:28:37 Functions: 15 18 83.3 %
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             : #include "ConservativeAdvection.h"
      11             : #include "SystemBase.h"
      12             : 
      13             : using namespace libMesh;
      14             : 
      15             : registerMooseObject("MooseApp", ConservativeAdvection);
      16             : registerMooseObject("MooseApp", ADConservativeAdvection);
      17             : 
      18             : template <bool is_ad>
      19             : InputParameters
      20       29115 : ConservativeAdvectionTempl<is_ad>::generalParams()
      21             : {
      22       29115 :   InputParameters params = GenericKernel<is_ad>::validParams();
      23       29115 :   params.addClassDescription("Conservative form of $\\nabla \\cdot \\vec{v} u$ which in its weak "
      24             :                              "form is given by: $(-\\nabla \\psi_i, \\vec{v} u)$.");
      25       29115 :   MooseEnum upwinding_type("none full", "none");
      26       29115 :   params.addParam<MooseEnum>("upwinding_type",
      27             :                              upwinding_type,
      28             :                              "Type of upwinding used.  None: Typically results in overshoots and "
      29             :                              "undershoots, but numerical diffusion is minimized.  Full: Overshoots "
      30             :                              "and undershoots are avoided, but numerical diffusion is large");
      31       29115 :   params.addParam<MaterialPropertyName>("advected_quantity",
      32             :                                         "An optional material property to be advected. If not "
      33             :                                         "supplied, then the variable will be used.");
      34       58230 :   return params;
      35       29115 : }
      36             : 
      37             : template <>
      38             : InputParameters
      39       14767 : ConservativeAdvectionTempl<false>::validParams()
      40             : {
      41       14767 :   InputParameters params = generalParams();
      42       14767 :   params.addCoupledVar("velocity", "Velocity vector");
      43       14767 :   params.deprecateCoupledVar("velocity", "velocity_variable", "12/31/2025");
      44       14767 :   params.addParam<MaterialPropertyName>("velocity_material", "Velocity vector given as a material");
      45       14767 :   return params;
      46           0 : }
      47             : 
      48             : template <>
      49             : InputParameters
      50       14348 : ConservativeAdvectionTempl<true>::validParams()
      51             : {
      52       14348 :   InputParameters params = generalParams();
      53       14348 :   params.addCoupledVar("velocity_variable", "Velocity vector given as a variable");
      54       14348 :   params.addParam<MaterialPropertyName>("velocity", "Velocity vector given as a material");
      55       14348 :   params.deprecateParam("velocity", "velocity_material", "12/31/2025");
      56       14348 :   return params;
      57           0 : }
      58             : 
      59             : template <bool is_ad>
      60         304 : ConservativeAdvectionTempl<is_ad>::ConservativeAdvectionTempl(const InputParameters & parameters)
      61             :   : GenericKernel<is_ad>(parameters),
      62         608 :     _velocity(this->isParamValid("velocity_variable")
      63         655 :                   ? &this->template coupledGenericVectorValue<is_ad>("velocity_variable")
      64         351 :                   : (this->isParamValid("velocity_material")
      65         351 :                          ? &this->template getGenericMaterialProperty<RealVectorValue, is_ad>(
      66             :                                     "velocity_material")
      67          39 :                                 .get()
      68             :                          : nullptr)),
      69         304 :     _adv_quant(
      70         608 :         isParamValid("advected_quantity")
      71         304 :             ? this->template getGenericMaterialProperty<Real, is_ad>("advected_quantity").get()
      72             :             : _u),
      73         304 :     _upwinding(
      74         304 :         this->template getParam<MooseEnum>("upwinding_type").template getEnum<UpwindingType>()),
      75         304 :     _u_nodal(_var.template genericDofValues<is_ad>()),
      76         304 :     _upwind_node(0),
      77         608 :     _dtotal_mass_out(0)
      78             : {
      79         304 :   if (_upwinding != UpwindingType::none && this->isParamValid("advected_quantity"))
      80           0 :     paramError(
      81             :         "advected_quantity",
      82             :         "Upwinding is not compatable with an advected quantity that is not the primary variable.");
      83             : 
      84         600 :   if (!_velocity ||
      85         600 :       (this->isParamValid("velocity_variable") && this->isParamValid("velocity_material")))
      86           8 :     paramError("velocity_variable",
      87             :                "Either velocity_variable or velocity_material must be specified");
      88             : 
      89         296 :   if (this->_has_diag_save_in)
      90           0 :     paramError("diag_save_in",
      91             :                "_local_ke not computed for global AD indexing. Save-in is deprecated anyway. Use "
      92             :                "the tagging system instead.");
      93         296 : }
      94             : 
      95             : template <bool is_ad>
      96             : GenericReal<is_ad>
      97    15400216 : ConservativeAdvectionTempl<is_ad>::negSpeedQp() const
      98             : {
      99    15400216 :   return -_grad_test[_i][_qp] * (*_velocity)[_qp];
     100             : }
     101             : 
     102             : template <bool is_ad>
     103             : GenericReal<is_ad>
     104     2704704 : ConservativeAdvectionTempl<is_ad>::computeQpResidual()
     105             : {
     106             :   // This is the no-upwinded version
     107             :   // It gets called via GenericKernel<is_ad>::computeResidual()
     108     2704704 :   return negSpeedQp() * _adv_quant[_qp];
     109             : }
     110             : 
     111             : template <>
     112             : Real
     113     8352384 : ConservativeAdvectionTempl<false>::computeQpJacobian()
     114             : {
     115             :   // This is the no-upwinded version
     116             :   // It gets called via GenericKernel<false>::computeJacobian()
     117     8352384 :   return negSpeedQp() * _phi[_j][_qp];
     118             : }
     119             : 
     120             : template <>
     121             : Real
     122           0 : ConservativeAdvectionTempl<true>::computeQpJacobian()
     123             : {
     124           0 :   mooseError("Internal error, should never get here when using AD");
     125             :   return 0.0;
     126             : }
     127             : 
     128             : template <bool is_ad>
     129             : void
     130      314480 : ConservativeAdvectionTempl<is_ad>::computeResidual()
     131             : {
     132      314480 :   switch (_upwinding)
     133             :   {
     134      172716 :     case UpwindingType::none:
     135      172716 :       GenericKernel<is_ad>::computeResidual();
     136      172716 :       break;
     137      141764 :     case UpwindingType::full:
     138      141764 :       fullUpwind(JacRes::CALCULATE_RESIDUAL);
     139      141764 :       break;
     140             :   }
     141      314480 : }
     142             : 
     143             : template <bool is_ad>
     144             : void
     145      272942 : ConservativeAdvectionTempl<is_ad>::computeJacobian()
     146             : {
     147      272942 :   switch (_upwinding)
     148             :   {
     149      132312 :     case UpwindingType::none:
     150      132312 :       GenericKernel<is_ad>::computeJacobian();
     151      132312 :       break;
     152      140630 :     case UpwindingType::full:
     153      140630 :       fullUpwind(JacRes::CALCULATE_JACOBIAN);
     154      140630 :       break;
     155             :   }
     156      272942 : }
     157             : 
     158             : template <bool is_ad>
     159             : void
     160      282394 : ConservativeAdvectionTempl<is_ad>::fullUpwind(JacRes res_or_jac)
     161             : {
     162             :   // The number of nodes in the element
     163      282394 :   const unsigned int num_nodes = _test.size();
     164             : 
     165             :   // Even if we are computing the Jacobian we still need to compute the outflow from each node to
     166             :   // see which nodes are upwind and which are downwind
     167      282394 :   _my_local_re.resize(_var.dofIndices().size());
     168             : 
     169      282394 :   if (!is_ad && (res_or_jac == JacRes::CALCULATE_JACOBIAN))
     170      140630 :     prepareMatrixTag(this->_assembly, _var.number(), _var.number());
     171             : 
     172             :   // Compute the outflux from each node and store in _my_local_re
     173             :   // If _my_local_re is positive at the node, mass (or whatever the Variable represents) is flowing
     174             :   // out of the node
     175      282394 :   _upwind_node.resize(num_nodes);
     176     1377794 :   for (_i = 0; _i < num_nodes; ++_i)
     177             :   {
     178     5438528 :     for (_qp = 0; _qp < this->_qrule->n_points(); _qp++)
     179     4343128 :       _my_local_re(_i) += this->_JxW[_qp] * this->_coord[_qp] * negSpeedQp();
     180     1095400 :     _upwind_node[_i] = (MetaPhysicL::raw_value(_my_local_re(_i)) >= 0.0);
     181             :   }
     182             : 
     183             :   // Variables used to ensure mass conservation
     184      282394 :   GenericReal<is_ad> total_mass_out = 0.0;
     185      282394 :   GenericReal<is_ad> total_in = 0.0;
     186      282394 :   if (res_or_jac == JacRes::CALCULATE_JACOBIAN)
     187      140630 :     _dtotal_mass_out.assign(num_nodes, 0.0);
     188             : 
     189     1377794 :   for (const auto n : make_range(num_nodes))
     190             :   {
     191     1095400 :     if (_upwind_node[n])
     192             :     {
     193             :       if constexpr (!is_ad)
     194      547808 :         if (res_or_jac == JacRes::CALCULATE_JACOBIAN)
     195             :         {
     196      271636 :           if (_test.size() == _phi.size())
     197             :             /* u at node=n depends only on the u at node=n, by construction.  For
     198             :              * linear-lagrange variables, this means that Jacobian entries involving the derivative
     199             :              * will only be nonzero for derivatives wrt variable at node=n.  Hence the
     200             :              * (n, n) in the line below.  The above "if" statement catches other variable types
     201             :              * (eg constant monomials)
     202             :              */
     203      271636 :             _local_ke(n, n) += _my_local_re(n);
     204             : 
     205      271636 :           _dtotal_mass_out[n] += _local_ke(n, n);
     206             :         }
     207      547808 :       _my_local_re(n) *= _u_nodal[n];
     208      547808 :       total_mass_out += _my_local_re(n);
     209             :     }
     210             :     else                           // downwind node
     211      547592 :       total_in -= _my_local_re(n); // note the -= means the result is positive
     212             :   }
     213             : 
     214             :   // Conserve mass over all phases by proportioning the total_mass_out mass to the inflow nodes,
     215             :   // weighted by their local_re values
     216     1377794 :   for (const auto n : make_range(num_nodes))
     217     1095400 :     if (!_upwind_node[n]) // downwind node
     218             :     {
     219             :       if constexpr (!is_ad)
     220      547592 :         if (res_or_jac == JacRes::CALCULATE_JACOBIAN)
     221     1339112 :           for (_j = 0; _j < _phi.size(); _j++)
     222     1067584 :             _local_ke(n, _j) += _my_local_re(n) * _dtotal_mass_out[_j] / total_in;
     223      547592 :       _my_local_re(n) *= total_mass_out / total_in;
     224             :     }
     225             : 
     226             :   // Add the result to the residual and jacobian
     227      282394 :   if (res_or_jac == JacRes::CALCULATE_RESIDUAL)
     228             :   {
     229      141764 :     this->addResiduals(this->_assembly, _my_local_re, _var.dofIndices(), _var.scalingFactor());
     230             : 
     231      141764 :     if (this->_has_save_in)
     232             :     {
     233           0 :       Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
     234           0 :       for (const auto & var : this->_save_in)
     235           0 :         var->sys().solution().add_vector(MetaPhysicL::raw_value(_my_local_re), var->dofIndices());
     236           0 :     }
     237             :   }
     238             : 
     239      282394 :   if (res_or_jac == JacRes::CALCULATE_JACOBIAN)
     240             :   {
     241             :     if constexpr (is_ad)
     242           0 :       this->addJacobian(this->_assembly, _my_local_re, _var.dofIndices(), _var.scalingFactor());
     243             :     else
     244      140630 :       accumulateTaggedLocalMatrix();
     245             :   }
     246      282394 : }
     247             : 
     248             : template class ConservativeAdvectionTempl<false>;
     249             : template class ConservativeAdvectionTempl<true>;

Generated by: LCOV version 1.14