https://mooseframework.inl.gov
Loading...
Searching...
No Matches
IncompressibleMomentumSPBase.C
Go to the documentation of this file.
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
11
12#include "FunctorInterface.h"
13#include "ScalarCoupleable.h"
15#include "PhysicalConstants.h"
16
17template <bool is_ad>
20{
23 params.addClassDescription("Base class for path-integrated incompressible momentum kernels.");
24 params.addCoupledVar("temperatures",
25 {},
26 "Fluid temperature in each segment of this component. Takes a "
27 "list of scalar variable names");
28 params.addParam<bool>(
29 "is_implicit",
30 false,
31 "Whether an explicit (previous value calculation) or implicit (current value) is used");
32 params.addRequiredParam<MooseFunctorName>("reference_pressure", "system reference pressure [Pa]");
33 params.addRequiredParam<UserObjectName>("fp", "The name of the user object for fluid properties");
34 params.addParam<std::vector<MooseFunctorName>>(
35 "areas",
36 std::vector<MooseFunctorName>({}),
37 "Component flow areas per segment. Takes a vector of functors.");
38 params.addParam<std::vector<MooseFunctorName>>(
39 "perimeters",
40 std::vector<MooseFunctorName>({}),
41 "Component flow perimeters per segment. Takes a vector of functors.");
42 params.addParam<std::vector<MooseFunctorName>>(
43 "lengths",
44 std::vector<MooseFunctorName>({}),
45 "Component flow lengths per segment. Takes a vector of functors.");
46 params.addParam<std::vector<MooseFunctorName>>(
47 "alphas",
48 std::vector<MooseFunctorName>({}),
49 "Component flow angles per segment with respect to horizontal (-pi/2 downward to pi/2 "
50 "upward). Takes a vector of functors.");
51 params.addParam<std::vector<MooseFunctorName>>(
52 "forms_losses",
53 std::vector<MooseFunctorName>({}),
54 "Forms loss coefficients per segment. Takes a vector of functors.");
55 params.addParam<std::vector<MooseFunctorName>>(
56 "pump_pressures",
57 std::vector<MooseFunctorName>({}),
58 "Pump pressure gains per segment [Pa]. Takes a vector of functors.");
59 params.addParam<std::vector<MooseFunctorName>>(
60 "roughnesses",
61 std::vector<MooseFunctorName>({}),
62 "Component wall roughnesses per segment [m]. Takes a vector of functors.");
63 params.addParam<MooseFunctorName>(
64 "g", PhysicalConstants::acceleration_of_gravity, "Gravitational acceleration [m/s]");
65
66 return params;
67}
68
69template <bool is_ad>
71 const InputParameters & parameters)
72 : Base(parameters),
73 FunctorInterface(this),
74 _n_temps(ScalarCoupleable::coupledScalarComponents("temperatures")),
75 _T(_n_temps),
76 _is_implicit(this->template getParam<bool>("is_implicit")),
77 _Pref(this->template getFunctor<GenericReal<is_ad>>("reference_pressure")),
78 _fp(this->template getUserObject<SinglePhaseFluidProperties>("fp")),
79 _n_segments(this->template getParam<std::vector<MooseFunctorName>>("areas").size()),
80 _areas(this->template getParam<std::vector<MooseFunctorName>>("areas").size()),
81 _perimeters(this->template getParam<std::vector<MooseFunctorName>>("perimeters").size()),
82 _lengths(this->template getParam<std::vector<MooseFunctorName>>("lengths").size()),
83 _alphas(this->template getParam<std::vector<MooseFunctorName>>("alphas").size()),
84 _forms_losses(this->template getParam<std::vector<MooseFunctorName>>("forms_losses").size()),
85 _dPps(this->template getParam<std::vector<MooseFunctorName>>("pump_pressures").size()),
86 _roughnesses(this->template getParam<std::vector<MooseFunctorName>>("roughnesses").size()),
87 _gravity(this->template getFunctor<GenericReal<is_ad>>("g"))
88{
89 const auto & area_names = MooseBase::getParam<std::vector<MooseFunctorName>>("areas");
90 const auto & perimeter_names = MooseBase::getParam<std::vector<MooseFunctorName>>("perimeters");
91 const auto & length_names = MooseBase::getParam<std::vector<MooseFunctorName>>("lengths");
92 const auto & alpha_names = MooseBase::getParam<std::vector<MooseFunctorName>>("alphas");
93 const auto & forms_loss_names =
94 MooseBase::getParam<std::vector<MooseFunctorName>>("forms_losses");
95 const auto & dPp_names = MooseBase::getParam<std::vector<MooseFunctorName>>("pump_pressures");
96 const auto & roughness_names = MooseBase::getParam<std::vector<MooseFunctorName>>("roughnesses");
97 if (_n_segments != area_names.size() || _n_segments != perimeter_names.size() ||
98 _n_segments != length_names.size() || _n_segments != alpha_names.size() ||
99 _n_segments != forms_loss_names.size() || _n_segments != dPp_names.size() ||
100 _n_segments != roughness_names.size() || _n_segments != _n_temps)
101 {
103 "Must provide consistent number of segments for each parameter! Including temperatures!");
104 }
105 for (const auto j : make_range(_n_segments))
106 {
107 _T[j] = &(ScalarCoupleable::coupledScalarValue("temperatures", j));
108 _areas[j] = &(this->template getFunctor<GenericReal<is_ad>>(area_names[j]));
109 _perimeters[j] = &(this->template getFunctor<GenericReal<is_ad>>(perimeter_names[j]));
110 _lengths[j] = &(this->template getFunctor<GenericReal<is_ad>>(length_names[j]));
111 _alphas[j] = &(this->template getFunctor<GenericReal<is_ad>>(alpha_names[j]));
112 _forms_losses[j] = &(this->template getFunctor<GenericReal<is_ad>>(forms_loss_names[j]));
113 _dPps[j] = &(this->template getFunctor<GenericReal<is_ad>>(dPp_names[j]));
114 _roughnesses[j] = &(this->template getFunctor<GenericReal<is_ad>>(roughness_names[j]));
115 }
116}
117
118template <bool is_ad>
121{
122 GenericReal<is_ad> momentum_residual = 0;
123 const Moose::ElemArg qp = Moose::ElemArg();
124 const int i = 0;
125 const auto state = _is_implicit ? Moose::currentState() : Moose::oldState();
126 // start by getting global fluid properties
127 const auto Tave = ((*(_T[0]))[i] + (*(_T[_n_temps - 1]))[i]) / 2;
128 const auto mu = _fp.mu_from_p_T(_Pref(qp, state), Tave);
129 const auto rhog = _fp.rho_from_p_T(_Pref(qp, state), Tave);
130 // Global rescale factor so the mass flow rate's transient term has a unit coefficient,
131 // matching the coefficient of ODETimeDerivative kernel: the path's lumped L_over_A_sum is
132 // Sum_j(length_j / area_j), so the whole equation is divided through by that single sum.
133 GenericReal<is_ad> L_over_A_sum = 0;
134 for (const auto j : make_range(_n_segments))
135 L_over_A_sum += (*(_lengths[j]))(qp, state) / (*(_areas[j]))(qp, state);
136 const auto inv_L_over_A_sum = 1.0 / L_over_A_sum;
137 // loop over segments
138 for (const auto j : make_range(_n_segments))
139 {
140 // Decide flow regime for friction factor
141 const auto Dh = 4.0 * (*(_areas[j]))(qp, state) / (*(_perimeters[j]))(qp, state);
142 const auto G = massFlowRate() / (*(_areas[j]))(qp, state);
143 const auto fd = computeFrictionFactor(mu, G, Dh, j);
144 // Friction
145 momentum_residual += fd * (*(_lengths[j]))(qp, state) / Dh * G * abs(G) / 2.0 / rhog;
146 // Form losses
147 momentum_residual += (*(_forms_losses[j]))(qp, state) * G * abs(G) / 2.0 / rhog;
148 // Gravity
149 // get local density for natural circulation aspect
150 auto rhol = _fp.rho_from_p_T(_Pref(qp, state), (*(_T[j]))[i]);
151 momentum_residual +=
152 rhol * _gravity(qp, state) * (*(_lengths[j]))(qp, state) * sin((*(_alphas[j]))(qp, state));
153 // Pump pressure
154 momentum_residual -= (*(_dPps[j]))(qp, state);
155 }
156 // Pressure drop (single path-wide unknown, applied once)
157 momentum_residual += pressureDrop();
158
159 return momentum_residual * inv_L_over_A_sum;
160}
161
162template <bool is_ad>
163Real
165{
166 if constexpr (!is_ad)
167 {
168 Real momentum_jacob = 0;
169 const Moose::ElemArg qp = Moose::ElemArg();
170 const int i = 0;
171 const auto state = _is_implicit ? Moose::currentState() : Moose::oldState();
172 // start by getting global fluid properties
173 const auto Tave = ((*(_T[0]))[i] + (*(_T[_n_temps - 1]))[i]) / 2;
174 const auto mu = _fp.mu_from_p_T(_Pref(qp, state), Tave);
175 const auto rhog = _fp.rho_from_p_T(_Pref(qp, state), Tave);
176 // Global rescale factor, see computeQpResidual()
177 Real L_over_A_sum = 0;
178 for (const auto j : make_range(_n_segments))
179 L_over_A_sum += (*(_lengths[j]))(qp, state) / (*(_areas[j]))(qp, state);
180 const auto inv_L_over_A_sum = 1.0 / L_over_A_sum;
181 // loop over segments
182 for (const auto j : make_range(_n_segments))
183 {
184 // Decide flow regime for friction factor
185 const auto Dh = 4.0 * (*(_areas[j]))(qp, state) / (*(_perimeters[j]))(qp, state);
186 const auto G = massFlowRate() / (*(_areas[j]))(qp, state);
187 const auto fd = computeFrictionFactor(mu, G, Dh, j);
188 // Friction
189 momentum_jacob +=
190 fd * (*(_lengths[j]))(qp, state) / Dh * G / rhog / (*(_areas[j]))(qp, state);
191 // Form losses
192 momentum_jacob += (*(_forms_losses[j]))(qp, state) * G / rhog / (*(_areas[j]))(qp, state);
193 }
194
195 return momentum_jacob * inv_L_over_A_sum;
196 }
197 else
198 {
199 mooseError("computeQpJacobian() should not be called in AD mode");
200 return 0;
201 }
202}
203
204template <bool is_ad>
205Real
207{
208 if constexpr (!is_ad)
209 {
210 const Moose::ElemArg qp = Moose::ElemArg();
211 const auto state = _is_implicit ? Moose::currentState() : Moose::oldState();
212 // Global rescale factor, see computeQpResidual()
213 Real L_over_A_sum = 0;
214 for (const auto j : make_range(_n_segments))
215 L_over_A_sum += (*(_lengths[j]))(qp, state) / (*(_areas[j]))(qp, state);
216 const auto inv_L_over_A_sum = 1.0 / L_over_A_sum;
217 // reference pressure drop is subtracted once, scaled by inv_L_over_A_sum, so its derivative is
218 // -inv_L_over_A_sum
219 return -inv_L_over_A_sum;
220 }
221 else
222 {
223 mooseError("computeQpJacobian() should not be called in AD mode");
224 return 0;
225 }
226}
227
228template <bool is_ad>
229Real
231{
232 if constexpr (!is_ad)
233 {
234 return 0;
235 }
236 else
237 {
238 mooseError("computeQpJacobian() should not be called in AD mode");
239 return 0;
240 }
241}
242
243template <>
244Real
246{
247 mooseError("Internal error, calling computeQpJacobian in AD class.");
248 return 0.0;
249}
250
251template <bool is_ad>
254 const GenericReal<is_ad> & G,
255 const GenericReal<is_ad> & Dh,
256 const unsigned int j)
257{
258 const Moose::ElemArg qp = Moose::ElemArg();
259 const auto state = _is_implicit ? Moose::currentState() : Moose::oldState();
260 const auto Re = abs(G) * Dh / mu;
261 const auto f_lam = 64.0 / Re;
262 const auto f_turb =
263 0.25 / pow((log10((*(_roughnesses[j]))(qp, state) / (Dh * 3.7) + 5.74 / pow(Re, 0.9))), 2);
264 if (Re < 2300.0) // laminar
265 return f_lam;
266 else if (Re > 4000.0) // turbulent using Swamee-Jain approx. of Colebrook-White eq.
267 return f_turb;
268 else // transition, conservative interpolation between the two
269 return std::max((f_turb - f_lam) / 1700 * Re + f_lam, std::max(f_lam, f_turb));
270}
271
ExpressionBuilder::EBTerm pow(const ExpressionBuilder::EBTerm &left, T exponent)
const double mu
const double Re
void mooseError(Args &&... args)
Moose::GenericType< Real, is_ad > GenericReal
static InputParameters validParams()
static InputParameters validParams()
typename std::conditional< is_ad, ADScalarKernel, ScalarKernel >::type Base
std::vector< const Moose::Functor< GenericReal< is_ad > > * > _forms_losses
Forms loss coefficients of each segment.
std::vector< const Moose::Functor< GenericReal< is_ad > > * > _alphas
Angle with respect to the horizontal of each segment.
const size_t _n_temps
Number of coupled temperature variables.
IncompressibleMomentumSPBaseTempl(const InputParameters &parameters)
virtual GenericReal< is_ad > computeQpResidual() override
std::vector< const Moose::Functor< GenericReal< is_ad > > * > _roughnesses
Wall roughness of each segment.
std::vector< const VariableValue * > _T
Coupled temperature variables.
std::vector< const Moose::Functor< GenericReal< is_ad > > * > _dPps
Pump pressure gains of each segment.
std::vector< const Moose::Functor< GenericReal< is_ad > > * > _lengths
Length of each segment.
virtual GenericReal< is_ad > computeFrictionFactor(const GenericReal< is_ad > &mu, const GenericReal< is_ad > &G, const GenericReal< is_ad > &Dh, const unsigned int j)
std::vector< const Moose::Functor< GenericReal< is_ad > > * > _perimeters
Wetted perimeter of each segment.
const size_t _n_segments
Number of geometrically/thermally unique segments.
std::vector< const Moose::Functor< GenericReal< is_ad > > * > _areas
Flow area of each segment.
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
void addCoupledVar(const std::string &name, const std::string &doc_string)
const VariableValue & coupledScalarValue(const std::string &var_name, unsigned int comp=0) const
static InputParameters validParams()
Common class for single phase fluid properties.
StateArg oldState()
StateArg currentState()
const auto acceleration_of_gravity