LCOV - code coverage report
Current view: top level - src/physics - WCNSLinearFVTwoPhaseMixturePhysics.C (source / functions) Hit Total Coverage
Test: idaholab/moose navier_stokes: #33359 (04c914) with base 7b3324 Lines: 178 223 79.8 %
Date: 2026-07-16 14:31:44 Functions: 8 10 80.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://www.mooseframework.org
       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 "WCNSLinearFVTwoPhaseMixturePhysics.h"
      11             : #include "WCNSFVTwoPhaseMixturePhysics.h"
      12             : #include "WCNSFVFluidHeatTransferPhysics.h"
      13             : #include "WCNSLinearFVFluidHeatTransferPhysics.h"
      14             : #include "WCNSFVFlowPhysics.h"
      15             : 
      16             : registerNavierStokesPhysicsBaseTasks("NavierStokesApp", WCNSLinearFVTwoPhaseMixturePhysics);
      17             : registerWCNSFVScalarTransportBaseTasks("NavierStokesApp", WCNSLinearFVTwoPhaseMixturePhysics);
      18             : registerMooseAction("NavierStokesApp",
      19             :                     WCNSLinearFVTwoPhaseMixturePhysics,
      20             :                     "add_interpolation_method_physics");
      21             : registerMooseAction("NavierStokesApp", WCNSLinearFVTwoPhaseMixturePhysics, "add_material");
      22             : registerMooseAction("NavierStokesApp", WCNSLinearFVTwoPhaseMixturePhysics, "check_integrity");
      23             : 
      24             : InputParameters
      25          17 : WCNSLinearFVTwoPhaseMixturePhysics::validParams()
      26             : {
      27             :   // The parameters are mostly the same being the linear and nonlinear version
      28          17 :   InputParameters params = WCNSLinearFVScalarTransportPhysics::validParams();
      29          17 :   WCNSFVTwoPhaseMixturePhysics::renamePassiveScalarToMixtureParams(params);
      30             :   // The flow physics is obtained from the scalar transport base class
      31             :   // The fluid heat transfer physics is retrieved even if unspecified
      32          34 :   params.addParam<PhysicsName>(
      33             :       "fluid_heat_transfer_physics",
      34             :       "NavierStokesFV",
      35             :       "WCNSLinearFVFluidHeatTransferPhysics generating the fluid energy equation");
      36          17 :   params += WCNSFVTwoPhaseMixturePhysics::commonMixtureParams();
      37          34 :   params.addParamNamesToGroup("fluid_heat_transfer_physics", "Phase change");
      38          17 :   params.addClassDescription("Define the additional terms for a mixture model for the two phase "
      39             :                              "weakly-compressible Navier Stokes equations using the linearized "
      40             :                              "segregated finite volume discretization");
      41             : 
      42             :   // This is added to match a nonlinear test result. If the underlying issue is fixed, remove it
      43          34 :   params.addParam<bool>("add_gravity_term_in_slip_velocity",
      44          34 :                         true,
      45             :                         "Whether to add the gravity term in the slip velocity vector computation");
      46          17 :   return params;
      47           0 : }
      48             : 
      49          17 : WCNSLinearFVTwoPhaseMixturePhysics::WCNSLinearFVTwoPhaseMixturePhysics(
      50          17 :     const InputParameters & parameters)
      51             :   : WCNSLinearFVScalarTransportPhysics(parameters),
      52          17 :     _add_phase_equation(_has_scalar_equation),
      53          17 :     _phase_1_fraction_name(getParam<MooseFunctorName>("phase_1_fraction_name")),
      54          17 :     _phase_2_fraction_name(_passive_scalar_names[0]),
      55          17 :     _phase_1_density(getParam<MooseFunctorName>("phase_1_density_name")),
      56          17 :     _phase_1_viscosity(getParam<MooseFunctorName>("phase_1_viscosity_name")),
      57          17 :     _phase_1_specific_heat(getParam<MooseFunctorName>("phase_1_specific_heat_name")),
      58          17 :     _phase_1_thermal_conductivity(getParam<MooseFunctorName>("phase_1_thermal_conductivity_name")),
      59          17 :     _phase_2_density(getParam<MooseFunctorName>("phase_2_density_name")),
      60          17 :     _phase_2_viscosity(getParam<MooseFunctorName>("phase_2_viscosity_name")),
      61          17 :     _phase_2_specific_heat(getParam<MooseFunctorName>("phase_2_specific_heat_name")),
      62          17 :     _phase_2_thermal_conductivity(getParam<MooseFunctorName>("phase_2_thermal_conductivity_name")),
      63          34 :     _use_external_mixture_properties(getParam<bool>("use_external_mixture_properties")),
      64          34 :     _use_drift_flux(getParam<bool>("add_drift_flux_momentum_terms")),
      65          51 :     _use_advection_slip(getParam<bool>("add_advection_slip_term"))
      66             : {
      67             :   // Check that only one scalar was passed, as we are using vector parameters
      68          17 :   if (_passive_scalar_names.size() > 1)
      69           0 :     paramError("phase_fraction_name", "Only one phase fraction currently supported.");
      70          17 :   if (_passive_scalar_inlet_functors.size() > 1)
      71           0 :     paramError("phase_fraction_inlet_functors", "Only one phase fraction currently supported");
      72             : 
      73             :   // Retrieve the fluid energy equation if it exists
      74          34 :   if (isParamValid("fluid_heat_transfer_physics"))
      75             :   {
      76          34 :     _fluid_energy_physics = getCoupledPhysics<WCNSLinearFVFluidHeatTransferPhysics>(
      77             :         getParam<PhysicsName>("fluid_heat_transfer_physics"), true);
      78             :     // Check for a missing parameter / do not support isolated physics for now
      79          34 :     if (!_fluid_energy_physics &&
      80          34 :         !getCoupledPhysics<const WCNSLinearFVFluidHeatTransferPhysics>(true).empty())
      81           0 :       paramError(
      82             :           "fluid_heat_transfer_physics",
      83             :           "We currently do not support creating both a phase transport equation and fluid heat "
      84             :           "transfer physics that are not coupled together");
      85          17 :     if (_fluid_energy_physics && _fluid_energy_physics->hasEnergyEquation())
      86           0 :       _has_energy_equation = true;
      87             :     else
      88          17 :       _has_energy_equation = false;
      89             :   }
      90             :   else
      91             :   {
      92           0 :     _has_energy_equation = false;
      93           0 :     _fluid_energy_physics = nullptr;
      94             :   }
      95             : 
      96             :   // Check that the mixture parameters are correctly in use in the other physics
      97          17 :   if (_has_energy_equation)
      98             :   {
      99           0 :     if (_fluid_energy_physics->densityName() != "rho_mixture")
     100           0 :       mooseError(
     101             :           "Density name for Physics '", _fluid_energy_physics->name(), "' should be 'rho_mixture'");
     102           0 :     if (_fluid_energy_physics->getSpecificHeatName() != "cp_mixture")
     103           0 :       mooseError("Specific heat name for Physics '",
     104             :                  _fluid_energy_physics->name(),
     105             :                  "' should be 'cp_mixture'");
     106             :   }
     107          17 :   if (_flow_equations_physics)
     108          17 :     if (_flow_equations_physics->densityName() != "rho_mixture")
     109           0 :       mooseError("Density name for Physics ,",
     110             :                  _flow_equations_physics->name(),
     111             :                  "' should be 'rho_mixture'");
     112             : 
     113          17 :   if (_verbose)
     114             :   {
     115           0 :     if (_flow_equations_physics)
     116           0 :       mooseInfoRepeated("Coupled to fluid flow physics " + _flow_equations_physics->name());
     117           0 :     if (_has_energy_equation)
     118           0 :       mooseInfoRepeated("Coupled to fluid heat transfer physics " + _fluid_energy_physics->name());
     119             :   }
     120             : 
     121             :   // Parameter checking
     122             :   // The two models are not consistent
     123          50 :   if (isParamSetByUser("alpha_exchange") && getParam<bool>("add_phase_change_energy_term"))
     124           0 :     paramError("alpha_exchange",
     125             :                "A phase exchange coefficient cannot be specified if the phase change is handled "
     126             :                "with a phase change heat loss model");
     127          17 :   if (_phase_1_fraction_name == _phase_2_fraction_name)
     128           0 :     paramError("phase_1_fraction_name",
     129             :                "First phase fraction name should be different from second phase fraction name");
     130          17 :   if (_use_drift_flux && _use_advection_slip)
     131           0 :     paramError("add_drift_flux_momentum_terms",
     132             :                "Drift flux model cannot be used at the same time as the advection slip model");
     133          34 :   if (!getParam<bool>("add_drift_flux_momentum_terms"))
     134          18 :     errorDependentParameter("add_drift_flux_momentum_terms", "true", {"density_interp_method"});
     135          34 :   if (!getParam<bool>("use_dispersed_phase_drag_model"))
     136           0 :     errorDependentParameter("use_dispersed_phase_drag_model", "true", {"particle_diameter"});
     137          17 : }
     138             : 
     139             : void
     140          17 : WCNSLinearFVTwoPhaseMixturePhysics::checkIntegrity() const
     141             : {
     142          17 :   if (!_flow_equations_physics)
     143           0 :     mooseError("Expected a flow physics");
     144             : 
     145             :   // Check the mesh for unsupported sknewness + buoyancy
     146          17 :   if (_flow_equations_physics->gravityVector().norm() > 0)
     147             :   {
     148             :     const auto tol = 1e-2;
     149           1 :     if (_problem->mesh().allFaceInfo().empty())
     150           0 :       _problem->mesh().setupFiniteVolumeMeshData();
     151           2 :     for (const auto & fi : _problem->mesh().allFaceInfo())
     152             :     {
     153           2 :       if (fi.skewnessCorrectionVector().norm() > tol * fi.dCNMag())
     154           1 :         mooseError("Face with centroid ",
     155             :                    fi.faceCentroid(),
     156             :                    " requires skewness correction. We currently do not support mixture flow with "
     157             :                    "buoyancy and mesh skewness. Please contact a MOOSE or Navier Stokes module "
     158             :                    "developer if you require this.");
     159             :     }
     160             :   }
     161          16 : }
     162             : 
     163             : void
     164          17 : WCNSLinearFVTwoPhaseMixturePhysics::addFVKernels()
     165             : {
     166          17 :   WCNSLinearFVScalarTransportPhysics::addFVKernels();
     167             : 
     168          51 :   if (_add_phase_equation && isParamSetByUser("alpha_exchange"))
     169           8 :     addPhaseInterfaceTerm();
     170             : 
     171          17 :   if (_fluid_energy_physics && _fluid_energy_physics->hasEnergyEquation() &&
     172          17 :       getParam<bool>("add_phase_change_energy_term"))
     173           0 :     addPhaseChangeEnergySource();
     174             : 
     175          17 :   if (_flow_equations_physics && _flow_equations_physics->hasFlowEquations() && _use_drift_flux)
     176           8 :     addPhaseDriftFluxTerm();
     177          17 :   if (_flow_equations_physics && _flow_equations_physics->hasFlowEquations() && _use_advection_slip)
     178           0 :     addAdvectionSlipTerm();
     179          17 : }
     180             : 
     181             : void
     182          33 : WCNSLinearFVTwoPhaseMixturePhysics::setSlipVelocityParams(InputParameters & params) const
     183             : {
     184          66 :   params.set<MooseFunctorName>("u_slip") = "vel_slip_x";
     185          33 :   if (dimension() >= 2)
     186          66 :     params.set<MooseFunctorName>("v_slip") = "vel_slip_y";
     187          33 :   if (dimension() >= 3)
     188           0 :     params.set<MooseFunctorName>("w_slip") = "vel_slip_z";
     189          33 : }
     190             : 
     191             : void
     192           8 : WCNSLinearFVTwoPhaseMixturePhysics::addPhaseInterfaceTerm()
     193             : {
     194             :   // Recreate the phase interface term from existing kernels
     195             :   {
     196           8 :     auto params = getFactory().getValidParams("LinearFVReaction");
     197           8 :     assignBlocks(params, _blocks);
     198          16 :     params.set<LinearVariableName>("variable") = _phase_2_fraction_name;
     199          16 :     params.set<MooseFunctorName>("coeff") = getParam<MooseFunctorName>(NS::alpha_exchange);
     200          24 :     getProblem().addLinearFVKernel(
     201           8 :         "LinearFVReaction", prefix() + "phase_interface_reaction", params);
     202           8 :   }
     203             :   {
     204           8 :     auto params = getFactory().getValidParams("LinearFVSource");
     205           8 :     assignBlocks(params, _blocks);
     206          16 :     params.set<LinearVariableName>("variable") = _phase_2_fraction_name;
     207          16 :     params.set<MooseFunctorName>("source_density") = _phase_1_fraction_name;
     208          16 :     params.set<MooseFunctorName>("scaling_factor") = getParam<MooseFunctorName>(NS::alpha_exchange);
     209          24 :     getProblem().addLinearFVKernel("LinearFVSource", prefix() + "phase_interface_source", params);
     210           8 :   }
     211           8 : }
     212             : 
     213             : void
     214           0 : WCNSLinearFVTwoPhaseMixturePhysics::addPhaseChangeEnergySource()
     215             : {
     216           0 :   mooseError("Phase change energy source not implemented at this time for linear finite volume");
     217             : }
     218             : 
     219             : void
     220           8 : WCNSLinearFVTwoPhaseMixturePhysics::addPhaseDriftFluxTerm()
     221             : {
     222           8 :   const std::vector<std::string> components = {"x", "y", "z"};
     223          32 :   for (const auto dim : make_range(dimension()))
     224             :   {
     225             :     const auto object_type = "LinearWCNSFV2PMomentumDriftFlux";
     226          16 :     auto params = getFactory().getValidParams(object_type);
     227          16 :     assignBlocks(params, _blocks);
     228          32 :     params.set<LinearVariableName>("variable") = _flow_equations_physics->getVelocityNames()[dim];
     229          16 :     setSlipVelocityParams(params);
     230          16 :     params.set<MooseFunctorName>("rho_d") = _phase_2_density;
     231          32 :     params.set<MooseFunctorName>("fraction_dispersed") = _phase_2_fraction_name;
     232          16 :     params.set<MooseEnum>("momentum_component") = components[dim];
     233          48 :     params.set<MooseEnum>("density_interp_method") = getParam<MooseEnum>("density_interp_method");
     234          32 :     params.set<UserObjectName>("rhie_chow_user_object") = _flow_equations_physics->rhieChowUOName();
     235          48 :     getProblem().addLinearFVKernel(object_type, prefix() + "drift_flux_" + components[dim], params);
     236          16 :   }
     237           8 : }
     238             : 
     239             : void
     240           0 : WCNSLinearFVTwoPhaseMixturePhysics::addAdvectionSlipTerm()
     241             : {
     242           0 :   mooseError("Phase advection slip not implemented at this time for linear finite volume");
     243             : }
     244             : 
     245             : void
     246          17 : WCNSLinearFVTwoPhaseMixturePhysics::addMaterials()
     247             : {
     248             :   // Add the phase fraction variable, for output purposes mostly
     249          17 :   if (!getProblem().hasFunctor(_phase_1_fraction_name, /*thread_id=*/0))
     250             :   {
     251          17 :     auto params = getFactory().getValidParams("ParsedFunctorMaterial");
     252          17 :     assignBlocks(params, _blocks);
     253          34 :     params.set<std::string>("expression") = "1 - " + _phase_2_fraction_name;
     254          51 :     params.set<std::vector<std::string>>("functor_names") = {_phase_2_fraction_name};
     255          17 :     params.set<std::string>("property_name") = _phase_1_fraction_name;
     256          51 :     params.set<std::vector<std::string>>("output_properties") = {_phase_1_fraction_name};
     257          51 :     params.set<std::vector<OutputName>>("outputs") = {"all"};
     258          68 :     getProblem().addMaterial("ParsedFunctorMaterial", prefix() + "phase_1_fraction", params);
     259             : 
     260             :     // One of the phase fraction should exist though (either as a variable or set by a
     261             :     // NSLiquidFractionAux)
     262          17 :     if (!getProblem().hasFunctor(_phase_2_fraction_name, /*thread_id=*/0))
     263           0 :       paramError("Phase 2 fraction should be defined as a variable or auxiliary variable");
     264          17 :   }
     265          17 :   if (!getProblem().hasFunctor(_phase_2_fraction_name, /*thread_id=*/0))
     266             :   {
     267           0 :     auto params = getFactory().getValidParams("ParsedFunctorMaterial");
     268           0 :     assignBlocks(params, _blocks);
     269           0 :     params.set<std::string>("expression") = "1 - " + _phase_1_fraction_name;
     270           0 :     params.set<std::vector<std::string>>("functor_names") = {_phase_1_fraction_name};
     271           0 :     params.set<std::string>("property_name") = _phase_2_fraction_name;
     272           0 :     params.set<std::vector<std::string>>("output_properties") = {_phase_2_fraction_name};
     273           0 :     params.set<std::vector<OutputName>>("outputs") = {"all"};
     274           0 :     getProblem().addMaterial("ParsedFunctorMaterial", prefix() + "phase_2_fraction", params);
     275           0 :   }
     276             : 
     277             :   // Compute mixture properties
     278          17 :   if (!_use_external_mixture_properties)
     279             :   {
     280          17 :     auto params = getFactory().getValidParams("WCNSLinearFVMixtureFunctorMaterial");
     281          17 :     assignBlocks(params, _blocks);
     282          34 :     params.set<std::vector<MooseFunctorName>>("prop_names") = {
     283         119 :         "rho_mixture", "mu_mixture", "cp_mixture", "k_mixture"};
     284             :     // The phase_1 and phase_2 assignments are only local to this object.
     285             :     // We use the phase 2 variable to save a functor evaluation as we expect
     286             :     // the phase 2 variable to be a nonlinear variable in the phase transport equation
     287          34 :     params.set<std::vector<MooseFunctorName>>("phase_2_names") = {_phase_1_density,
     288             :                                                                   _phase_1_viscosity,
     289             :                                                                   _phase_1_specific_heat,
     290         119 :                                                                   _phase_1_thermal_conductivity};
     291          34 :     params.set<std::vector<MooseFunctorName>>("phase_1_names") = {_phase_2_density,
     292             :                                                                   _phase_2_viscosity,
     293             :                                                                   _phase_2_specific_heat,
     294         119 :                                                                   _phase_2_thermal_conductivity};
     295          17 :     params.set<MooseFunctorName>("phase_1_fraction") = _phase_2_fraction_name;
     296          34 :     if (getParam<bool>("output_all_properties"))
     297          51 :       params.set<std::vector<OutputName>>("outputs") = {"all"};
     298          17 :     params.set<bool>("limit_phase_fraction") = true;
     299          51 :     getProblem().addMaterial(
     300          17 :         "WCNSLinearFVMixtureFunctorMaterial", prefix() + "mixture_material", params);
     301          17 :   }
     302             : 
     303             :   // Compute slip terms as functors, used by the drift flux kernels
     304          17 :   if (_use_advection_slip || _use_drift_flux || _add_phase_equation)
     305             :   {
     306             :     mooseAssert(_flow_equations_physics, "We must have coupled to this");
     307          17 :     const std::vector<std::string> vel_components = {"u", "v", "w"};
     308          17 :     const std::vector<std::string> components = {"x", "y", "z"};
     309          68 :     for (const auto dim : make_range(dimension()))
     310             :     {
     311          34 :       auto params = getFactory().getValidParams("WCNSFV2PSlipVelocityFunctorMaterial");
     312          34 :       assignBlocks(params, _blocks);
     313         136 :       params.set<MooseFunctorName>("slip_velocity_name") = "vel_slip_" + components[dim];
     314          34 :       params.set<MooseEnum>("momentum_component") = components[dim];
     315         136 :       for (const auto j : make_range(dimension()))
     316          68 :         params.set<std::vector<VariableName>>(vel_components[j]) = {
     317         204 :             _flow_equations_physics->getVelocityNames()[j]};
     318          34 :       params.set<MooseFunctorName>(NS::density) = _phase_1_density;
     319          34 :       params.set<MooseFunctorName>(NS::mu) = "mu_mixture";
     320          34 :       params.set<MooseFunctorName>("rho_d") = _phase_2_density;
     321          68 :       if (getParam<bool>("add_gravity_term_in_slip_velocity"))
     322          34 :         params.set<RealVectorValue>("gravity") = _flow_equations_physics->gravityVector();
     323          68 :       if (isParamValid("slip_linear_friction_name"))
     324          32 :         params.set<MooseFunctorName>("linear_coef_name") =
     325          32 :             getParam<MooseFunctorName>("slip_linear_friction_name");
     326          36 :       else if (getParam<bool>("use_dispersed_phase_drag_model"))
     327          36 :         params.set<MooseFunctorName>("linear_coef_name") = "Darcy_coefficient";
     328           0 :       else if (_flow_equations_physics)
     329             :       {
     330           0 :         if (!_flow_equations_physics->getLinearFrictionCoefName().empty())
     331           0 :           params.set<MooseFunctorName>("linear_coef_name") =
     332           0 :               _flow_equations_physics->getLinearFrictionCoefName();
     333             :         else
     334           0 :           params.set<MooseFunctorName>("linear_coef_name") = "0";
     335             :       }
     336             :       else
     337           0 :         paramError("slip_linear_friction_name",
     338             :                    "WCNSFV2PSlipVelocityFunctorMaterial created by this Physics required a scalar "
     339             :                    "field linear friction factor.");
     340          68 :       params.set<MooseFunctorName>("particle_diameter") =
     341          34 :           getParam<MooseFunctorName>("particle_diameter");
     342          68 :       if (getParam<bool>("output_all_properties"))
     343             :       {
     344          34 :         if (!isTransient())
     345          48 :           params.set<std::vector<OutputName>>("outputs") = {"all"};
     346             :         else
     347          36 :           paramInfo("output_all_properties",
     348             :                     "Slip velocity functor material output currently unsupported in Physics "
     349             :                     "in transient conditions.");
     350             :       }
     351         102 :       getProblem().addMaterial(
     352          34 :           "WCNSFV2PSlipVelocityFunctorMaterial", prefix() + "slip_" + components[dim], params);
     353          34 :     }
     354          17 :   }
     355             : 
     356             :   // Add a default drag model for a dispersed phase
     357          34 :   if (getParam<bool>("use_dispersed_phase_drag_model"))
     358             :   {
     359          17 :     const std::vector<std::string> vel_components = {"u", "v", "w"};
     360             : 
     361          17 :     auto params = getFactory().getValidParams("NSFVDispersePhaseDragFunctorMaterial");
     362          17 :     assignBlocks(params, _blocks);
     363          34 :     params.set<MooseFunctorName>("drag_coef_name") = "Darcy_coefficient";
     364          68 :     for (const auto j : make_range(dimension()))
     365          34 :       params.set<MooseFunctorName>(vel_components[j]) = {
     366          68 :           _flow_equations_physics->getVelocityNames()[j]};
     367          34 :     params.set<MooseFunctorName>(NS::density) = "rho_mixture";
     368          17 :     params.set<MooseFunctorName>(NS::mu) = "mu_mixture";
     369          34 :     params.set<MooseFunctorName>("particle_diameter") =
     370          17 :         getParam<MooseFunctorName>("particle_diameter");
     371          34 :     if (getParam<bool>("output_all_properties"))
     372          51 :       params.set<std::vector<OutputName>>("outputs") = {"all"};
     373          51 :     getProblem().addMaterial(
     374          17 :         "NSFVDispersePhaseDragFunctorMaterial", prefix() + "dispersed_drag", params);
     375          17 :   }
     376          51 : }

Generated by: LCOV version 1.14