Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : #include "IdealGasMixtureFluidProperties.h"
11 : #include "IdealGasFluidProperties.h"
12 :
13 : registerMooseObject("FluidPropertiesApp", IdealGasMixtureFluidProperties);
14 :
15 : /**
16 : * Defines a mass-specific property z from (p,T)
17 : */
18 : #define define_mass_specific_prop_from_p_T(prop) \
19 : Real IdealGasMixtureFluidProperties::prop##_from_p_T( \
20 : Real p, Real T, const std::vector<Real> & x_secondary) const \
21 : { \
22 : const auto x = secondaryToAllMassFractions(x_secondary); \
23 : mooseAssert(x.size() == _n_components, "Size mismatch"); \
24 : \
25 : Real z = 0; \
26 : for (const auto i : make_range(_n_components)) \
27 : z += x[i] * _component_fps[i]->prop##_from_p_T(p, T); \
28 : \
29 : return z; \
30 : } \
31 : ADReal IdealGasMixtureFluidProperties::prop##_from_p_T( \
32 : const ADReal & p, const ADReal & T, const std::vector<ADReal> & x_secondary) const \
33 : { \
34 : const auto x = secondaryToAllMassFractions(x_secondary); \
35 : mooseAssert(x.size() == _n_components, "Size mismatch"); \
36 : \
37 : ADReal z = 0; \
38 : for (const auto i : make_range(_n_components)) \
39 : z += x[i] * _component_fps[i]->prop##_from_p_T(p, T); \
40 : \
41 : return z; \
42 : }
43 :
44 : /**
45 : * Defines a transport property y from (p,T)
46 : */
47 : #define define_transport_prop_from_p_T(prop) \
48 : Real IdealGasMixtureFluidProperties::prop##_from_p_T( \
49 : Real p, Real T, const std::vector<Real> & x_secondary) const \
50 : { \
51 : const auto x = secondaryToAllMassFractions(x_secondary); \
52 : const auto psi = molarFractionsFromMassFractions(x); \
53 : mooseAssert(psi.size() == _n_components, "Size mismatch"); \
54 : \
55 : Real y = 0; \
56 : for (const auto i : make_range(_n_components)) \
57 : y += psi[i] * _component_fps[i]->prop##_from_p_T(p, T); \
58 : \
59 : return y; \
60 : } \
61 : ADReal IdealGasMixtureFluidProperties::prop##_from_p_T( \
62 : const ADReal & p, const ADReal & T, const std::vector<ADReal> & x_secondary) const \
63 : { \
64 : const auto x = secondaryToAllMassFractions(x_secondary); \
65 : const auto psi = molarFractionsFromMassFractions(x); \
66 : mooseAssert(psi.size() == _n_components, "Size mismatch"); \
67 : \
68 : ADReal y = 0; \
69 : for (const auto i : make_range(_n_components)) \
70 : y += psi[i] * _component_fps[i]->prop##_from_p_T(p, T); \
71 : \
72 : return y; \
73 : }
74 :
75 : // clang-format off
76 42 : define_mass_specific_prop_from_p_T(v)
77 27 : define_mass_specific_prop_from_p_T(e)
78 39 : define_mass_specific_prop_from_p_T(s)
79 27 : define_mass_specific_prop_from_p_T(cp)
80 27 : define_mass_specific_prop_from_p_T(cv)
81 :
82 27 : define_transport_prop_from_p_T(mu)
83 27 : define_transport_prop_from_p_T(k)
84 :
85 : #undef define_mass_specific_prop_from_p_T
86 : #undef define_transport_prop_from_p_T
87 :
88 64 : InputParameters IdealGasMixtureFluidProperties::validParams()
89 : // clang-format on
90 : {
91 64 : InputParameters params = VaporMixtureFluidProperties::validParams();
92 64 : params += NaNInterface::validParams();
93 :
94 64 : params.addClassDescription("Class for fluid properties of an ideal gas mixture");
95 :
96 128 : params.addRequiredParam<std::vector<UserObjectName>>(
97 : "component_fluid_properties",
98 : "Name of component fluid properties user objects. The first entry should be the primary "
99 : "component.");
100 :
101 64 : return params;
102 0 : }
103 :
104 36 : IdealGasMixtureFluidProperties::IdealGasMixtureFluidProperties(const InputParameters & parameters)
105 : : VaporMixtureFluidProperties(parameters),
106 : NaNInterface(this),
107 72 : _component_fp_names(getParam<std::vector<UserObjectName>>("component_fluid_properties")),
108 36 : _n_components(_component_fp_names.size()),
109 72 : _n_secondary_components(_n_components - 1)
110 : {
111 36 : if (_n_components == 0)
112 0 : mooseError("There must be at least one entry in 'component_fluid_properties'.");
113 :
114 36 : _component_fps.resize(_n_components);
115 106 : for (const auto i : make_range(_n_components))
116 : {
117 : const auto & single_phase_fp =
118 72 : getUserObjectByName<SinglePhaseFluidProperties>(_component_fp_names[i]);
119 72 : _component_fps[i] = dynamic_cast<const IdealGasFluidProperties *>(&single_phase_fp);
120 72 : if (!_component_fps[i])
121 2 : mooseError(
122 : "Each entry in 'component_fluid_properties' must have type 'IdealGasFluidProperties'.");
123 : }
124 34 : }
125 :
126 : const SinglePhaseFluidProperties &
127 0 : IdealGasMixtureFluidProperties::getPrimaryFluidProperties() const
128 : {
129 0 : return *_component_fps[0];
130 : }
131 :
132 : const SinglePhaseFluidProperties &
133 0 : IdealGasMixtureFluidProperties::getSecondaryFluidProperties(unsigned int i) const
134 : {
135 : mooseAssert(i < getNumberOfSecondaryVapors(), "Requested secondary index too high.");
136 0 : return *_component_fps[i + 1];
137 : }
138 :
139 : template <typename CppType>
140 : std::vector<CppType>
141 86 : IdealGasMixtureFluidProperties::secondaryToAllMassFractions_templ(
142 : const std::vector<CppType> & x_secondary) const
143 : {
144 : mooseAssert(x_secondary.size() == _n_secondary_components, "Size mismatch");
145 :
146 0 : CppType sum = 0;
147 172 : for (const auto i : make_range(_n_secondary_components))
148 86 : sum += x_secondary[i];
149 :
150 86 : const CppType x_primary = 1.0 - sum;
151 :
152 : std::vector<CppType> x;
153 86 : x.push_back(x_primary);
154 86 : x.insert(x.end(), x_secondary.begin(), x_secondary.end());
155 :
156 86 : return x;
157 0 : }
158 :
159 : std::vector<ADReal>
160 0 : IdealGasMixtureFluidProperties::secondaryToAllMassFractions(
161 : const std::vector<ADReal> & x_secondary) const
162 : {
163 0 : return secondaryToAllMassFractions_templ(x_secondary);
164 : }
165 :
166 : std::vector<Real>
167 86 : IdealGasMixtureFluidProperties::secondaryToAllMassFractions(
168 : const std::vector<Real> & x_secondary) const
169 : {
170 86 : return secondaryToAllMassFractions_templ(x_secondary);
171 : }
172 :
173 : template <typename CppType>
174 : CppType
175 30 : IdealGasMixtureFluidProperties::mixtureMolarMass_templ(const std::vector<CppType> & x) const
176 : {
177 : mooseAssert(x.size() == _n_components, "Size mismatch");
178 :
179 0 : CppType sum = 0;
180 90 : for (const auto i : make_range(_n_components))
181 60 : sum += x[i] / _component_fps[i]->molarMass();
182 :
183 30 : return 1.0 / sum;
184 : }
185 :
186 : ADReal
187 0 : IdealGasMixtureFluidProperties::mixtureMolarMass(const std::vector<ADReal> & x) const
188 : {
189 0 : return mixtureMolarMass_templ(x);
190 : }
191 :
192 : Real
193 30 : IdealGasMixtureFluidProperties::mixtureMolarMass(const std::vector<Real> & x) const
194 : {
195 30 : return mixtureMolarMass_templ(x);
196 : }
197 :
198 : template <typename CppType>
199 : CppType
200 10 : IdealGasMixtureFluidProperties::mixtureSpecificHeatRatio_templ(const std::vector<CppType> & x) const
201 : {
202 : mooseAssert(x.size() == _n_components, "Size mismatch");
203 :
204 0 : CppType cp_mix = 0, cv_mix = 0;
205 30 : for (const auto i : make_range(_n_components))
206 : {
207 : // cp and cv are constant due to ideal gas assumption; any (p, T) is fine:
208 20 : cp_mix += x[i] * _component_fps[i]->cp_from_p_T(0, 0);
209 20 : cv_mix += x[i] * _component_fps[i]->cv_from_p_T(0, 0);
210 : }
211 :
212 10 : return cp_mix / cv_mix;
213 : }
214 :
215 : ADReal
216 0 : IdealGasMixtureFluidProperties::mixtureSpecificHeatRatio(const std::vector<ADReal> & x) const
217 : {
218 0 : return mixtureSpecificHeatRatio_templ(x);
219 : }
220 :
221 : Real
222 10 : IdealGasMixtureFluidProperties::mixtureSpecificHeatRatio(const std::vector<Real> & x) const
223 : {
224 10 : return mixtureSpecificHeatRatio_templ(x);
225 : }
226 :
227 : template <typename CppType>
228 : std::vector<CppType>
229 18 : IdealGasMixtureFluidProperties::molarFractionsFromMassFractions_templ(
230 : const std::vector<CppType> & x) const
231 : {
232 : mooseAssert(x.size() == _n_components, "Size mismatch");
233 :
234 18 : const auto M = mixtureMolarMass(x);
235 18 : std::vector<CppType> psi(_n_components);
236 54 : for (const auto i : make_range(_n_components))
237 36 : psi[i] = x[i] * M / _component_fps[i]->molarMass();
238 :
239 18 : return psi;
240 0 : }
241 :
242 : std::vector<ADReal>
243 0 : IdealGasMixtureFluidProperties::molarFractionsFromMassFractions(const std::vector<ADReal> & x) const
244 : {
245 0 : return molarFractionsFromMassFractions_templ(x);
246 : }
247 :
248 : std::vector<Real>
249 18 : IdealGasMixtureFluidProperties::molarFractionsFromMassFractions(const std::vector<Real> & x) const
250 : {
251 18 : return molarFractionsFromMassFractions_templ(x);
252 : }
253 :
254 : ADReal
255 0 : IdealGasMixtureFluidProperties::rho_from_p_T(const ADReal & p,
256 : const ADReal & T,
257 : const std::vector<ADReal> & x_secondary) const
258 : {
259 0 : return 1.0 / v_from_p_T(p, T, x_secondary);
260 : }
261 :
262 : Real
263 1 : IdealGasMixtureFluidProperties::rho_from_p_T(Real p,
264 : Real T,
265 : const std::vector<Real> & x_secondary) const
266 : {
267 1 : return 1.0 / v_from_p_T(p, T, x_secondary);
268 : }
269 :
270 : template <typename CppType>
271 : CppType
272 1 : IdealGasMixtureFluidProperties::e_from_p_rho_templ(const CppType & p,
273 : const CppType & rho,
274 : const std::vector<CppType> & x_secondary) const
275 : {
276 1 : const auto x = secondaryToAllMassFractions(x_secondary);
277 : mooseAssert(x.size() == _n_components, "Size mismatch");
278 :
279 1 : const auto M = mixtureMolarMass(x);
280 :
281 0 : CppType e_ref_sum = 0;
282 0 : CppType cv_sum = 0;
283 3 : for (const auto i : make_range(_n_components))
284 : {
285 2 : e_ref_sum += x[i] * _component_fps[i]->referenceSpecificInternalEnergy();
286 : // cv is constant due to ideal gas assumption; any (p, T) is fine:
287 2 : cv_sum += x[i] * _component_fps[i]->cv_from_p_T(0, 0);
288 : }
289 :
290 1 : return cv_sum * M * p / (_R * rho) + e_ref_sum;
291 1 : }
292 :
293 : ADReal
294 0 : IdealGasMixtureFluidProperties::e_from_p_rho(const ADReal & p,
295 : const ADReal & rho,
296 : const std::vector<ADReal> & x_secondary) const
297 : {
298 0 : return e_from_p_rho_templ(p, rho, x_secondary);
299 : }
300 :
301 : Real
302 1 : IdealGasMixtureFluidProperties::e_from_p_rho(Real p,
303 : Real rho,
304 : const std::vector<Real> & x_secondary) const
305 : {
306 1 : return e_from_p_rho_templ(p, rho, x_secondary);
307 : }
308 :
309 : template <typename CppType>
310 : CppType
311 1 : IdealGasMixtureFluidProperties::p_from_v_e_templ(const CppType & v,
312 : const CppType & e,
313 : const std::vector<CppType> & x_secondary) const
314 : {
315 1 : const auto x = secondaryToAllMassFractions(x_secondary);
316 1 : const auto M = mixtureMolarMass(x);
317 :
318 2 : return _R * T_from_v_e(v, e, x_secondary) / (M * v);
319 1 : }
320 :
321 : ADReal
322 0 : IdealGasMixtureFluidProperties::p_from_v_e(const ADReal & v,
323 : const ADReal & e,
324 : const std::vector<ADReal> & x_secondary) const
325 : {
326 0 : return p_from_v_e_templ(v, e, x_secondary);
327 : }
328 :
329 : Real
330 1 : IdealGasMixtureFluidProperties::p_from_v_e(Real v,
331 : Real e,
332 : const std::vector<Real> & x_secondary) const
333 : {
334 1 : return p_from_v_e_templ(v, e, x_secondary);
335 : }
336 :
337 : template <typename CppType>
338 : CppType
339 2 : IdealGasMixtureFluidProperties::T_from_v_e_templ(const CppType & /*v*/,
340 : const CppType & e,
341 : const std::vector<CppType> & x_secondary) const
342 : {
343 2 : const auto x = secondaryToAllMassFractions(x_secondary);
344 : mooseAssert(x.size() == _n_components, "Size mismatch");
345 :
346 0 : CppType e_ref_sum = 0;
347 0 : CppType cv_sum = 0;
348 6 : for (const auto i : make_range(_n_components))
349 : {
350 4 : e_ref_sum += x[i] * _component_fps[i]->referenceSpecificInternalEnergy();
351 : // cv is constant due to ideal gas assumption; any (p, T) is fine:
352 4 : cv_sum += x[i] * _component_fps[i]->cv_from_p_T(0, 0);
353 : }
354 :
355 2 : return (e - e_ref_sum) / cv_sum;
356 2 : }
357 :
358 : ADReal
359 0 : IdealGasMixtureFluidProperties::T_from_v_e(const ADReal & v,
360 : const ADReal & e,
361 : const std::vector<ADReal> & x_secondary) const
362 : {
363 0 : return T_from_v_e_templ(v, e, x_secondary);
364 : }
365 :
366 : Real
367 2 : IdealGasMixtureFluidProperties::T_from_v_e(Real v,
368 : Real e,
369 : const std::vector<Real> & x_secondary) const
370 : {
371 2 : return T_from_v_e_templ(v, e, x_secondary);
372 : }
373 :
374 : template <typename CppType>
375 : CppType
376 10 : IdealGasMixtureFluidProperties::c_from_p_T_templ(const CppType & /*p*/,
377 : const CppType & T,
378 : const std::vector<CppType> & x_secondary) const
379 : {
380 10 : const auto x = secondaryToAllMassFractions(x_secondary);
381 10 : const auto M = mixtureMolarMass(x);
382 10 : const auto gamma = mixtureSpecificHeatRatio(x);
383 :
384 10 : return std::sqrt(gamma * _R * T / M);
385 10 : }
386 :
387 : ADReal
388 0 : IdealGasMixtureFluidProperties::c_from_p_T(const ADReal & p,
389 : const ADReal & T,
390 : const std::vector<ADReal> & x_secondary) const
391 : {
392 0 : return c_from_p_T_templ(p, T, x_secondary);
393 : }
394 :
395 : Real
396 10 : IdealGasMixtureFluidProperties::c_from_p_T(Real p,
397 : Real T,
398 : const std::vector<Real> & x_secondary) const
399 : {
400 10 : return c_from_p_T_templ(p, T, x_secondary);
401 : }
|