LCOV - code coverage report
Current view: top level - src/physics - WCNSLinearFVTwoPhaseMixturePhysics.C (source / functions) Hit Total Coverage
Test: idaholab/moose navier_stokes: 9fc4b0 Lines: 178 224 79.5 %
Date: 2025-08-14 10:14:56 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          40 : WCNSLinearFVTwoPhaseMixturePhysics::validParams()
      23             : {
      24             :   // The parameters are mostly the same being the linear and nonlinear version
      25          40 :   InputParameters params = WCNSLinearFVScalarTransportPhysics::validParams();
      26          40 :   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          80 :   params.addParam<PhysicsName>(
      30             :       "fluid_heat_transfer_physics",
      31             :       "NavierStokesFV",
      32             :       "WCNSLinearFVFluidHeatTransferPhysics generating the fluid energy equation");
      33          40 :   params += WCNSFVTwoPhaseMixturePhysics::commonMixtureParams();
      34          80 :   params.addParamNamesToGroup("fluid_heat_transfer_physics", "Phase change");
      35          40 :   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          80 :   params.addParam<bool>("add_gravity_term_in_slip_velocity",
      41          80 :                         true,
      42             :                         "Whether to add the gravity term in the slip velocity vector computation");
      43          40 :   return params;
      44           0 : }
      45             : 
      46          40 : WCNSLinearFVTwoPhaseMixturePhysics::WCNSLinearFVTwoPhaseMixturePhysics(
      47          40 :     const InputParameters & parameters)
      48             :   : WCNSLinearFVScalarTransportPhysics(parameters),
      49          40 :     _add_phase_equation(_has_scalar_equation),
      50          40 :     _phase_1_fraction_name(getParam<MooseFunctorName>("phase_1_fraction_name")),
      51          40 :     _phase_2_fraction_name(_passive_scalar_names[0]),
      52          40 :     _phase_1_density(getParam<MooseFunctorName>("phase_1_density_name")),
      53          40 :     _phase_1_viscosity(getParam<MooseFunctorName>("phase_1_viscosity_name")),
      54          40 :     _phase_1_specific_heat(getParam<MooseFunctorName>("phase_1_specific_heat_name")),
      55          40 :     _phase_1_thermal_conductivity(getParam<MooseFunctorName>("phase_1_thermal_conductivity_name")),
      56          40 :     _phase_2_density(getParam<MooseFunctorName>("phase_2_density_name")),
      57          40 :     _phase_2_viscosity(getParam<MooseFunctorName>("phase_2_viscosity_name")),
      58          40 :     _phase_2_specific_heat(getParam<MooseFunctorName>("phase_2_specific_heat_name")),
      59          40 :     _phase_2_thermal_conductivity(getParam<MooseFunctorName>("phase_2_thermal_conductivity_name")),
      60          80 :     _use_external_mixture_properties(getParam<bool>("use_external_mixture_properties")),
      61          80 :     _use_drift_flux(getParam<bool>("add_drift_flux_momentum_terms")),
      62         120 :     _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          40 :   if (_passive_scalar_names.size() > 1)
      66           0 :     paramError("phase_fraction_name", "Only one phase fraction currently supported.");
      67          40 :   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          80 :   if (isParamValid("fluid_heat_transfer_physics"))
      72             :   {
      73          80 :     _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          80 :     if (!_fluid_energy_physics &&
      77          80 :         !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          40 :     if (_fluid_energy_physics && _fluid_energy_physics->hasEnergyEquation())
      83           0 :       _has_energy_equation = true;
      84             :     else
      85          40 :       _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          40 :   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          40 :   if (_flow_equations_physics)
     105          40 :     if (_flow_equations_physics->densityName() != "rho_mixture")
     106           0 :       mooseError("Density name for Physics ,",
     107           0 :                  _flow_equations_physics->name(),
     108             :                  "' should be 'rho_mixture'");
     109             : 
     110          40 :   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         118 :   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          40 :   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          40 :   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          80 :   if (!getParam<bool>("add_drift_flux_momentum_terms"))
     131          42 :     errorDependentParameter("add_drift_flux_momentum_terms", "true", {"density_interp_method"});
     132          80 :   if (!getParam<bool>("use_dispersed_phase_drag_model"))
     133           0 :     errorDependentParameter("use_dispersed_phase_drag_model", "true", {"particle_diameter"});
     134          40 : }
     135             : 
     136             : void
     137          40 : WCNSLinearFVTwoPhaseMixturePhysics::checkIntegrity() const
     138             : {
     139          40 :   if (!_flow_equations_physics)
     140           0 :     mooseError("Expected a flow physics");
     141             : 
     142             :   // Check the mesh for unsupported sknewness + buoyancy
     143          40 :   if (_flow_equations_physics->gravityVector().norm() > 0)
     144             :   {
     145             :     const auto tol = 1e-2;
     146           2 :     if (_problem->mesh().allFaceInfo().empty())
     147           0 :       _problem->mesh().setupFiniteVolumeMeshData();
     148           4 :     for (const auto & fi : _problem->mesh().allFaceInfo())
     149             :     {
     150           4 :       if (fi.skewnessCorrectionVector().norm() > tol * fi.dCNMag())
     151           2 :         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          38 : }
     159             : 
     160             : void
     161          40 : WCNSLinearFVTwoPhaseMixturePhysics::addFVKernels()
     162             : {
     163          40 :   WCNSLinearFVScalarTransportPhysics::addFVKernels();
     164             : 
     165         120 :   if (_add_phase_equation && isParamSetByUser("alpha_exchange"))
     166          19 :     addPhaseInterfaceTerm();
     167             : 
     168          40 :   if (_fluid_energy_physics && _fluid_energy_physics->hasEnergyEquation() &&
     169          40 :       getParam<bool>("add_phase_change_energy_term"))
     170           0 :     addPhaseChangeEnergySource();
     171             : 
     172          40 :   if (_flow_equations_physics && _flow_equations_physics->hasFlowEquations() && _use_drift_flux)
     173          19 :     addPhaseDriftFluxTerm();
     174          40 :   if (_flow_equations_physics && _flow_equations_physics->hasFlowEquations() && _use_advection_slip)
     175           0 :     addAdvectionSlipTerm();
     176          40 : }
     177             : 
     178             : void
     179          78 : WCNSLinearFVTwoPhaseMixturePhysics::setSlipVelocityParams(InputParameters & params) const
     180             : {
     181         156 :   params.set<MooseFunctorName>("u_slip") = "vel_slip_x";
     182          78 :   if (dimension() >= 2)
     183         156 :     params.set<MooseFunctorName>("v_slip") = "vel_slip_y";
     184          78 :   if (dimension() >= 3)
     185           0 :     params.set<MooseFunctorName>("w_slip") = "vel_slip_z";
     186          78 : }
     187             : 
     188             : void
     189          19 : WCNSLinearFVTwoPhaseMixturePhysics::addPhaseInterfaceTerm()
     190             : {
     191             :   // Recreate the phase interface term from existing kernels
     192             :   {
     193          19 :     auto params = getFactory().getValidParams("LinearFVReaction");
     194          19 :     assignBlocks(params, _blocks);
     195          38 :     params.set<LinearVariableName>("variable") = _phase_2_fraction_name;
     196          38 :     params.set<MooseFunctorName>("coeff") = getParam<MooseFunctorName>(NS::alpha_exchange);
     197          38 :     getProblem().addLinearFVKernel(
     198          19 :         "LinearFVReaction", prefix() + "phase_interface_reaction", params);
     199          19 :   }
     200             :   {
     201          19 :     auto params = getFactory().getValidParams("LinearFVSource");
     202          19 :     assignBlocks(params, _blocks);
     203          38 :     params.set<LinearVariableName>("variable") = _phase_2_fraction_name;
     204          38 :     params.set<MooseFunctorName>("source_density") = _phase_1_fraction_name;
     205          38 :     params.set<MooseFunctorName>("scaling_factor") = getParam<MooseFunctorName>(NS::alpha_exchange);
     206          57 :     getProblem().addLinearFVKernel("LinearFVSource", prefix() + "phase_interface_source", params);
     207          19 :   }
     208          19 : }
     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          19 : WCNSLinearFVTwoPhaseMixturePhysics::addPhaseDriftFluxTerm()
     218             : {
     219          19 :   const std::vector<std::string> components = {"x", "y", "z"};
     220          76 :   for (const auto dim : make_range(dimension()))
     221             :   {
     222             :     const auto object_type = "LinearWCNSFV2PMomentumDriftFlux";
     223          38 :     auto params = getFactory().getValidParams(object_type);
     224          38 :     assignBlocks(params, _blocks);
     225          76 :     params.set<LinearVariableName>("variable") = _flow_equations_physics->getVelocityNames()[dim];
     226          38 :     setSlipVelocityParams(params);
     227          38 :     params.set<MooseFunctorName>("rho_d") = _phase_2_density;
     228          76 :     params.set<MooseFunctorName>("fraction_dispersed") = _phase_2_fraction_name;
     229          38 :     params.set<MooseEnum>("momentum_component") = components[dim];
     230         114 :     params.set<MooseEnum>("density_interp_method") = getParam<MooseEnum>("density_interp_method");
     231          76 :     params.set<UserObjectName>("rhie_chow_user_object") = _flow_equations_physics->rhieChowUOName();
     232         114 :     getProblem().addLinearFVKernel(object_type, prefix() + "drift_flux_" + components[dim], params);
     233          38 :   }
     234          19 : }
     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          40 : WCNSLinearFVTwoPhaseMixturePhysics::addMaterials()
     244             : {
     245             :   // Add the phase fraction variable, for output purposes mostly
     246          40 :   if (!getProblem().hasFunctor(_phase_1_fraction_name, /*thread_id=*/0))
     247             :   {
     248          40 :     auto params = getFactory().getValidParams("ParsedFunctorMaterial");
     249          40 :     assignBlocks(params, _blocks);
     250          80 :     params.set<std::string>("expression") = "1 - " + _phase_2_fraction_name;
     251         120 :     params.set<std::vector<std::string>>("functor_names") = {_phase_2_fraction_name};
     252          40 :     params.set<std::string>("property_name") = _phase_1_fraction_name;
     253         120 :     params.set<std::vector<std::string>>("output_properties") = {_phase_1_fraction_name};
     254         120 :     params.set<std::vector<OutputName>>("outputs") = {"all"};
     255         160 :     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          40 :     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          40 :   }
     262          40 :   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          40 :   if (!_use_external_mixture_properties)
     276             :   {
     277          40 :     auto params = getFactory().getValidParams("WCNSLinearFVMixtureFunctorMaterial");
     278          40 :     assignBlocks(params, _blocks);
     279          80 :     params.set<std::vector<MooseFunctorName>>("prop_names") = {
     280         280 :         "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          80 :     params.set<std::vector<MooseFunctorName>>("phase_2_names") = {_phase_1_density,
     285             :                                                                   _phase_1_viscosity,
     286             :                                                                   _phase_1_specific_heat,
     287         280 :                                                                   _phase_1_thermal_conductivity};
     288          80 :     params.set<std::vector<MooseFunctorName>>("phase_1_names") = {_phase_2_density,
     289             :                                                                   _phase_2_viscosity,
     290             :                                                                   _phase_2_specific_heat,
     291         280 :                                                                   _phase_2_thermal_conductivity};
     292          40 :     params.set<MooseFunctorName>("phase_1_fraction") = _phase_2_fraction_name;
     293          80 :     if (getParam<bool>("output_all_properties"))
     294         120 :       params.set<std::vector<OutputName>>("outputs") = {"all"};
     295          40 :     params.set<bool>("limit_phase_fraction") = true;
     296          80 :     getProblem().addMaterial(
     297          40 :         "WCNSLinearFVMixtureFunctorMaterial", prefix() + "mixture_material", params);
     298          40 :   }
     299             : 
     300             :   // Compute slip terms as functors, used by the drift flux kernels
     301          40 :   if (_use_advection_slip || _use_drift_flux || _add_phase_equation)
     302             :   {
     303             :     mooseAssert(_flow_equations_physics, "We must have coupled to this");
     304          40 :     const std::vector<std::string> vel_components = {"u", "v", "w"};
     305          40 :     const std::vector<std::string> components = {"x", "y", "z"};
     306         160 :     for (const auto dim : make_range(dimension()))
     307             :     {
     308          80 :       auto params = getFactory().getValidParams("WCNSFV2PSlipVelocityFunctorMaterial");
     309          80 :       assignBlocks(params, _blocks);
     310         320 :       params.set<MooseFunctorName>("slip_velocity_name") = "vel_slip_" + components[dim];
     311          80 :       params.set<MooseEnum>("momentum_component") = components[dim];
     312         320 :       for (const auto j : make_range(dimension()))
     313         160 :         params.set<std::vector<VariableName>>(vel_components[j]) = {
     314         480 :             _flow_equations_physics->getVelocityNames()[j]};
     315          80 :       params.set<MooseFunctorName>(NS::density) = _phase_1_density;
     316          80 :       params.set<MooseFunctorName>(NS::mu) = "mu_mixture";
     317          80 :       params.set<MooseFunctorName>("rho_d") = _phase_2_density;
     318         160 :       if (getParam<bool>("add_gravity_term_in_slip_velocity"))
     319          80 :         params.set<RealVectorValue>("gravity") = _flow_equations_physics->gravityVector();
     320         160 :       if (isParamValid("slip_linear_friction_name"))
     321          76 :         params.set<MooseFunctorName>("linear_coef_name") =
     322          76 :             getParam<MooseFunctorName>("slip_linear_friction_name");
     323          84 :       else if (getParam<bool>("use_dispersed_phase_drag_model"))
     324          84 :         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         160 :       params.set<MooseFunctorName>("particle_diameter") =
     338          80 :           getParam<MooseFunctorName>("particle_diameter");
     339         160 :       if (getParam<bool>("output_all_properties"))
     340             :       {
     341          80 :         if (!isTransient())
     342         114 :           params.set<std::vector<OutputName>>("outputs") = {"all"};
     343             :         else
     344          84 :           paramInfo("output_all_properties",
     345             :                     "Slip velocity functor material output currently unsupported in Physics "
     346             :                     "in transient conditions.");
     347             :       }
     348         240 :       getProblem().addMaterial(
     349         160 :           "WCNSFV2PSlipVelocityFunctorMaterial", prefix() + "slip_" + components[dim], params);
     350          80 :     }
     351          40 :   }
     352             : 
     353             :   // Add a default drag model for a dispersed phase
     354          80 :   if (getParam<bool>("use_dispersed_phase_drag_model"))
     355             :   {
     356          40 :     const std::vector<std::string> vel_components = {"u", "v", "w"};
     357             : 
     358          40 :     auto params = getFactory().getValidParams("NSFVDispersePhaseDragFunctorMaterial");
     359          40 :     assignBlocks(params, _blocks);
     360          80 :     params.set<MooseFunctorName>("drag_coef_name") = "Darcy_coefficient";
     361         160 :     for (const auto j : make_range(dimension()))
     362          80 :       params.set<MooseFunctorName>(vel_components[j]) = {
     363         160 :           _flow_equations_physics->getVelocityNames()[j]};
     364          80 :     params.set<MooseFunctorName>(NS::density) = "rho_mixture";
     365          40 :     params.set<MooseFunctorName>(NS::mu) = "mu_mixture";
     366          80 :     params.set<MooseFunctorName>("particle_diameter") =
     367          40 :         getParam<MooseFunctorName>("particle_diameter");
     368          80 :     if (getParam<bool>("output_all_properties"))
     369         120 :       params.set<std::vector<OutputName>>("outputs") = {"all"};
     370          80 :     getProblem().addMaterial(
     371          40 :         "NSFVDispersePhaseDragFunctorMaterial", prefix() + "dispersed_drag", params);
     372          40 :   }
     373         120 : }

Generated by: LCOV version 1.14