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

Generated by: LCOV version 1.14