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 "TabulatedFluidProperties.h"
11 : #include "MooseUtils.h"
12 : #include "Conversion.h"
13 : #include "KDTree.h"
14 : #include "BidimensionalInterpolation.h"
15 : #include "NewtonInversion.h"
16 :
17 : // C++ includes
18 : #include <fstream>
19 : #include <ctime>
20 : #include <cmath>
21 : #include <regex>
22 :
23 : InputParameters
24 526 : TabulatedFluidProperties::validParams()
25 : {
26 526 : InputParameters params = SinglePhaseFluidProperties::validParams();
27 526 : params.addClassDescription(
28 : "Single phase fluid properties computed using bi-dimensional interpolation of tabulated "
29 : "values.");
30 :
31 : // Which interpolations to create
32 1052 : params.addParam<bool>("create_pT_interpolations",
33 1052 : true,
34 : "Whether to load (from file) or create (from a fluid property object) "
35 : "properties interpolations from pressure and temperature");
36 1052 : params.addParam<bool>(
37 : "create_ve_interpolations",
38 1052 : false,
39 : "Whether to load (from file) or create (from a fluid property object) "
40 : "properties interpolations from specific volume and specific internal energy");
41 :
42 : // Input / output
43 1052 : params.addParam<UserObjectName>("fp", "The name of the FluidProperties UserObject");
44 1052 : params.deprecateParam("fp", "input_fp", "12/12/26");
45 : // deprecate to be able to put "fp" in the GlobalParams without creating issues with TabulatedFP
46 1052 : params.addParam<FileName>("fluid_property_file",
47 : "Name of the csv file containing the tabulated fluid property data.");
48 1052 : params.addParam<FileName>(
49 : "fluid_property_ve_file",
50 : "Name of the csv file containing the tabulated (v,e) fluid property data.");
51 1052 : params.addParam<FileName>("fluid_property_output_file",
52 : "Name of the CSV file which can be output with the tabulation. This "
53 : "file can then be read as a 'fluid_property_file'");
54 1052 : params.addParam<FileName>(
55 : "fluid_property_ve_output_file",
56 : "Name of the CSV file which can be output with the (v,e) tabulation. This "
57 : "file can then be read as a 'fluid_property_ve_file'");
58 1052 : params.addDeprecatedParam<bool>(
59 : "save_file",
60 : "Whether to save the csv fluid properties file",
61 : "This parameter is no longer required. Whether to save a CSV tabulation file is controlled "
62 : "by specifying the 'fluid_property_output_file' parameter");
63 1052 : params.addParam<bool>("skip_header_tabulation",
64 1052 : false,
65 : "Whether to skip the header in the tabulation output, useful for testing");
66 :
67 : // Data source on a per-property basis
68 : MultiMooseEnum properties(
69 : "density enthalpy internal_energy viscosity k c cv cp entropy pressure temperature",
70 526 : "density enthalpy internal_energy viscosity");
71 1052 : params.addParam<MultiMooseEnum>("interpolated_properties",
72 : properties,
73 : "Properties to interpolate. If unspecified and a data file is "
74 : "provided, the properties from the data file will be used. If "
75 : "specified, some properties from the data file can be ignored.");
76 :
77 : // (p,T) grid parameters
78 1052 : params.addRangeCheckedParam<Real>(
79 : "temperature_min", 300, "temperature_min > 0", "Minimum temperature for tabulated data.");
80 1052 : params.addParam<Real>("temperature_max", 500, "Maximum temperature for tabulated data.");
81 1578 : params.addRangeCheckedParam<Real>(
82 1052 : "pressure_min", 1e5, "pressure_min > 0", "Minimum pressure for tabulated data.");
83 1052 : params.addParam<Real>("pressure_max", 50.0e6, "Maximum pressure for tabulated data.");
84 1578 : params.addRangeCheckedParam<unsigned int>(
85 1052 : "num_T", 100, "num_T > 0", "Number of points to divide temperature range.");
86 1578 : params.addRangeCheckedParam<unsigned int>(
87 1052 : "num_p", 100, "num_p > 0", "Number of points to divide pressure range.");
88 :
89 : // (v,e) grid parameters
90 1052 : params.addParam<Real>("e_min", "Minimum specific internal energy for tabulated data.");
91 1052 : params.addParam<Real>("e_max", "Maximum specific internal energy for tabulated data.");
92 1052 : params.addRangeCheckedParam<Real>(
93 : "v_min", "v_min > 0", "Minimum specific volume for tabulated data.");
94 1052 : params.addRangeCheckedParam<Real>(
95 : "v_max", "v_max > 0", "Maximum specific volume for tabulated data.");
96 1052 : params.addParam<bool>("construct_pT_from_ve",
97 1052 : false,
98 : "If the lookup table (p, T) as functions of (v, e) should be constructed.");
99 1052 : params.addParam<bool>("construct_pT_from_vh",
100 1052 : false,
101 : "If the lookup table (p, T) as functions of (v, h) should be constructed.");
102 1578 : params.addRangeCheckedParam<unsigned int>(
103 : "num_v",
104 1052 : 100,
105 : "num_v > 0",
106 : "Number of points to divide specific volume range for (v,e) lookups.");
107 1578 : params.addRangeCheckedParam<unsigned int>("num_e",
108 1052 : 100,
109 : "num_e > 0",
110 : "Number of points to divide specific internal energy "
111 : "range for (v,e) lookups.");
112 1052 : params.addParam<bool>(
113 : "use_log_grid_v",
114 1052 : false,
115 : "Option to use a base-10 logarithmically-spaced grid for specific volume instead of a "
116 : "linearly-spaced grid.");
117 1052 : params.addParam<bool>(
118 : "use_log_grid_e",
119 1052 : false,
120 : "Option to use a base-10 logarithmically-spaced grid for specific internal energy instead "
121 : "of a linearly-spaced grid.");
122 1052 : params.addParam<bool>(
123 : "use_log_grid_h",
124 1052 : false,
125 : "Option to use a base-10 logarithmically-spaced grid for specific enthalpy instead "
126 : "of a linearly-spaced grid.");
127 :
128 : // Out of bounds behavior
129 1052 : params.addDeprecatedParam<bool>(
130 : "error_on_out_of_bounds",
131 : "Whether pressure or temperature from tabulation exceeding user-specified bounds leads to "
132 : "an error.",
133 : "This parameter has been replaced by the 'out_of_bounds_behavior' parameter which offers "
134 : "more flexibility. The option to error is called 'throw' in that parameter.");
135 : // NOTE: this enum must remain the same as OOBBehavior in the header
136 1052 : MooseEnum OOBBehavior("ignore throw declare_invalid warn_invalid set_to_closest_bound", "throw");
137 1052 : params.addParam<MooseEnum>("out_of_bounds_behavior",
138 : OOBBehavior,
139 : "Property evaluation behavior when evaluated outside the "
140 : "user-specified or tabulation-specified bounds");
141 :
142 : // This is generally a bad idea. However, several properties have not been tabulated so several
143 : // tests are relying on the original fp object to provide the value (for example for the
144 : // vaporPressure())
145 1052 : params.addParam<bool>(
146 1052 : "allow_fp_and_tabulation", false, "Whether to allow the two sources of data concurrently");
147 :
148 1052 : params.addParamNamesToGroup("fluid_property_file fluid_property_ve_file "
149 : "fluid_property_output_file fluid_property_ve_output_file",
150 : "Tabulation file read/write");
151 1052 : params.addParamNamesToGroup("construct_pT_from_ve construct_pT_from_vh",
152 : "Variable set conversion");
153 1052 : params.addParamNamesToGroup("temperature_min temperature_max pressure_min pressure_max e_min "
154 : "e_max v_min v_max error_on_out_of_bounds out_of_bounds_behavior",
155 : "Tabulation and interpolation bounds");
156 1052 : params.addParamNamesToGroup(
157 : "num_T num_p num_v num_e use_log_grid_v use_log_grid_e use_log_grid_h",
158 : "Tabulation and interpolation discretization");
159 :
160 526 : return params;
161 526 : }
162 :
163 280 : TabulatedFluidProperties::TabulatedFluidProperties(const InputParameters & parameters)
164 : : SinglePhaseFluidProperties(parameters),
165 560 : _file_name_in(isParamValid("fluid_property_file") ? getParam<FileName>("fluid_property_file")
166 : : ""),
167 302 : _file_name_ve_in(
168 560 : isParamValid("fluid_property_ve_file") ? getParam<FileName>("fluid_property_ve_file") : ""),
169 576 : _file_name_out(isParamValid("fluid_property_output_file")
170 280 : ? getParam<FileName>("fluid_property_output_file")
171 : : ""),
172 568 : _file_name_ve_out(isParamValid("fluid_property_ve_output_file")
173 280 : ? getParam<FileName>("fluid_property_ve_output_file")
174 : : ""),
175 854 : _save_file(isParamValid("save_file") ? getParam<bool>("save_file")
176 812 : : (isParamValid("fluid_property_output_file") ||
177 780 : isParamValid("fluid_property_ve_output_file"))),
178 560 : _create_direct_pT_interpolations(getParam<bool>("create_pT_interpolations")),
179 560 : _create_direct_ve_interpolations(getParam<bool>("create_ve_interpolations")),
180 560 : _temperature_min(getParam<Real>("temperature_min")),
181 560 : _temperature_max(getParam<Real>("temperature_max")),
182 560 : _pressure_min(getParam<Real>("pressure_min")),
183 560 : _pressure_max(getParam<Real>("pressure_max")),
184 560 : _num_T(getParam<unsigned int>("num_T")),
185 560 : _num_p(getParam<unsigned int>("num_p")),
186 : // work-around to allow use of 'fp' in GlobalParams
187 988 : _fp(isParamValid("input_fp") ? ((getParam<UserObjectName>("input_fp") != name())
188 428 : ? &getUserObject<SinglePhaseFluidProperties>("input_fp")
189 : : nullptr)
190 : : nullptr),
191 560 : _allow_fp_and_tabulation(getParam<bool>("allow_fp_and_tabulation")),
192 840 : _interpolated_properties_enum(getParam<MultiMooseEnum>("interpolated_properties")),
193 : _interpolated_properties(),
194 280 : _interpolate_density(false),
195 280 : _interpolate_enthalpy(false),
196 280 : _interpolate_internal_energy(false),
197 280 : _interpolate_viscosity(false),
198 280 : _interpolate_k(false),
199 280 : _interpolate_c(false),
200 280 : _interpolate_cp(false),
201 280 : _interpolate_cv(false),
202 280 : _interpolate_entropy(false),
203 280 : _interpolate_pressure(false),
204 280 : _interpolate_temperature(false),
205 280 : _density_idx(libMesh::invalid_uint),
206 280 : _enthalpy_idx(libMesh::invalid_uint),
207 280 : _internal_energy_idx(libMesh::invalid_uint),
208 280 : _viscosity_idx(libMesh::invalid_uint),
209 280 : _k_idx(libMesh::invalid_uint),
210 280 : _c_idx(libMesh::invalid_uint),
211 280 : _cp_idx(libMesh::invalid_uint),
212 280 : _cv_idx(libMesh::invalid_uint),
213 280 : _entropy_idx(libMesh::invalid_uint),
214 280 : _p_idx(libMesh::invalid_uint),
215 280 : _T_idx(libMesh::invalid_uint),
216 280 : _csv_reader(_file_name_in, &_communicator),
217 560 : _construct_pT_from_ve(getParam<bool>("construct_pT_from_ve")),
218 560 : _construct_pT_from_vh(getParam<bool>("construct_pT_from_vh")),
219 280 : _initial_setup_done(false),
220 560 : _num_v(getParam<unsigned int>("num_v")),
221 560 : _num_e(getParam<unsigned int>("num_e")),
222 560 : _log_space_v(getParam<bool>("use_log_grid_v")),
223 560 : _log_space_e(getParam<bool>("use_log_grid_e")),
224 560 : _log_space_h(getParam<bool>("use_log_grid_h")),
225 840 : _OOBBehavior(getParam<MooseEnum>("out_of_bounds_behavior")),
226 280 : _e_min(0),
227 280 : _e_max(0),
228 280 : _v_min(0),
229 280 : _v_max(0)
230 : {
231 : // Check that initial guess (used in Newton Method) is within min and max values
232 280 : checkInitialGuess(false);
233 : // Sanity check on minimum and maximum temperatures and pressures
234 276 : if (_temperature_max <= _temperature_min)
235 2 : mooseError("temperature_max must be greater than temperature_min");
236 274 : if (_pressure_max <= _pressure_min)
237 2 : mooseError("pressure_max must be greater than pressure_min");
238 :
239 : // Set (v,e) bounds if specified by the user
240 548 : if (isParamValid("e_min") && isParamValid("e_max"))
241 : {
242 0 : _e_min = getParam<Real>("e_min");
243 0 : _e_max = getParam<Real>("e_max");
244 0 : _e_bounds_specified = true;
245 : }
246 1084 : else if (isParamValid("e_min") || isParamValid("e_max"))
247 2 : paramError("e_min",
248 : "Either both or none of the min and max values of the specific internal energy "
249 : "should be specified");
250 : else
251 270 : _e_bounds_specified = false;
252 548 : if (isParamValid("v_min") && isParamValid("v_max"))
253 : {
254 4 : _v_min = getParam<Real>("v_min");
255 4 : _v_max = getParam<Real>("v_max");
256 2 : _v_bounds_specified = true;
257 : }
258 1068 : else if (isParamValid("v_min") || isParamValid("v_max"))
259 2 : paramError("v_min",
260 : "Either both or none of the min and max values of the specific volume "
261 : "should be specified");
262 : else
263 266 : _v_bounds_specified = false;
264 :
265 : // Handle out of bounds behavior parameters and deprecation
266 554 : if (isParamValid("error_on_out_of_bounds") && getParam<bool>("error_on_out_of_bounds") &&
267 6 : _OOBBehavior != Throw)
268 0 : paramError("out_of_bounds_behavior", "Inconsistent selection of out of bounds behavior.");
269 554 : else if (isParamValid("error_on_out_of_bounds") && !getParam<bool>("error_on_out_of_bounds"))
270 0 : _OOBBehavior = SetToClosestBound;
271 :
272 : // Lines starting with # in the data file are treated as comments
273 268 : _csv_reader.setComment("#");
274 :
275 : // Can only and must receive one source of data between fp and tabulations
276 268 : if (_fp && (!_file_name_in.empty() || !_file_name_ve_in.empty()) && !_allow_fp_and_tabulation)
277 0 : paramError(
278 : "fluid_property_file",
279 : "Cannot supply both a fluid properties object with 'input_fp' and a source tabulation "
280 : "file with 'fluid_property_file', unless 'allow_fp_and_tabulation' is set to true");
281 268 : if (!_fp && _file_name_in.empty() && _file_name_ve_in.empty())
282 0 : paramError(
283 : "fluid_property_file",
284 : "Either a fluid properties object with the parameter 'input_fp' and a source tabulation "
285 : "file with the parameter 'fluid_property_file' or 'fluid_property_ve_file' should "
286 : "be provided.");
287 268 : if (!_create_direct_pT_interpolations && !_create_direct_ve_interpolations)
288 0 : paramError("create_pT_interpolations", "Must create either (p,T) or (v,e) interpolations");
289 :
290 : // Some parameters are not used when reading a tabulation
291 374 : if (!_fp && !_file_name_in.empty() &&
292 750 : (isParamSetByUser("pressure_min") || isParamSetByUser("pressure_max") ||
293 628 : isParamSetByUser("temperature_min") || isParamSetByUser("temperature_max")))
294 16 : mooseWarning("User-specified bounds in pressure and temperature are ignored when reading a "
295 : "'fluid_property_file'. The tabulation bounds are selected "
296 : "from the bounds of the input tabulation.");
297 692 : if (!_fp && !_file_name_in.empty() && (isParamSetByUser("num_p") || isParamSetByUser("num_T")))
298 0 : mooseWarning("User-specified grid sizes in pressure and temperature are ignored when reading a "
299 : "'fluid_property_file'. The tabulation bounds are selected "
300 : "from the bounds of the input tabulation.");
301 290 : if (!_fp && !_file_name_ve_in.empty() &&
302 392 : (isParamSetByUser("v_min") || isParamSetByUser("v_max") || isParamSetByUser("e_min") ||
303 308 : isParamSetByUser("e_max")))
304 2 : mooseWarning(
305 : "User-specified bounds in specific volume and internal energy are ignored when reading a "
306 : "'fluid_property_ve_file'. The tabulation bounds are selected "
307 : "from the bounds of the input tabulation.");
308 346 : if (!_fp && !_file_name_ve_in.empty() && (isParamSetByUser("num_e") || isParamSetByUser("num_v")))
309 2 : mooseWarning("User-specified grid sizes in specific volume and internal energy are ignored "
310 : "when reading a 'fluid_property_ve_file'. The tabulation widths are read "
311 : "from the input tabulation.");
312 264 : if (!_file_name_ve_in.empty() && (_log_space_v || _log_space_e))
313 2 : mooseWarning(
314 : "User specfied logarithmic grids in specific volume and energy are ignored when reading a "
315 : "'fluid_properties_ve_file'. The tabulation grid is read from the input tabulation");
316 262 : }
317 :
318 : void
319 125 : TabulatedFluidProperties::initialSetup()
320 : {
321 125 : if (_initial_setup_done)
322 : return;
323 125 : _initial_setup_done = true;
324 :
325 125 : if (_create_direct_pT_interpolations)
326 : {
327 : // If the user specified a (p, T) tabulation to read, use that
328 106 : if (!_file_name_in.empty())
329 23 : readFileTabulationData(true);
330 : else
331 : {
332 83 : if (!_fp)
333 0 : paramError("create_pT_interpolations",
334 : "No FluidProperties (specified with 'input_fp' parameter) exists. Either "
335 : "specify a 'input_fp' or "
336 : "specify a (p, T) tabulation file with the 'fluid_property_file' parameter");
337 83 : _console << name() + ": Generating (p, T) tabulated data\n";
338 83 : _console << std::flush;
339 :
340 83 : generateTabulatedData();
341 : }
342 : }
343 :
344 120 : if (_create_direct_ve_interpolations)
345 : {
346 : // If the user specified a (v, e) tabulation to read, use that
347 19 : if (!_file_name_ve_in.empty())
348 16 : readFileTabulationData(false);
349 : else
350 : {
351 3 : if (!_fp)
352 0 : paramError("create_ve_interpolations",
353 : "No FluidProperties (specified with 'input_fp' parameter) exists. Either "
354 : "specify a 'input_fp' or "
355 : "specify a (v, e) tabulation file with the 'fluid_property_ve_file' parameter");
356 3 : _console << name() + ": Generating (v, e) tabulated data\n";
357 3 : _console << std::flush;
358 :
359 3 : generateVETabulatedData();
360 : }
361 : }
362 :
363 120 : computePropertyIndicesInInterpolationVectors();
364 120 : constructInterpolation();
365 :
366 : // Could be needed to get bounds computed from (p, T) bounds
367 120 : if (_fp && !_create_direct_ve_interpolations)
368 83 : createVEGridVectors();
369 :
370 : // Write tabulated data to file
371 120 : if (_save_file)
372 : {
373 24 : _console << name() + ": Writing tabulated data to " << _file_name_out << "\n";
374 48 : writeTabulatedData(_file_name_out);
375 : }
376 : }
377 :
378 : std::string
379 11 : TabulatedFluidProperties::fluidName() const
380 : {
381 11 : if (_fp)
382 11 : return _fp->fluidName();
383 : else
384 0 : return "TabulationFromFile";
385 : }
386 :
387 : Real
388 11 : TabulatedFluidProperties::molarMass() const
389 : {
390 11 : if (_fp)
391 11 : return _fp->molarMass();
392 : else
393 0 : TabulationNotImplementedError("molarMass");
394 : }
395 :
396 : Real
397 255 : TabulatedFluidProperties::v_from_p_T(Real pressure, Real temperature) const
398 : {
399 255 : if (_interpolate_density && _create_direct_pT_interpolations)
400 : {
401 12 : checkInputVariables(pressure, temperature);
402 12 : return 1.0 / _property_ipol[_density_idx]->sample(pressure, temperature);
403 : }
404 243 : else if (_create_direct_ve_interpolations)
405 : {
406 242 : checkInputVariables(pressure, temperature);
407 : Real v, e;
408 : auto p_from_v_e = [&](Real v, Real e, Real & new_p, Real & dp_dv, Real & dp_de)
409 970 : { this->p_from_v_e(v, e, new_p, dp_dv, dp_de); };
410 : auto T_from_v_e = [&](Real v, Real e, Real & new_T, Real & dT_dv, Real & dT_de)
411 970 : { this->T_from_v_e(v, e, new_T, dT_dv, dT_de); };
412 484 : FluidPropertiesUtils::NewtonSolve2D(pressure,
413 : temperature,
414 242 : (_v_min + _v_max) / 2,
415 242 : (_e_min + _e_max) / 2,
416 : v,
417 : e,
418 : _tolerance,
419 242 : _tolerance,
420 : p_from_v_e,
421 : T_from_v_e,
422 242 : name() + "::v_from_p_T",
423 242 : _max_newton_its,
424 242 : _verbose_newton);
425 242 : return v;
426 : }
427 : else
428 : {
429 1 : if (_fp)
430 1 : return 1.0 / _fp->rho_from_p_T(pressure, temperature);
431 : else
432 0 : NeedTabulationOrFPError("AD v_from_p_T", "density");
433 : }
434 : }
435 :
436 : ADReal
437 6 : TabulatedFluidProperties::v_from_p_T(const ADReal & pressure, const ADReal & temperature) const
438 : {
439 6 : if (_interpolate_density && _create_direct_pT_interpolations)
440 : {
441 1 : ADReal pressure_nc = pressure, temperature_nc = temperature;
442 1 : checkInputVariables(pressure_nc, temperature_nc);
443 2 : return 1.0 / _property_ipol[_density_idx]->sample(pressure_nc, temperature_nc);
444 : }
445 5 : else if (_create_direct_ve_interpolations)
446 : {
447 2 : ADReal pressure_nc = pressure, temperature_nc = temperature;
448 2 : checkInputVariables(pressure_nc, temperature_nc);
449 : ADReal v, e;
450 : auto p_from_v_e = [&](ADReal v, ADReal e, ADReal & new_p, ADReal & dp_dv, ADReal & dp_de)
451 8 : { this->p_from_v_e(v, e, new_p, dp_dv, dp_de); };
452 : auto T_from_v_e = [&](ADReal v, ADReal e, ADReal & new_T, ADReal & dT_dv, ADReal & dT_de)
453 8 : { this->T_from_v_e(v, e, new_T, dT_dv, dT_de); };
454 4 : FluidPropertiesUtils::NewtonSolve2D(pressure_nc,
455 : temperature_nc,
456 2 : (_v_min + _v_max) / 2,
457 2 : (_e_min + _e_max) / 2,
458 : v,
459 : e,
460 : _tolerance,
461 2 : _tolerance,
462 : p_from_v_e,
463 : T_from_v_e,
464 2 : name() + "::v_from_p_T",
465 2 : _max_newton_its,
466 2 : _verbose_newton);
467 2 : return v;
468 : }
469 : else
470 : {
471 3 : if (_fp)
472 6 : return 1.0 / _fp->rho_from_p_T(pressure, temperature);
473 : else
474 0 : NeedTabulationOrFPError("AD v_from_p_T", "density");
475 : }
476 : }
477 :
478 : void
479 12687145 : TabulatedFluidProperties::v_from_p_T(
480 : Real pressure, Real temperature, Real & v, Real & dv_dp, Real & dv_dT) const
481 : {
482 12687145 : Real rho = 0, drho_dp = 0, drho_dT = 0;
483 12687145 : if (_interpolate_density && _create_direct_pT_interpolations)
484 : {
485 12687145 : checkInputVariables(pressure, temperature);
486 12687145 : _property_ipol[_density_idx]->sampleValueAndDerivatives(
487 : pressure, temperature, rho, drho_dp, drho_dT);
488 : }
489 : else
490 : {
491 0 : if (_fp)
492 0 : _fp->rho_from_p_T(pressure, temperature, rho, drho_dp, drho_dT);
493 : else
494 0 : NeedTabulationOrFPError("v_from_p_T with derivatives", "density");
495 : }
496 : // convert from rho to v
497 12687145 : v = 1.0 / rho;
498 12687145 : dv_dp = -drho_dp / (rho * rho);
499 12687145 : dv_dT = -drho_dT / (rho * rho);
500 12687145 : }
501 :
502 : Real
503 768 : TabulatedFluidProperties::rho_from_p_T(Real pressure, Real temperature) const
504 : {
505 768 : if (_interpolate_density && _create_direct_pT_interpolations)
506 : {
507 524 : checkInputVariables(pressure, temperature);
508 520 : return _property_ipol[_density_idx]->sample(pressure, temperature);
509 : }
510 244 : else if (_create_direct_ve_interpolations)
511 242 : return 1. / v_from_p_T(pressure, temperature);
512 : else
513 : {
514 2 : if (_fp)
515 2 : return _fp->rho_from_p_T(pressure, temperature);
516 : else
517 0 : NeedTabulationOrFPError("rho_from_p_T", "density");
518 : }
519 : }
520 :
521 : ADReal
522 6 : TabulatedFluidProperties::rho_from_p_T(const ADReal & pressure, const ADReal & temperature) const
523 : {
524 6 : if (_interpolate_density && _create_direct_pT_interpolations)
525 : {
526 1 : ADReal pressure_nc = pressure, temperature_nc = temperature;
527 1 : checkInputVariables(pressure_nc, temperature_nc);
528 1 : return _property_ipol[_density_idx]->sample(pressure_nc, temperature_nc);
529 : }
530 5 : else if (_create_direct_ve_interpolations)
531 4 : return 1. / v_from_p_T(pressure, temperature);
532 : else
533 : {
534 3 : if (_fp)
535 3 : return _fp->rho_from_p_T(pressure, temperature);
536 : else
537 0 : NeedTabulationOrFPError("AD rho_from_p_T", "density");
538 : }
539 : }
540 :
541 : void
542 107 : TabulatedFluidProperties::rho_from_p_T(
543 : Real pressure, Real temperature, Real & rho, Real & drho_dp, Real & drho_dT) const
544 : {
545 107 : if (_interpolate_density && _create_direct_pT_interpolations)
546 : {
547 54 : checkInputVariables(pressure, temperature);
548 54 : _property_ipol[_density_idx]->sampleValueAndDerivatives(
549 : pressure, temperature, rho, drho_dp, drho_dT);
550 : }
551 53 : else if (_create_direct_ve_interpolations)
552 : {
553 50 : checkInputVariables(pressure, temperature);
554 : // use finite differencing stencil
555 50 : rho = rho_from_p_T(pressure, temperature);
556 : Real eps = 1e-8;
557 50 : drho_dp = (rho_from_p_T(pressure * (1 + eps), temperature) - rho) / (eps * pressure);
558 50 : drho_dT = (rho_from_p_T(pressure, temperature * (1 + eps)) - rho) / (eps * temperature);
559 : }
560 : else
561 : {
562 3 : if (_fp)
563 3 : _fp->rho_from_p_T(pressure, temperature, rho, drho_dp, drho_dT);
564 : else
565 0 : NeedTabulationOrFPError("rho_from_p_T with derivatives", "density");
566 : }
567 107 : }
568 :
569 : void
570 5 : TabulatedFluidProperties::rho_from_p_T(const ADReal & pressure,
571 : const ADReal & temperature,
572 : ADReal & rho,
573 : ADReal & drho_dp,
574 : ADReal & drho_dT) const
575 : {
576 5 : if (_interpolate_density && _create_direct_pT_interpolations)
577 : {
578 1 : ADReal p = pressure, T = temperature;
579 1 : checkInputVariables(p, T);
580 1 : _property_ipol[_density_idx]->sampleValueAndDerivatives(p, T, rho, drho_dp, drho_dT);
581 1 : }
582 : else
583 : {
584 4 : if (_fp)
585 4 : _fp->rho_from_p_T(pressure, temperature, rho, drho_dp, drho_dT);
586 : else
587 0 : NeedTabulationOrFPError("AD rho_from_p_T with derivatives", "density");
588 : }
589 5 : }
590 :
591 : Real
592 6 : TabulatedFluidProperties::rho_from_p_s(Real p, Real s) const
593 : {
594 6 : Real T = T_from_p_s(p, s);
595 6 : return rho_from_p_T(p, T);
596 : }
597 :
598 : void
599 1 : TabulatedFluidProperties::rho_from_p_s(
600 : Real p, Real s, Real & rho, Real & drho_dp, Real & drho_ds) const
601 : {
602 : Real T, dT_dp, dT_ds;
603 1 : T_from_p_s(p, s, T, dT_dp, dT_ds);
604 : Real drho_dp_T, drho_dT;
605 1 : rho_from_p_T(p, T, rho, drho_dp_T, drho_dT);
606 1 : drho_dp = drho_dT * dT_dp + drho_dp_T;
607 1 : drho_ds = drho_dT * dT_ds;
608 1 : }
609 :
610 : Real
611 328 : TabulatedFluidProperties::e_from_p_T(Real pressure, Real temperature) const
612 : {
613 328 : if (_interpolate_internal_energy)
614 : {
615 242 : checkInputVariables(pressure, temperature);
616 242 : if (_create_direct_pT_interpolations)
617 242 : return _property_ipol[_internal_energy_idx]->sample(pressure, temperature);
618 : else
619 0 : NeedTabulationError("internal_energy");
620 : }
621 86 : else if (_create_direct_ve_interpolations)
622 : {
623 85 : checkInputVariables(pressure, temperature);
624 85 : const Real rho = rho_from_p_T(pressure, temperature);
625 : auto lambda = [&](Real v, Real current_e, Real & new_T, Real & dT_dv, Real & dT_de)
626 143 : { T_from_v_e(v, current_e, new_T, dT_dv, dT_de); };
627 85 : const auto pair = FluidPropertiesUtils::NewtonSolve(1. / rho,
628 : temperature,
629 85 : /*initial guess*/ (_e_min + _e_max) / 2,
630 85 : _tolerance,
631 : lambda,
632 85 : name() + "::e_from_p_T",
633 85 : _max_newton_its,
634 85 : _verbose_newton);
635 85 : return pair.first;
636 : }
637 : else
638 : {
639 1 : if (_fp)
640 1 : return _fp->e_from_p_T(pressure, temperature);
641 : else
642 0 : NeedTabulationOrFPError("e_from_p_T", "internal_energy");
643 : }
644 : }
645 :
646 : ADReal
647 5 : TabulatedFluidProperties::e_from_p_T(const ADReal & pressure, const ADReal & temperature) const
648 : {
649 5 : if (_interpolate_internal_energy)
650 : {
651 1 : ADReal pressure_nc = pressure, temperature_nc = temperature;
652 1 : checkInputVariables(pressure_nc, temperature_nc);
653 1 : if (_create_direct_pT_interpolations)
654 1 : return _property_ipol[_internal_energy_idx]->sample(pressure_nc, temperature_nc);
655 : else
656 0 : NeedTabulationError("internal_energy");
657 : }
658 4 : else if (_create_direct_ve_interpolations)
659 : {
660 1 : ADReal pressure_nc = pressure, temperature_nc = temperature;
661 1 : checkInputVariables(pressure_nc, temperature_nc);
662 1 : const ADReal rho = rho_from_p_T(pressure_nc, temperature_nc);
663 : auto lambda = [&](ADReal v, ADReal current_e, ADReal & new_T, ADReal & dT_dv, ADReal & dT_de)
664 2 : { T_from_v_e(v, current_e, new_T, dT_dv, dT_de); };
665 1 : const auto pair = FluidPropertiesUtils::NewtonSolve(1. / rho,
666 : temperature_nc,
667 1 : /*initial guess*/ (_e_min + _e_max) / 2,
668 1 : _tolerance,
669 : lambda,
670 1 : name() + "::e_from_p_T",
671 1 : _max_newton_its,
672 2 : _verbose_newton);
673 1 : return pair.first;
674 : }
675 : else
676 : {
677 3 : if (_fp)
678 3 : return _fp->e_from_p_T(pressure, temperature);
679 : else
680 0 : NeedTabulationOrFPError("AD e_from_p_T", "internal_energy");
681 : }
682 : }
683 :
684 : void
685 6273004 : TabulatedFluidProperties::e_from_p_T(
686 : Real pressure, Real temperature, Real & e, Real & de_dp, Real & de_dT) const
687 : {
688 6273004 : if (_interpolate_internal_energy)
689 : {
690 6272976 : checkInputVariables(pressure, temperature);
691 6272976 : if (_create_direct_pT_interpolations)
692 6272976 : _property_ipol[_internal_energy_idx]->sampleValueAndDerivatives(
693 : pressure, temperature, e, de_dp, de_dT);
694 : else
695 0 : NeedTabulationError("internal_energy");
696 : }
697 28 : else if (_create_direct_ve_interpolations)
698 : {
699 26 : checkInputVariables(pressure, temperature);
700 : // use finite differencing stencil
701 26 : e = e_from_p_T(pressure, temperature);
702 : Real eps = 1e-8;
703 26 : de_dp = (e_from_p_T(pressure * (1 + eps), temperature) - e) / (eps * pressure);
704 26 : de_dT = (e_from_p_T(pressure, temperature * (1 + eps)) - e) / (eps * temperature);
705 : }
706 : else
707 : {
708 2 : if (_fp)
709 2 : _fp->e_from_p_T(pressure, temperature, e, de_dp, de_dT);
710 : else
711 0 : NeedTabulationOrFPError("e_from_p_T with derivatives", "internal_energy");
712 : }
713 6273004 : }
714 :
715 : ADReal
716 1 : TabulatedFluidProperties::e_from_p_rho(const ADReal & pressure, const ADReal & rho) const
717 : {
718 : ADReal e;
719 : // Use v,e data, we already have v from rho
720 1 : if (_create_direct_ve_interpolations)
721 : {
722 : auto lambda = [&](ADReal v, ADReal current_e, ADReal & new_p, ADReal & dp_dv, ADReal & dp_de)
723 2 : { p_from_v_e(v, current_e, new_p, dp_dv, dp_de); };
724 1 : const auto pair = FluidPropertiesUtils::NewtonSolve(1. / rho,
725 : pressure,
726 1 : /*initial guess*/ (_e_min + _e_max) / 2,
727 1 : _tolerance,
728 : lambda,
729 1 : name() + "::e_from_p_rho",
730 1 : _max_newton_its,
731 2 : _verbose_newton);
732 1 : e = pair.first;
733 : }
734 : // May use rho_from_p_T with derivatives in a Newton solve
735 : else
736 : {
737 0 : const auto T = T_from_p_rho(pressure, rho);
738 0 : e = e_from_p_T(pressure, T);
739 : }
740 1 : return e;
741 : }
742 :
743 : Real
744 90 : TabulatedFluidProperties::e_from_p_rho(Real pressure, Real rho) const
745 : {
746 : Real e;
747 : // Use v,e data, we already have v from rho
748 90 : if (_create_direct_ve_interpolations)
749 : {
750 84 : Real T_dummy = _T_initial_guess;
751 84 : checkInputVariables(pressure, T_dummy);
752 : auto lambda = [&](Real v, Real current_e, Real & new_p, Real & dp_dv, Real & dp_de)
753 141 : { p_from_v_e(v, current_e, new_p, dp_dv, dp_de); };
754 84 : const auto pair = FluidPropertiesUtils::NewtonSolve(1. / rho,
755 : pressure,
756 84 : /*initial guess*/ (_e_min + _e_max) / 2,
757 84 : _tolerance,
758 : lambda,
759 84 : name() + "::e_from_p_rho",
760 84 : _max_newton_its,
761 84 : _verbose_newton);
762 84 : e = pair.first;
763 : }
764 : // May use rho_from_p_T with derivatives in a Newton solve
765 : else
766 : {
767 6 : Real T = T_from_p_rho(pressure, rho);
768 6 : e = e_from_p_T(pressure, T);
769 : }
770 90 : return e;
771 : }
772 :
773 : void
774 26 : TabulatedFluidProperties::e_from_p_rho(
775 : Real pressure, Real rho, Real & e, Real & de_dp, Real & de_drho) const
776 : {
777 : // get derivatives of T wrt to pressure and density
778 : Real T, dT_dp, dT_drho;
779 26 : T_from_p_rho(pressure, rho, T, dT_dp, dT_drho);
780 :
781 : // Get e, then derivatives of e wrt pressure and temperature
782 : Real de_dp_at_const_T, de_dT;
783 26 : e_from_p_T(pressure, T, e, de_dp_at_const_T, de_dT);
784 :
785 : // Get the derivatives of density wrt pressure and temperature
786 : Real rho_pT, drho_dp, drho_dT;
787 26 : rho_from_p_T(pressure, T, rho_pT, drho_dp, drho_dT);
788 :
789 : // derivatives of e wrt pressure and rho (what we want from e_from_p_rho)
790 26 : de_drho = de_dT * dT_drho;
791 26 : de_dp = de_dp_at_const_T - (de_drho * drho_dp);
792 26 : }
793 :
794 : Real
795 98 : TabulatedFluidProperties::T_from_p_rho(Real pressure, Real rho) const
796 : {
797 98 : Real T = _T_initial_guess;
798 98 : if (_interpolate_density && _create_direct_pT_interpolations)
799 : {
800 17 : checkInputVariables(pressure, T);
801 : auto lambda = [&](Real p, Real current_T, Real & new_rho, Real & drho_dp, Real & drho_dT)
802 49 : { rho_from_p_T(p, current_T, new_rho, drho_dp, drho_dT); };
803 51 : T = FluidPropertiesUtils::NewtonSolve(pressure,
804 : rho,
805 17 : _T_initial_guess,
806 17 : _tolerance,
807 : lambda,
808 17 : name() + "::T_from_p_rho",
809 17 : _max_newton_its,
810 17 : _verbose_newton)
811 17 : .first;
812 17 : }
813 81 : else if (_create_direct_ve_interpolations)
814 81 : T = T_from_v_e(1. / rho, e_from_p_rho(pressure, rho));
815 : else
816 0 : NeedTabulationOrFPError("T_from_p_rho", "temperature");
817 : // check for nans
818 98 : if (std::isnan(T))
819 0 : mooseError("Conversion from pressure (p = ",
820 : pressure,
821 : ") and density (rho = ",
822 : rho,
823 : ") to temperature failed to converge.");
824 98 : return T;
825 : }
826 :
827 : ADReal
828 1 : TabulatedFluidProperties::T_from_p_rho(const ADReal & pressure, const ADReal & rho) const
829 : {
830 1 : if (_interpolate_density)
831 : {
832 : auto lambda =
833 : [&](ADReal p, ADReal current_T, ADReal & new_rho, ADReal & drho_dp, ADReal & drho_dT)
834 4 : { rho_from_p_T(p, current_T, new_rho, drho_dp, drho_dT); };
835 3 : ADReal T = FluidPropertiesUtils::NewtonSolve(pressure,
836 : rho,
837 1 : _T_initial_guess,
838 1 : _tolerance,
839 : lambda,
840 1 : name() + "::T_from_p_rho",
841 1 : _max_newton_its,
842 1 : _verbose_newton)
843 1 : .first;
844 : // check for nans
845 1 : if (std::isnan(T.value()))
846 0 : mooseError("Conversion from pressure (p = ",
847 : pressure,
848 : ") and density (rho = ",
849 : rho,
850 : ") to temperature failed to converge.");
851 1 : return T;
852 : }
853 0 : else if (_create_direct_ve_interpolations)
854 0 : return T_from_v_e(1. / rho, e_from_p_rho(pressure, rho));
855 : else
856 0 : NeedTabulationOrFPError("AD T_from_p_rho", "temperature");
857 : }
858 :
859 : void
860 28 : TabulatedFluidProperties::T_from_p_rho(
861 : Real pressure, Real rho, Real & T, Real & dT_dp, Real & dT_drho) const
862 : {
863 28 : T = T_from_p_rho(pressure, rho);
864 : Real eps = 1e-8;
865 28 : dT_dp = (T_from_p_rho(pressure * (1 + eps), rho) - T) / (eps * pressure);
866 28 : dT_drho = (T_from_p_rho(pressure, rho * (1 + eps)) - T) / (eps * rho);
867 28 : }
868 :
869 : Real
870 21 : TabulatedFluidProperties::T_from_p_s(Real pressure, Real s) const
871 : {
872 : auto lambda = [&](Real p, Real current_T, Real & new_s, Real & ds_dp, Real & ds_dT)
873 62 : { s_from_p_T(p, current_T, new_s, ds_dp, ds_dT); };
874 42 : Real T = FluidPropertiesUtils::NewtonSolve(pressure,
875 : s,
876 21 : _T_initial_guess,
877 21 : _tolerance,
878 : lambda,
879 21 : name() + "::T_from_p_s",
880 21 : _max_newton_its,
881 21 : _verbose_newton)
882 21 : .first;
883 : // check for nans
884 21 : if (std::isnan(T))
885 0 : mooseError("Conversion from pressure (p = ",
886 : pressure,
887 : ") and entropy (s = ",
888 : s,
889 : ") to temperature failed to converge.");
890 21 : return T;
891 : }
892 :
893 : void
894 2 : TabulatedFluidProperties::T_from_p_s(
895 : Real pressure, Real s, Real & T, Real & dT_dp, Real & dT_ds) const
896 : {
897 2 : T = T_from_p_s(pressure, s);
898 : Real eps = 1e-8;
899 2 : dT_dp = (T_from_p_s(pressure * (1 + eps), s) - T) / (eps * pressure);
900 2 : dT_ds = (T_from_p_s(pressure, s * (1 + eps)) - T) / (eps * s);
901 2 : }
902 :
903 : Real
904 534 : TabulatedFluidProperties::h_from_p_T(Real pressure, Real temperature) const
905 : {
906 534 : if (_interpolate_enthalpy)
907 : {
908 533 : checkInputVariables(pressure, temperature);
909 533 : if (_create_direct_pT_interpolations)
910 530 : return _property_ipol[_enthalpy_idx]->sample(pressure, temperature);
911 3 : else if (_create_direct_ve_interpolations)
912 : {
913 : Real v, e;
914 3 : SinglePhaseFluidProperties::v_e_from_p_T(pressure, temperature, v, e);
915 3 : return _property_ve_ipol[_enthalpy_idx]->sample(v, e);
916 : }
917 : else
918 0 : NeedTabulationError("enthalpy");
919 : }
920 : else
921 : {
922 1 : if (_fp)
923 1 : return _fp->h_from_p_T(pressure, temperature);
924 : else
925 0 : NeedTabulationOrFPError("h_from_p_T", "enthalpy");
926 : }
927 : }
928 :
929 : ADReal
930 0 : TabulatedFluidProperties::h_from_p_T(const ADReal & pressure, const ADReal & temperature) const
931 : {
932 0 : if (_interpolate_enthalpy)
933 : {
934 0 : ADReal pressure_nc = pressure, temperature_nc = temperature;
935 0 : checkInputVariables(pressure_nc, temperature_nc);
936 0 : if (_create_direct_pT_interpolations)
937 0 : return _property_ipol[_enthalpy_idx]->sample(pressure_nc, temperature_nc);
938 0 : else if (_create_direct_ve_interpolations)
939 : {
940 : ADReal v, e;
941 0 : SinglePhaseFluidProperties::v_e_from_p_T(pressure_nc, temperature_nc, v, e);
942 0 : return _property_ve_ipol[_enthalpy_idx]->sample(v, e);
943 : }
944 : else
945 0 : NeedTabulationError("enthalpy");
946 : }
947 0 : else if (_fp) // Assuming _fp can handle ADReal types
948 0 : return _fp->h_from_p_T(pressure, temperature);
949 : else
950 0 : NeedTabulationOrFPError("AD h_from_p_T", "enthalpy");
951 : }
952 :
953 : void
954 6414192 : TabulatedFluidProperties::h_from_p_T(
955 : Real pressure, Real temperature, Real & h, Real & dh_dp, Real & dh_dT) const
956 : {
957 6414192 : if (_interpolate_enthalpy)
958 : {
959 6414192 : checkInputVariables(pressure, temperature);
960 6414192 : if (_create_direct_pT_interpolations)
961 6414180 : _property_ipol[_enthalpy_idx]->sampleValueAndDerivatives(
962 : pressure, temperature, h, dh_dp, dh_dT);
963 12 : else if (_create_direct_ve_interpolations)
964 : {
965 : Real v, e, dv_dp, dv_dT, de_dp, de_dT;
966 12 : SinglePhaseFluidProperties::v_e_from_p_T(
967 : pressure, temperature, v, dv_dp, dv_dT, e, de_dp, de_dT);
968 : Real dh_dv, dh_de;
969 12 : _property_ve_ipol[_enthalpy_idx]->sampleValueAndDerivatives(v, e, h, dh_dv, dh_de);
970 12 : dh_dp = dh_dv * dv_dp + dh_de * de_dp;
971 12 : dh_dT = dh_dv * dv_dT + dh_de * de_dT;
972 : }
973 : else
974 0 : NeedTabulationError("enthalpy");
975 : }
976 : else
977 : {
978 0 : if (_fp)
979 0 : _fp->h_from_p_T(pressure, temperature, h, dh_dp, dh_dT);
980 : else
981 0 : NeedTabulationOrFPError("h_from_p_T with derivatives", "enthalpy");
982 : }
983 6414192 : }
984 :
985 : Real
986 251 : TabulatedFluidProperties::mu_from_p_T(Real pressure, Real temperature) const
987 : {
988 251 : if (_interpolate_viscosity && _create_direct_pT_interpolations)
989 : {
990 249 : checkInputVariables(pressure, temperature);
991 249 : return _property_ipol[_viscosity_idx]->sample(pressure, temperature);
992 : }
993 : else
994 : {
995 2 : if (_fp)
996 2 : return _fp->mu_from_p_T(pressure, temperature);
997 : else
998 0 : NeedTabulationOrFPError("mu_from_p_T", "viscosity");
999 : }
1000 : }
1001 :
1002 : void
1003 7 : TabulatedFluidProperties::mu_from_p_T(
1004 : Real pressure, Real temperature, Real & mu, Real & dmu_dp, Real & dmu_dT) const
1005 : {
1006 7 : if (_interpolate_viscosity && _create_direct_pT_interpolations)
1007 : {
1008 5 : checkInputVariables(pressure, temperature);
1009 5 : _property_ipol[_viscosity_idx]->sampleValueAndDerivatives(
1010 : pressure, temperature, mu, dmu_dp, dmu_dT);
1011 : }
1012 : else
1013 : {
1014 2 : if (_fp)
1015 2 : _fp->mu_from_p_T(pressure, temperature, mu, dmu_dp, dmu_dT);
1016 : else
1017 0 : NeedTabulationOrFPError("mu_from_p_T with derivatives", "viscosity");
1018 : }
1019 7 : }
1020 :
1021 : Real
1022 231 : TabulatedFluidProperties::c_from_p_T(Real pressure, Real temperature) const
1023 : {
1024 231 : if (_interpolate_c && _create_direct_pT_interpolations)
1025 : {
1026 231 : checkInputVariables(pressure, temperature);
1027 231 : return _property_ipol[_c_idx]->sample(pressure, temperature);
1028 : }
1029 : else
1030 : {
1031 0 : if (_fp)
1032 0 : return _fp->c_from_p_T(pressure, temperature);
1033 : else
1034 0 : NeedTabulationOrFPError("c_from_p_T", "c");
1035 : }
1036 : }
1037 :
1038 : void
1039 0 : TabulatedFluidProperties::c_from_p_T(
1040 : Real pressure, Real temperature, Real & c, Real & dc_dp, Real & dc_dT) const
1041 : {
1042 0 : if (_interpolate_c && _create_direct_pT_interpolations)
1043 : {
1044 0 : checkInputVariables(pressure, temperature);
1045 0 : _property_ipol[_c_idx]->sampleValueAndDerivatives(pressure, temperature, c, dc_dp, dc_dT);
1046 : }
1047 : else
1048 : {
1049 0 : if (_fp)
1050 0 : _fp->c_from_p_T(pressure, temperature, c, dc_dp, dc_dT);
1051 : else
1052 0 : NeedTabulationOrFPError("c_from_p_T with derivatives", "c");
1053 : }
1054 0 : }
1055 :
1056 : Real
1057 394 : TabulatedFluidProperties::cp_from_p_T(Real pressure, Real temperature) const
1058 : {
1059 394 : if (_interpolate_cp && _create_direct_pT_interpolations)
1060 : {
1061 248 : checkInputVariables(pressure, temperature);
1062 248 : return _property_ipol[_cp_idx]->sample(pressure, temperature);
1063 : }
1064 : else
1065 : {
1066 146 : if (_fp)
1067 146 : return _fp->cp_from_p_T(pressure, temperature);
1068 : else
1069 0 : NeedTabulationOrFPError("cp_from_p_T", "c");
1070 : }
1071 : }
1072 :
1073 : void
1074 7 : TabulatedFluidProperties::cp_from_p_T(
1075 : Real pressure, Real temperature, Real & cp, Real & dcp_dp, Real & dcp_dT) const
1076 : {
1077 7 : if (_interpolate_cp && _create_direct_pT_interpolations)
1078 : {
1079 4 : checkInputVariables(pressure, temperature);
1080 4 : _property_ipol[_cp_idx]->sampleValueAndDerivatives(pressure, temperature, cp, dcp_dp, dcp_dT);
1081 : }
1082 : else
1083 : {
1084 3 : if (_fp)
1085 3 : _fp->cp_from_p_T(pressure, temperature, cp, dcp_dp, dcp_dT);
1086 : else
1087 0 : NeedTabulationOrFPError("cp_from_p_T with derivatives", "cp");
1088 : }
1089 7 : }
1090 :
1091 : Real
1092 250 : TabulatedFluidProperties::cv_from_p_T(Real pressure, Real temperature) const
1093 : {
1094 250 : if (_interpolate_cv && _create_direct_pT_interpolations)
1095 : {
1096 248 : checkInputVariables(pressure, temperature);
1097 248 : return _property_ipol[_cv_idx]->sample(pressure, temperature);
1098 : }
1099 : else
1100 : {
1101 2 : if (_fp)
1102 2 : return _fp->cv_from_p_T(pressure, temperature);
1103 : else
1104 0 : NeedTabulationOrFPError("cv_from_p_T", "cv");
1105 : }
1106 : }
1107 :
1108 : void
1109 4 : TabulatedFluidProperties::cv_from_p_T(
1110 : Real pressure, Real temperature, Real & cv, Real & dcv_dp, Real & dcv_dT) const
1111 : {
1112 4 : if (_interpolate_cv)
1113 : {
1114 4 : checkInputVariables(pressure, temperature);
1115 4 : _property_ipol[_cv_idx]->sampleValueAndDerivatives(pressure, temperature, cv, dcv_dp, dcv_dT);
1116 : }
1117 : else
1118 : {
1119 0 : if (_fp)
1120 0 : _fp->cv_from_p_T(pressure, temperature, cv, dcv_dp, dcv_dT);
1121 : else
1122 0 : NeedTabulationOrFPError("cv_from_p_T with derivatives", "cv");
1123 : }
1124 4 : }
1125 :
1126 : Real
1127 250 : TabulatedFluidProperties::k_from_p_T(Real pressure, Real temperature) const
1128 : {
1129 250 : if (_interpolate_k && _create_direct_pT_interpolations)
1130 : {
1131 248 : checkInputVariables(pressure, temperature);
1132 248 : return _property_ipol[_k_idx]->sample(pressure, temperature);
1133 : }
1134 : else
1135 : {
1136 2 : if (_fp)
1137 2 : return _fp->k_from_p_T(pressure, temperature);
1138 : else
1139 0 : NeedTabulationOrFPError("k_from_p_T", "k");
1140 : }
1141 : }
1142 :
1143 : void
1144 5 : TabulatedFluidProperties::k_from_p_T(
1145 : Real pressure, Real temperature, Real & k, Real & dk_dp, Real & dk_dT) const
1146 : {
1147 5 : if (_interpolate_k && _create_direct_pT_interpolations)
1148 : {
1149 4 : checkInputVariables(pressure, temperature);
1150 4 : return _property_ipol[_k_idx]->sampleValueAndDerivatives(
1151 4 : pressure, temperature, k, dk_dp, dk_dT);
1152 : }
1153 : else
1154 : {
1155 1 : if (_fp)
1156 1 : return _fp->k_from_p_T(pressure, temperature, k, dk_dp, dk_dT);
1157 : else
1158 0 : NeedTabulationOrFPError("k_from_p_T with derivatives", "k");
1159 : }
1160 : }
1161 :
1162 : Real
1163 259 : TabulatedFluidProperties::s_from_p_T(Real pressure, Real temperature) const
1164 : {
1165 259 : if (_interpolate_entropy && _create_direct_pT_interpolations)
1166 : {
1167 251 : checkInputVariables(pressure, temperature);
1168 251 : return _property_ipol[_entropy_idx]->sample(pressure, temperature);
1169 : }
1170 : else
1171 : {
1172 8 : if (_fp)
1173 8 : return _fp->s_from_p_T(pressure, temperature);
1174 : else
1175 0 : NeedTabulationOrFPError("s_from_p_T", "entropy");
1176 : }
1177 : }
1178 :
1179 : void
1180 63 : TabulatedFluidProperties::s_from_p_T(Real p, Real T, Real & s, Real & ds_dp, Real & ds_dT) const
1181 : {
1182 63 : if (_interpolate_entropy)
1183 : {
1184 62 : checkInputVariables(p, T);
1185 62 : if (_create_direct_pT_interpolations)
1186 50 : _property_ipol[_entropy_idx]->sampleValueAndDerivatives(p, T, s, ds_dp, ds_dT);
1187 12 : else if (_create_direct_ve_interpolations)
1188 : {
1189 : Real v, e, dv_dp, dv_dT, de_dp, de_dT;
1190 12 : SinglePhaseFluidProperties::v_e_from_p_T(p, T, v, dv_dp, dv_dT, e, de_dp, de_dT);
1191 : Real ds_dv, ds_de;
1192 12 : _property_ve_ipol[_entropy_idx]->sampleValueAndDerivatives(v, e, s, ds_dv, ds_de);
1193 12 : ds_dp = ds_dv * dv_dp + ds_de * de_dp;
1194 12 : ds_dT = ds_dv * dv_dT + ds_de * de_dT;
1195 : }
1196 : else
1197 0 : NeedTabulationError("entropy");
1198 : }
1199 : else
1200 : {
1201 1 : if (_fp)
1202 1 : _fp->s_from_p_T(p, T, s, ds_dp, ds_dT);
1203 : else
1204 0 : NeedTabulationOrFPError("s_from_p_T with derivatives", "entropy");
1205 : }
1206 63 : }
1207 :
1208 : Real
1209 15 : TabulatedFluidProperties::e_from_v_h(Real v, Real h) const
1210 : {
1211 15 : if (_construct_pT_from_vh)
1212 : {
1213 4 : const Real p = _p_from_v_h_ipol->sample(v, h);
1214 4 : const Real T = _T_from_v_h_ipol->sample(v, h);
1215 4 : return e_from_p_T(p, T);
1216 : }
1217 11 : else if (_create_direct_ve_interpolations)
1218 : {
1219 : // Lambda computes h from v and the current_e
1220 : auto lambda = [&](Real v, Real current_e, Real & new_h, Real & dh_dv, Real & dh_de)
1221 26 : { h_from_v_e(v, current_e, new_h, dh_dv, dh_de); };
1222 22 : Real e = FluidPropertiesUtils::NewtonSolve(v,
1223 : h,
1224 11 : /*e initial guess*/ h - _p_initial_guess * v,
1225 11 : _tolerance,
1226 : lambda,
1227 22 : name() + "::e_from_v_h",
1228 11 : _max_newton_its,
1229 11 : _verbose_newton)
1230 11 : .first;
1231 : return e;
1232 : }
1233 0 : else if (_fp)
1234 0 : return _fp->e_from_v_h(v, h);
1235 : else
1236 0 : NeedTabulationOrFPError("e_from_v_h", "internal_energy");
1237 : }
1238 :
1239 : void
1240 3 : TabulatedFluidProperties::e_from_v_h(Real v, Real h, Real & e, Real & de_dv, Real & de_dh) const
1241 : {
1242 3 : if (_construct_pT_from_vh)
1243 : {
1244 1 : Real p = 0, dp_dv = 0, dp_dh = 0;
1245 1 : _p_from_v_h_ipol->sampleValueAndDerivatives(v, h, p, dp_dv, dp_dh);
1246 1 : Real T = 0, dT_dv = 0, dT_dh = 0;
1247 1 : _T_from_v_h_ipol->sampleValueAndDerivatives(v, h, T, dT_dv, dT_dh);
1248 : Real de_dp, de_dT;
1249 1 : e_from_p_T(p, T, e, de_dp, de_dT);
1250 1 : de_dv = de_dp * dp_dv + de_dT * dT_dv;
1251 1 : de_dh = de_dp * dp_dh + de_dT * dT_dh;
1252 : }
1253 2 : else if (_create_direct_ve_interpolations)
1254 : {
1255 : // Lambda computes h from v and the current_e
1256 : auto lambda = [&](Real v, Real current_e, Real & new_h, Real & dh_dv, Real & dh_de)
1257 4 : { h_from_v_e(v, current_e, new_h, dh_dv, dh_de); };
1258 : const auto e_data =
1259 4 : FluidPropertiesUtils::NewtonSolve(v,
1260 : h,
1261 2 : /*e initial guess*/ h - _p_initial_guess * v,
1262 2 : _tolerance,
1263 : lambda,
1264 2 : name() + "::e_from_v_h",
1265 2 : _max_newton_its,
1266 2 : _verbose_newton);
1267 2 : e = e_data.first;
1268 : // Finite difference approximation
1269 2 : const auto e2 = e_from_v_h(v * (1 + TOLERANCE), h);
1270 2 : de_dv = (e2 - e) / (TOLERANCE * v);
1271 2 : de_dh = 1. / e_data.second;
1272 : }
1273 0 : else if (_fp)
1274 0 : _fp->e_from_v_h(v, h, e, de_dv, de_dh);
1275 : else
1276 0 : NeedTabulationOrFPError("e_from_v_h", "internal_energy");
1277 3 : }
1278 :
1279 : std::vector<Real>
1280 3 : TabulatedFluidProperties::henryCoefficients() const
1281 : {
1282 3 : if (_fp)
1283 3 : return _fp->henryCoefficients();
1284 : else
1285 0 : TabulationNotImplementedError("henryCoefficients");
1286 : }
1287 :
1288 : Real
1289 1 : TabulatedFluidProperties::vaporPressure(Real temperature) const
1290 : {
1291 1 : if (_fp)
1292 1 : return _fp->vaporPressure(temperature);
1293 : else
1294 0 : TabulationNotImplementedError("vaporPressure");
1295 : }
1296 :
1297 : void
1298 0 : TabulatedFluidProperties::vaporPressure(Real temperature, Real & psat, Real & dpsat_dT) const
1299 : {
1300 0 : if (_fp)
1301 0 : _fp->vaporPressure(temperature, psat, dpsat_dT);
1302 : else
1303 0 : TabulationNotImplementedError("vaporPressure");
1304 0 : }
1305 :
1306 : Real
1307 0 : TabulatedFluidProperties::vaporTemperature(Real pressure) const
1308 : {
1309 0 : if (_fp)
1310 0 : return _fp->vaporTemperature(pressure);
1311 : else
1312 0 : TabulationNotImplementedError("vaporTemperature");
1313 : }
1314 :
1315 : void
1316 0 : TabulatedFluidProperties::vaporTemperature(Real pressure, Real & Tsat, Real & dTsat_dp) const
1317 : {
1318 :
1319 0 : if (_fp)
1320 0 : _fp->vaporTemperature(pressure, Tsat, dTsat_dp);
1321 : else
1322 0 : TabulationNotImplementedError("vaporTemperature");
1323 0 : }
1324 :
1325 : Real
1326 1 : TabulatedFluidProperties::triplePointPressure() const
1327 : {
1328 :
1329 1 : if (_fp)
1330 1 : return _fp->triplePointPressure();
1331 : else
1332 0 : TabulationNotImplementedError("triplePointPressure");
1333 : }
1334 :
1335 : Real
1336 1 : TabulatedFluidProperties::triplePointTemperature() const
1337 : {
1338 :
1339 1 : if (_fp)
1340 1 : return _fp->triplePointTemperature();
1341 : else
1342 0 : TabulationNotImplementedError("triplePointTemperature");
1343 : }
1344 :
1345 : Real
1346 1 : TabulatedFluidProperties::criticalPressure() const
1347 : {
1348 :
1349 1 : if (_fp)
1350 1 : return _fp->criticalPressure();
1351 : else
1352 0 : TabulationNotImplementedError("criticalPressure");
1353 : }
1354 :
1355 : Real
1356 1 : TabulatedFluidProperties::criticalTemperature() const
1357 : {
1358 :
1359 1 : if (_fp)
1360 1 : return _fp->criticalTemperature();
1361 : else
1362 0 : TabulationNotImplementedError("criticalTemperature");
1363 : }
1364 :
1365 : Real
1366 1 : TabulatedFluidProperties::criticalDensity() const
1367 : {
1368 1 : if (_fp)
1369 1 : return _fp->criticalDensity();
1370 : else
1371 0 : TabulationNotImplementedError("criticalDensity");
1372 : }
1373 :
1374 : Real
1375 1252 : TabulatedFluidProperties::p_from_v_e(Real v, Real e) const
1376 : {
1377 1252 : if (_interpolate_pressure && !_construct_pT_from_ve && !_create_direct_ve_interpolations)
1378 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1379 1252 : checkInputVariablesVE(v, e);
1380 :
1381 1252 : if (_create_direct_ve_interpolations && _interpolate_pressure)
1382 1229 : return _property_ve_ipol[_p_idx]->sample(v, e);
1383 23 : else if (_construct_pT_from_ve)
1384 23 : return _p_from_v_e_ipol->sample(v, e);
1385 0 : else if (_fp)
1386 0 : return _fp->p_from_v_e(v, e);
1387 : else
1388 0 : NeedTabulationOrFPError("p_from_v_e", "pressure");
1389 : }
1390 :
1391 : void
1392 1150 : TabulatedFluidProperties::p_from_v_e(Real v, Real e, Real & p, Real & dp_dv, Real & dp_de) const
1393 : {
1394 1150 : if (_interpolate_pressure && !_construct_pT_from_ve && !_create_direct_ve_interpolations)
1395 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1396 1150 : checkInputVariablesVE(v, e);
1397 :
1398 1150 : if (_create_direct_ve_interpolations && _interpolate_pressure)
1399 1146 : _property_ve_ipol[_p_idx]->sampleValueAndDerivatives(v, e, p, dp_dv, dp_de);
1400 4 : else if (_construct_pT_from_ve)
1401 4 : _p_from_v_e_ipol->sampleValueAndDerivatives(v, e, p, dp_dv, dp_de);
1402 0 : else if (_fp)
1403 0 : _fp->p_from_v_e(v, e, p, dp_dv, dp_de);
1404 : else
1405 0 : NeedTabulationOrFPError("p_from_v_e with derivatives", "pressure");
1406 1150 : }
1407 :
1408 : void
1409 11 : TabulatedFluidProperties::p_from_v_e(
1410 : const ADReal & v, const ADReal & e, ADReal & p, ADReal & dp_dv, ADReal & dp_de) const
1411 : {
1412 11 : if (_interpolate_pressure && !_construct_pT_from_ve && !_create_direct_ve_interpolations)
1413 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1414 11 : ADReal vc = v, ec = e;
1415 11 : checkInputVariablesVE(vc, ec);
1416 :
1417 11 : if (_create_direct_ve_interpolations && _interpolate_pressure)
1418 10 : _property_ve_ipol[_p_idx]->sampleValueAndDerivatives(vc, ec, p, dp_dv, dp_de);
1419 1 : else if (_construct_pT_from_ve)
1420 1 : _p_from_v_e_ipol->sampleValueAndDerivatives(vc, ec, p, dp_dv, dp_de);
1421 0 : else if (_fp)
1422 0 : _fp->p_from_v_e(vc, ec, p, dp_dv, dp_de);
1423 : else
1424 0 : NeedTabulationOrFPError("AD p_from_v_e with derivatives", "pressure");
1425 11 : }
1426 :
1427 : Real
1428 727 : TabulatedFluidProperties::T_from_v_e(Real v, Real e) const
1429 : {
1430 727 : if (_interpolate_temperature && !_construct_pT_from_ve && !_create_direct_ve_interpolations)
1431 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1432 727 : checkInputVariablesVE(v, e);
1433 :
1434 727 : if (_create_direct_ve_interpolations && _interpolate_temperature)
1435 705 : return _property_ve_ipol[_T_idx]->sample(v, e);
1436 22 : else if (_construct_pT_from_ve)
1437 22 : return _T_from_v_e_ipol->sample(v, e);
1438 0 : else if (_fp)
1439 0 : return _fp->T_from_v_e(v, e);
1440 : else
1441 0 : NeedTabulationOrFPError("T_from_v_e", "temperature");
1442 : }
1443 :
1444 : void
1445 1122 : TabulatedFluidProperties::T_from_v_e(Real v, Real e, Real & T, Real & dT_dv, Real & dT_de) const
1446 : {
1447 1122 : if (_interpolate_temperature && !_construct_pT_from_ve && !_create_direct_ve_interpolations)
1448 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1449 1122 : checkInputVariablesVE(v, e);
1450 :
1451 1122 : if (_create_direct_ve_interpolations && _interpolate_temperature)
1452 1118 : _property_ve_ipol[_T_idx]->sampleValueAndDerivatives(v, e, T, dT_dv, dT_de);
1453 4 : else if (_construct_pT_from_ve)
1454 4 : _T_from_v_e_ipol->sampleValueAndDerivatives(v, e, T, dT_dv, dT_de);
1455 0 : else if (_fp)
1456 0 : _fp->T_from_v_e(v, e, T, dT_dv, dT_de);
1457 : else
1458 0 : NeedTabulationOrFPError("T_from_v_e with derivatives", "temperature");
1459 1122 : }
1460 :
1461 : void
1462 11 : TabulatedFluidProperties::T_from_v_e(
1463 : const ADReal & v, const ADReal & e, ADReal & T, ADReal & dT_dv, ADReal & dT_de) const
1464 : {
1465 11 : if (_interpolate_temperature && !_construct_pT_from_ve && !_create_direct_ve_interpolations)
1466 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1467 11 : ADReal vc = v, ec = e;
1468 11 : checkInputVariablesVE(vc, ec);
1469 :
1470 11 : if (_create_direct_ve_interpolations && _interpolate_temperature)
1471 10 : _property_ve_ipol[_T_idx]->sampleValueAndDerivatives(vc, ec, T, dT_dv, dT_de);
1472 1 : else if (_construct_pT_from_ve)
1473 1 : _T_from_v_e_ipol->sampleValueAndDerivatives(vc, ec, T, dT_dv, dT_de);
1474 0 : else if (_fp)
1475 0 : _fp->T_from_v_e(vc, ec, T, dT_dv, dT_de);
1476 : else
1477 0 : NeedTabulationOrFPError("AD T_from_v_e with derivatives", "temperature");
1478 11 : }
1479 :
1480 : Real
1481 627 : TabulatedFluidProperties::c_from_v_e(Real v, Real e) const
1482 : {
1483 627 : if (_interpolate_c && !_construct_pT_from_ve && !_create_direct_ve_interpolations)
1484 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1485 627 : checkInputVariablesVE(v, e);
1486 :
1487 627 : if (_create_direct_ve_interpolations && _interpolate_c)
1488 612 : return _property_ve_ipol[_c_idx]->sample(v, e);
1489 15 : else if (_construct_pT_from_ve)
1490 : {
1491 15 : Real p = _p_from_v_e_ipol->sample(v, e);
1492 15 : Real T = _T_from_v_e_ipol->sample(v, e);
1493 15 : return c_from_p_T(p, T);
1494 : }
1495 0 : else if (_fp)
1496 0 : return _fp->c_from_v_e(v, e);
1497 : else
1498 0 : NeedTabulationOrFPError("c_from_v_e", "c");
1499 : }
1500 :
1501 : void
1502 1 : TabulatedFluidProperties::c_from_v_e(Real v, Real e, Real & c, Real & dc_dv, Real & dc_de) const
1503 : {
1504 1 : if (_interpolate_c && !_construct_pT_from_ve && !_create_direct_ve_interpolations)
1505 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1506 1 : checkInputVariablesVE(v, e);
1507 :
1508 1 : if (_create_direct_ve_interpolations && _interpolate_c)
1509 1 : _property_ve_ipol[_c_idx]->sampleValueAndDerivatives(v, e, c, dc_dv, dc_de);
1510 0 : else if (_construct_pT_from_ve)
1511 : {
1512 : Real p, dp_dv, dp_de;
1513 0 : _p_from_v_e_ipol->sampleValueAndDerivatives(v, e, p, dp_dv, dp_de);
1514 : Real T, dT_dv, dT_de;
1515 0 : _T_from_v_e_ipol->sampleValueAndDerivatives(v, e, T, dT_dv, dT_de);
1516 : Real dc_dp, dc_dT;
1517 0 : c_from_p_T(p, T, c, dc_dp, dc_dT);
1518 0 : dc_dv = dc_dp * dp_dv + dc_dT * dT_dv;
1519 0 : dc_de = dc_dp * dp_de + dc_dT * dT_de;
1520 : }
1521 0 : else if (_fp)
1522 0 : _fp->c_from_v_e(v, e, c, dc_dv, dc_de);
1523 : else
1524 0 : NeedTabulationOrFPError("c_from_v_e with derivatives", "c");
1525 1 : }
1526 :
1527 : Real
1528 646 : TabulatedFluidProperties::cp_from_v_e(Real v, Real e) const
1529 : {
1530 646 : if (_interpolate_cp && !_construct_pT_from_ve && !_create_direct_ve_interpolations)
1531 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1532 646 : checkInputVariablesVE(v, e);
1533 :
1534 646 : if (_create_direct_ve_interpolations && _interpolate_cp)
1535 621 : return _property_ve_ipol[_cp_idx]->sample(v, e);
1536 25 : else if (_construct_pT_from_ve)
1537 : {
1538 25 : Real p = _p_from_v_e_ipol->sample(v, e);
1539 25 : Real T = _T_from_v_e_ipol->sample(v, e);
1540 25 : return cp_from_p_T(p, T);
1541 : }
1542 0 : else if (_fp)
1543 0 : return _fp->cp_from_v_e(v, e);
1544 : else
1545 0 : NeedTabulationOrFPError("cp_from_v_e", "cp");
1546 : }
1547 :
1548 : void
1549 6 : TabulatedFluidProperties::cp_from_v_e(Real v, Real e, Real & cp, Real & dcp_dv, Real & dcp_de) const
1550 : {
1551 6 : if (_interpolate_cp && !_construct_pT_from_ve && !_create_direct_ve_interpolations)
1552 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1553 6 : checkInputVariablesVE(v, e);
1554 :
1555 6 : if (_create_direct_ve_interpolations && _interpolate_cp)
1556 3 : _property_ve_ipol[_cp_idx]->sampleValueAndDerivatives(v, e, cp, dcp_dv, dcp_de);
1557 3 : else if (_construct_pT_from_ve)
1558 : {
1559 : Real p, dp_dv, dp_de;
1560 3 : _p_from_v_e_ipol->sampleValueAndDerivatives(v, e, p, dp_dv, dp_de);
1561 : Real T, dT_dv, dT_de;
1562 3 : _T_from_v_e_ipol->sampleValueAndDerivatives(v, e, T, dT_dv, dT_de);
1563 : Real dcp_dp, dcp_dT;
1564 3 : cp_from_p_T(p, T, cp, dcp_dp, dcp_dT);
1565 3 : dcp_dv = dcp_dp * dp_dv + dcp_dT * dT_dv;
1566 3 : dcp_de = dcp_dp * dp_de + dcp_dT * dT_de;
1567 : }
1568 0 : else if (_fp)
1569 0 : _fp->cp_from_v_e(v, e, cp, dcp_dv, dcp_de);
1570 : else
1571 0 : NeedTabulationOrFPError("cp_from_v_e with derivatives", "cp");
1572 6 : }
1573 :
1574 : Real
1575 646 : TabulatedFluidProperties::cv_from_v_e(Real v, Real e) const
1576 : {
1577 646 : if (_interpolate_cv && !_construct_pT_from_ve && !_create_direct_ve_interpolations)
1578 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1579 646 : checkInputVariablesVE(v, e);
1580 :
1581 646 : if (_create_direct_ve_interpolations && _interpolate_cv)
1582 621 : return _property_ve_ipol[_cv_idx]->sample(v, e);
1583 25 : else if (_construct_pT_from_ve)
1584 : {
1585 25 : Real p = _p_from_v_e_ipol->sample(v, e);
1586 25 : Real T = _T_from_v_e_ipol->sample(v, e);
1587 25 : return cv_from_p_T(p, T);
1588 : }
1589 0 : else if (_fp)
1590 0 : return _fp->cv_from_v_e(v, e);
1591 : else
1592 0 : NeedTabulationOrFPError("cv_from_v_e", "cv");
1593 : }
1594 :
1595 : void
1596 6 : TabulatedFluidProperties::cv_from_v_e(Real v, Real e, Real & cv, Real & dcv_dv, Real & dcv_de) const
1597 : {
1598 6 : if (_interpolate_cv && !_construct_pT_from_ve && !_create_direct_ve_interpolations)
1599 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1600 6 : checkInputVariablesVE(v, e);
1601 :
1602 6 : if (_create_direct_ve_interpolations && _interpolate_cv)
1603 3 : _property_ve_ipol[_cv_idx]->sampleValueAndDerivatives(v, e, cv, dcv_dv, dcv_de);
1604 3 : else if (_construct_pT_from_ve)
1605 : {
1606 : Real p, dp_dv, dp_de;
1607 3 : _p_from_v_e_ipol->sampleValueAndDerivatives(v, e, p, dp_dv, dp_de);
1608 : Real T, dT_dv, dT_de;
1609 3 : _T_from_v_e_ipol->sampleValueAndDerivatives(v, e, T, dT_dv, dT_de);
1610 : Real dcv_dp, dcv_dT;
1611 3 : cv_from_p_T(p, T, cv, dcv_dp, dcv_dT);
1612 3 : dcv_dv = dcv_dp * dp_dv + dcv_dT * dT_dv;
1613 3 : dcv_de = dcv_dp * dp_de + dcv_dT * dT_de;
1614 : }
1615 0 : else if (_fp)
1616 0 : _fp->cv_from_v_e(v, e, cv, dcv_dv, dcv_de);
1617 : else
1618 0 : NeedTabulationOrFPError("cv_from_v_e with derivatives", "cv");
1619 6 : }
1620 :
1621 : Real
1622 646 : TabulatedFluidProperties::mu_from_v_e(Real v, Real e) const
1623 : {
1624 646 : if (_interpolate_viscosity && !_construct_pT_from_ve && !_create_direct_ve_interpolations)
1625 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1626 646 : checkInputVariablesVE(v, e);
1627 :
1628 646 : if (_create_direct_ve_interpolations && _interpolate_viscosity)
1629 621 : return _property_ve_ipol[_viscosity_idx]->sample(v, e);
1630 25 : else if (_construct_pT_from_ve)
1631 : {
1632 25 : Real p = _p_from_v_e_ipol->sample(v, e);
1633 25 : Real T = _T_from_v_e_ipol->sample(v, e);
1634 25 : return mu_from_p_T(p, T);
1635 : }
1636 0 : else if (_fp)
1637 0 : return _fp->mu_from_v_e(v, e);
1638 : else
1639 0 : NeedTabulationOrFPError("mu_from_v_e", "viscosity");
1640 : }
1641 :
1642 : void
1643 6 : TabulatedFluidProperties::mu_from_v_e(Real v, Real e, Real & mu, Real & dmu_dv, Real & dmu_de) const
1644 : {
1645 6 : if (_interpolate_viscosity & !_construct_pT_from_ve && !_create_direct_ve_interpolations)
1646 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1647 6 : checkInputVariablesVE(v, e);
1648 :
1649 6 : if (_create_direct_ve_interpolations && _interpolate_viscosity)
1650 3 : _property_ve_ipol[_viscosity_idx]->sampleValueAndDerivatives(v, e, mu, dmu_dv, dmu_de);
1651 3 : else if (_construct_pT_from_ve)
1652 : {
1653 : Real p, dp_dv, dp_de;
1654 3 : _p_from_v_e_ipol->sampleValueAndDerivatives(v, e, p, dp_dv, dp_de);
1655 : Real T, dT_dv, dT_de;
1656 3 : _T_from_v_e_ipol->sampleValueAndDerivatives(v, e, T, dT_dv, dT_de);
1657 : Real dmu_dp, dmu_dT;
1658 3 : mu_from_p_T(p, T, mu, dmu_dp, dmu_dT);
1659 3 : dmu_dv = dmu_dp * dp_dv + dmu_dT * dT_dv;
1660 3 : dmu_de = dmu_dp * dp_de + dmu_dT * dT_de;
1661 : }
1662 0 : else if (_fp)
1663 0 : _fp->mu_from_v_e(v, e, mu, dmu_dv, dmu_de);
1664 : else
1665 0 : NeedTabulationOrFPError("mu_from_v_e with derivatives", "viscosity");
1666 6 : }
1667 :
1668 : Real
1669 646 : TabulatedFluidProperties::k_from_v_e(Real v, Real e) const
1670 : {
1671 646 : if (_interpolate_k && !_construct_pT_from_ve && !_create_direct_ve_interpolations)
1672 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1673 646 : checkInputVariablesVE(v, e);
1674 :
1675 646 : if (_create_direct_ve_interpolations && _interpolate_k)
1676 621 : return _property_ve_ipol[_k_idx]->sample(v, e);
1677 25 : else if (_construct_pT_from_ve)
1678 : {
1679 25 : Real T = _T_from_v_e_ipol->sample(v, e);
1680 25 : Real p = _p_from_v_e_ipol->sample(v, e);
1681 25 : return k_from_p_T(p, T);
1682 : }
1683 0 : else if (_fp)
1684 0 : return _fp->k_from_v_e(v, e);
1685 : else
1686 0 : NeedTabulationOrFPError("k_from_v_e", "k");
1687 : }
1688 :
1689 : void
1690 6 : TabulatedFluidProperties::k_from_v_e(Real v, Real e, Real & k, Real & dk_dv, Real & dk_de) const
1691 : {
1692 6 : if (_interpolate_k && !_construct_pT_from_ve && !_create_direct_ve_interpolations)
1693 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1694 6 : checkInputVariablesVE(v, e);
1695 :
1696 6 : if (_create_direct_ve_interpolations && _interpolate_k)
1697 3 : _property_ve_ipol[_k_idx]->sampleValueAndDerivatives(v, e, k, dk_dv, dk_de);
1698 3 : else if (_construct_pT_from_ve)
1699 : {
1700 : Real p, dp_dv, dp_de;
1701 3 : _p_from_v_e_ipol->sampleValueAndDerivatives(v, e, p, dp_dv, dp_de);
1702 : Real T, dT_dv, dT_de;
1703 3 : _T_from_v_e_ipol->sampleValueAndDerivatives(v, e, T, dT_dv, dT_de);
1704 : Real dk_dp, dk_dT;
1705 3 : k_from_p_T(p, T, k, dk_dp, dk_dT);
1706 3 : dk_dv = dk_dp * dp_dv + dk_dT * dT_dv;
1707 3 : dk_de = dk_dp * dp_de + dk_dT * dT_de;
1708 : }
1709 0 : else if (_fp)
1710 0 : _fp->k_from_v_e(v, e, k, dk_dv, dk_de);
1711 : else
1712 0 : NeedTabulationOrFPError("k_from_v_e with derivatives", "k");
1713 6 : }
1714 :
1715 : Real
1716 633 : TabulatedFluidProperties::s_from_v_e(Real v, Real e) const
1717 : {
1718 633 : if (_interpolate_entropy && !_construct_pT_from_ve && !_create_direct_ve_interpolations)
1719 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1720 633 : checkInputVariablesVE(v, e);
1721 :
1722 633 : if (_create_direct_ve_interpolations && _interpolate_entropy)
1723 617 : return _property_ve_ipol[_entropy_idx]->sample(v, e);
1724 16 : else if (_construct_pT_from_ve)
1725 : {
1726 16 : Real T = _T_from_v_e_ipol->sample(v, e);
1727 16 : Real p = _p_from_v_e_ipol->sample(v, e);
1728 16 : return s_from_p_T(p, T);
1729 : }
1730 0 : else if (_fp)
1731 0 : return _fp->s_from_v_e(v, e);
1732 : else
1733 0 : NeedTabulationOrFPError("s_from_v_e", "entropy");
1734 : }
1735 :
1736 : void
1737 1 : TabulatedFluidProperties::s_from_v_e(Real v, Real e, Real & s, Real & ds_dv, Real & ds_de) const
1738 : {
1739 1 : if (_interpolate_entropy && !_construct_pT_from_ve && !_create_direct_ve_interpolations)
1740 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1741 1 : checkInputVariablesVE(v, e);
1742 :
1743 1 : if (_create_direct_ve_interpolations && _interpolate_entropy)
1744 1 : _property_ve_ipol[_entropy_idx]->sampleValueAndDerivatives(v, e, s, ds_dv, ds_de);
1745 0 : else if (_construct_pT_from_ve)
1746 : {
1747 : Real p, T, dT_dv, dT_de, dp_dv, dp_de;
1748 0 : _T_from_v_e_ipol->sampleValueAndDerivatives(v, e, T, dT_dv, dT_de);
1749 0 : _p_from_v_e_ipol->sampleValueAndDerivatives(v, e, p, dp_dv, dp_de);
1750 : Real ds_dp, ds_dT;
1751 0 : s_from_p_T(p, T, s, ds_dp, ds_dT);
1752 0 : ds_dv = ds_dp * dp_dv + ds_dT * dT_dv;
1753 0 : ds_dv = ds_dp * dp_de + ds_dT * dT_de;
1754 : }
1755 0 : else if (_fp)
1756 0 : _fp->s_from_v_e(v, e, s, ds_dv, ds_de);
1757 : else
1758 0 : NeedTabulationOrFPError("s_from_v_e", "entropy");
1759 1 : }
1760 :
1761 : Real
1762 25 : TabulatedFluidProperties::g_from_v_e(Real v, Real e) const
1763 : {
1764 25 : if (!_construct_pT_from_ve &&
1765 10 : (!_create_direct_ve_interpolations || _entropy_idx == libMesh::invalid_uint ||
1766 10 : _enthalpy_idx == libMesh::invalid_uint || _T_idx == libMesh::invalid_uint))
1767 0 : missingVEInterpolationError(__PRETTY_FUNCTION__);
1768 25 : checkInputVariablesVE(v, e);
1769 :
1770 25 : Real h, T = 0, s;
1771 25 : if (_create_direct_ve_interpolations)
1772 : {
1773 10 : s = _property_ve_ipol[_entropy_idx]->sample(v, e);
1774 10 : h = _property_ve_ipol[_enthalpy_idx]->sample(v, e);
1775 10 : T = _property_ve_ipol[_T_idx]->sample(v, e);
1776 : }
1777 15 : else if (_fp || _create_direct_pT_interpolations)
1778 : {
1779 15 : Real p0 = _p_initial_guess;
1780 15 : Real T0 = _T_initial_guess;
1781 15 : Real p = 0;
1782 : bool conversion_succeeded;
1783 15 : p_T_from_v_e(v, e, p0, T0, p, T, conversion_succeeded);
1784 15 : s = s_from_p_T(p, T);
1785 15 : h = h_from_p_T(p, T);
1786 15 : }
1787 : else
1788 0 : mooseError(__PRETTY_FUNCTION__,
1789 : "\nNo tabulation or fluid property 'input_fp' object to compute value");
1790 25 : return h - T * s;
1791 : }
1792 :
1793 : Real
1794 0 : TabulatedFluidProperties::T_from_h_s(Real h, Real s) const
1795 : {
1796 0 : Real p0 = _p_initial_guess;
1797 0 : Real T0 = _T_initial_guess;
1798 : Real p, T;
1799 : bool conversion_succeeded;
1800 0 : p_T_from_h_s(h, s, p0, T0, p, T, conversion_succeeded);
1801 0 : return T;
1802 : }
1803 :
1804 : Real
1805 10 : TabulatedFluidProperties::T_from_p_h(Real pressure, Real enthalpy) const
1806 : {
1807 10 : if (_create_direct_pT_interpolations || _create_direct_ve_interpolations)
1808 : {
1809 : auto lambda = [&](Real pressure, Real current_T, Real & new_h, Real & dh_dp, Real & dh_dT)
1810 17 : { h_from_p_T(pressure, current_T, new_h, dh_dp, dh_dT); };
1811 20 : Real T = FluidPropertiesUtils::NewtonSolve(pressure,
1812 : enthalpy,
1813 10 : _T_initial_guess,
1814 10 : _tolerance,
1815 : lambda,
1816 10 : name() + "::T_from_p_h",
1817 10 : _max_newton_its,
1818 10 : _verbose_newton)
1819 10 : .first;
1820 : // check for nans
1821 10 : if (std::isnan(T))
1822 0 : mooseError("Conversion from enthalpy (h = ",
1823 : enthalpy,
1824 : ") and pressure (p = ",
1825 : pressure,
1826 : ") to temperature failed to converge.");
1827 : return T;
1828 : }
1829 0 : else if (_fp)
1830 0 : return _fp->T_from_p_h(pressure, enthalpy);
1831 : else
1832 0 : NeedTabulationOrFPError("T_from_p_h", "temperature");
1833 : }
1834 :
1835 : ADReal
1836 1 : TabulatedFluidProperties::T_from_p_h(const ADReal & pressure, const ADReal & enthalpy) const
1837 : {
1838 : using std::isnan;
1839 1 : if (_create_direct_pT_interpolations || _create_direct_ve_interpolations)
1840 : {
1841 : auto lambda =
1842 1 : [&](ADReal pressure, ADReal current_T, ADReal & new_h, ADReal & dh_dp, ADReal & dh_dT)
1843 : {
1844 1 : h_from_p_T(pressure.value(), current_T.value(), new_h.value(), dh_dp.value(), dh_dT.value());
1845 : // Reconstruct derivatives
1846 : new_h.derivatives() =
1847 1 : dh_dp.value() * pressure.derivatives() + dh_dT.value() * current_T.derivatives();
1848 2 : };
1849 3 : ADReal T = FluidPropertiesUtils::NewtonSolve(pressure,
1850 : enthalpy,
1851 1 : _T_initial_guess,
1852 1 : _tolerance,
1853 : lambda,
1854 2 : name() + "::T_from_p_h",
1855 1 : _max_newton_its,
1856 1 : _verbose_newton)
1857 1 : .first;
1858 : // check for nans
1859 1 : if (isnan(T))
1860 0 : mooseError("Conversion from enthalpy (h = ",
1861 : enthalpy,
1862 : ") and pressure (p = ",
1863 : pressure,
1864 : ") to temperature failed to converge.");
1865 1 : return T;
1866 : }
1867 0 : else if (_fp)
1868 0 : return _fp->T_from_p_h(pressure, enthalpy);
1869 : else
1870 0 : NeedTabulationOrFPError("T_from_p_h", "temperature");
1871 : }
1872 :
1873 : Real
1874 3 : TabulatedFluidProperties::s_from_h_p(Real enthalpy, Real pressure) const
1875 : {
1876 3 : Real T = T_from_p_h(pressure, enthalpy);
1877 3 : return s_from_p_T(pressure, T);
1878 : }
1879 :
1880 : void
1881 0 : TabulatedFluidProperties::s_from_h_p(
1882 : Real h, Real pressure, Real & s, Real & ds_dh, Real & ds_dp) const
1883 : {
1884 0 : if (_fp)
1885 0 : _fp->s_from_h_p(h, pressure, s, ds_dh, ds_dp);
1886 : else
1887 0 : TabulationNotImplementedError("s_from_h_p with derivatives");
1888 0 : }
1889 :
1890 : [[noreturn]] void
1891 0 : TabulatedFluidProperties::TabulationNotImplementedError(const std::string & desired_routine) const
1892 : {
1893 0 : mooseError("TabulatedFluidProperties can only call the function '" + desired_routine +
1894 : "' when the 'input_fp' parameter is provided. It is currently not implemented using "
1895 : "tabulations, and this property is simply forwarded to the FluidProperties specified "
1896 : "in the 'input_fp' parameter");
1897 : }
1898 :
1899 : [[noreturn]] void
1900 0 : TabulatedFluidProperties::NeedTabulationOrFPError(const std::string & desired_routine,
1901 : const std::string & needed_property) const
1902 : {
1903 0 : mooseError(
1904 0 : "TabulatedFluidProperties can only call the function '" + desired_routine +
1905 0 : "' when either:\n- the property '" + needed_property +
1906 : "' is tabulated and listed in the 'interpolated_properties' parameter.\n- the 'input_fp' "
1907 : "parameter is provided.");
1908 : }
1909 :
1910 : [[noreturn]] void
1911 0 : TabulatedFluidProperties::NeedTabulationError(const std::string & needed_property) const
1912 : {
1913 0 : mooseError("Property '" + needed_property +
1914 : "' is marked as interpolated but neither of the following methods are active:\n- "
1915 : "(p,T) interpolation created from fluid properties ('create_pT_interpolations' "
1916 : "parameter)\n- a (p,T) tabulation file ('fluid_property_file')\n- (v,e) interpolation "
1917 : "created from fluid properties or a (p,T) tabulation ('create_ve_interpolations' "
1918 : "parameter)\n- a (v,e) tabulation file ('fluid_property_ve_file' parameter)");
1919 : }
1920 :
1921 : void
1922 24 : TabulatedFluidProperties::writeTabulatedData(std::string file_name)
1923 : {
1924 24 : if (processor_id() == 0)
1925 : {
1926 : // Write out the (p, T) interpolation tables
1927 18 : if (_file_name_out != "")
1928 : {
1929 24 : file_name = file_name.empty() ? "fluid_properties_" + name() + "_out.csv" : file_name;
1930 12 : MooseUtils::checkFileWriteable(file_name);
1931 :
1932 12 : std::ofstream file_out(file_name.c_str());
1933 :
1934 24 : if (!getParam<bool>("skip_header_tabulation"))
1935 : {
1936 : // Write out date and fluid type
1937 6 : time_t now = std::time(&now);
1938 12 : file_out << "# " << (_fp ? _fp->fluidName() : "")
1939 : << " properties (p,T) tabulation created by TabulatedFluidProperties on "
1940 12 : << ctime(&now) << "\n";
1941 : }
1942 :
1943 : // Write out column names
1944 12 : file_out << "pressure, temperature";
1945 120 : for (std::size_t i = 0; i < _interpolated_properties.size(); ++i)
1946 108 : if (_interpolated_properties[i] != "pressure" &&
1947 : _interpolated_properties[i] != "temperature")
1948 108 : file_out << ", " << _interpolated_properties[i];
1949 12 : file_out << "\n";
1950 :
1951 : // Write out the fluid property data
1952 672 : for (unsigned int p = 0; p < _num_p; ++p)
1953 61260 : for (unsigned int t = 0; t < _num_T; ++t)
1954 : {
1955 60600 : file_out << _pressure[p] << ", " << _temperature[t];
1956 606000 : for (std::size_t i = 0; i < _properties.size(); ++i)
1957 545400 : file_out << ", " << _properties[i][p * _num_T + t];
1958 60600 : file_out << "\n";
1959 : }
1960 :
1961 : file_out << std::flush;
1962 12 : file_out.close();
1963 12 : }
1964 :
1965 : // Write out the (v,e) interpolation tables
1966 18 : if (_file_name_ve_out != "" && (_construct_pT_from_ve || _create_direct_ve_interpolations))
1967 : {
1968 : const auto file_name_ve = (_file_name_ve_out == "")
1969 : ? std::regex_replace(file_name, std::regex("\\.csv"), "_ve.csv")
1970 6 : : _file_name_ve_out;
1971 6 : MooseUtils::checkFileWriteable(file_name_ve);
1972 6 : std::ofstream file_out(file_name_ve.c_str());
1973 :
1974 : // Write out date and fluid type
1975 12 : if (!getParam<bool>("skip_header_tabulation"))
1976 : {
1977 0 : time_t now = std::time(&now);
1978 0 : file_out << "# " << (_fp ? _fp->fluidName() : "")
1979 : << " properties (v,e) tabulation created by TabulatedFluidProperties on "
1980 0 : << ctime(&now) << "\n";
1981 : }
1982 :
1983 : // Write out column names
1984 6 : file_out << "specific_volume, internal_energy, pressure, temperature";
1985 66 : for (const auto i : index_range(_interpolated_properties))
1986 : // Avoid writing the fixed columns twice
1987 60 : if (_interpolated_properties[i] != "internal_energy" &&
1988 114 : _interpolated_properties[i] != "pressure" &&
1989 : _interpolated_properties[i] != "temperature")
1990 48 : file_out << ", " << _interpolated_properties[i];
1991 6 : file_out << "\n";
1992 :
1993 : // Write out the fluid property data
1994 66 : for (const auto v : make_range(_num_v))
1995 660 : for (const auto e : make_range(_num_e))
1996 : {
1997 600 : const auto v_val = _specific_volume[v];
1998 600 : const auto e_val = _internal_energy[e];
1999 : // Use the expected source for the grid. Note that the tabulations are already created
2000 : Real pressure, temperature;
2001 600 : if (_construct_pT_from_ve)
2002 : {
2003 0 : pressure = _p_from_v_e_ipol->sample(v_val, e_val);
2004 0 : temperature = _T_from_v_e_ipol->sample(v_val, e_val);
2005 : }
2006 : else
2007 : {
2008 600 : pressure = p_from_v_e(v_val, e_val);
2009 600 : temperature = T_from_v_e(v_val, e_val);
2010 : }
2011 1800 : file_out << v_val << ", " << e_val << ", " << pressure << ", " << temperature
2012 600 : << (_interpolated_properties.size() ? ", " : "");
2013 6600 : for (const auto i : index_range(_interpolated_properties))
2014 : {
2015 : bool add_comma = true;
2016 6000 : if (i == _density_idx)
2017 600 : file_out << 1. / v_val;
2018 5400 : else if (i == _enthalpy_idx)
2019 600 : file_out << h_from_v_e(v_val, e_val);
2020 : // Note that we could use (p,T) routine to generate this instead of (v,e)
2021 : // Or could use the _properties_ve array similar to what we do for (pressure,
2022 : // temperature)
2023 4800 : else if (i == _viscosity_idx)
2024 600 : file_out << mu_from_v_e(v_val, e_val);
2025 4200 : else if (i == _k_idx)
2026 600 : file_out << k_from_v_e(v_val, e_val);
2027 3600 : else if (i == _c_idx)
2028 600 : file_out << c_from_v_e(v_val, e_val);
2029 3000 : else if (i == _cv_idx)
2030 600 : file_out << cv_from_v_e(v_val, e_val);
2031 2400 : else if (i == _cp_idx)
2032 600 : file_out << cp_from_v_e(v_val, e_val);
2033 1800 : else if (i == _entropy_idx)
2034 600 : file_out << s_from_v_e(v_val, e_val);
2035 : else
2036 : add_comma = false;
2037 6000 : if (i != _interpolated_properties.size() - 1 && add_comma)
2038 4200 : file_out << ", ";
2039 : }
2040 :
2041 600 : file_out << "\n";
2042 : }
2043 :
2044 : file_out << std::flush;
2045 6 : file_out.close();
2046 6 : }
2047 : }
2048 24 : }
2049 :
2050 : void
2051 83 : TabulatedFluidProperties::generateTabulatedData()
2052 : {
2053 : mooseAssert(_fp, "We should not try to generate (p,T) tabulated data without a _fp user object");
2054 83 : _pressure.resize(_num_p);
2055 83 : _temperature.resize(_num_T);
2056 :
2057 : // Generate data for all properties entered in input file
2058 83 : _properties.resize(_interpolated_properties_enum.size());
2059 83 : _interpolated_properties.resize(_interpolated_properties_enum.size());
2060 :
2061 781 : for (std::size_t i = 0; i < _interpolated_properties_enum.size(); ++i)
2062 698 : _interpolated_properties[i] = _interpolated_properties_enum[i];
2063 :
2064 781 : for (const auto i : index_range(_properties))
2065 698 : _properties[i].resize(_num_p * _num_T);
2066 :
2067 : // Temperature is divided equally into _num_T segments
2068 83 : Real delta_T = (_temperature_max - _temperature_min) / static_cast<Real>(_num_T - 1);
2069 :
2070 7569 : for (unsigned int j = 0; j < _num_T; ++j)
2071 7486 : _temperature[j] = _temperature_min + j * delta_T;
2072 :
2073 : // Divide the pressure into _num_p equal segments
2074 83 : Real delta_p = (_pressure_max - _pressure_min) / static_cast<Real>(_num_p - 1);
2075 :
2076 7569 : for (unsigned int i = 0; i < _num_p; ++i)
2077 7486 : _pressure[i] = _pressure_min + i * delta_p;
2078 :
2079 : // Generate the tabulated data at the pressure and temperature points
2080 781 : for (const auto i : index_range(_properties))
2081 : {
2082 698 : if (_interpolated_properties[i] == "density")
2083 7468 : for (unsigned int p = 0; p < _num_p; ++p)
2084 738222 : for (unsigned int t = 0; t < _num_T; ++t)
2085 730836 : _properties[i][p * _num_T + t] = _fp->rho_from_p_T(_pressure[p], _temperature[t]);
2086 :
2087 698 : if (_interpolated_properties[i] == "enthalpy")
2088 7468 : for (unsigned int p = 0; p < _num_p; ++p)
2089 738222 : for (unsigned int t = 0; t < _num_T; ++t)
2090 730836 : _properties[i][p * _num_T + t] = _fp->h_from_p_T(_pressure[p], _temperature[t]);
2091 :
2092 698 : if (_interpolated_properties[i] == "internal_energy")
2093 7468 : for (unsigned int p = 0; p < _num_p; ++p)
2094 738222 : for (unsigned int t = 0; t < _num_T; ++t)
2095 730836 : _properties[i][p * _num_T + t] = _fp->e_from_p_T(_pressure[p], _temperature[t]);
2096 :
2097 698 : if (_interpolated_properties[i] == "viscosity")
2098 7468 : for (unsigned int p = 0; p < _num_p; ++p)
2099 738222 : for (unsigned int t = 0; t < _num_T; ++t)
2100 730836 : _properties[i][p * _num_T + t] = _fp->mu_from_p_T(_pressure[p], _temperature[t]);
2101 :
2102 698 : if (_interpolated_properties[i] == "k")
2103 6357 : for (unsigned int p = 0; p < _num_p; ++p)
2104 627122 : for (unsigned int t = 0; t < _num_T; ++t)
2105 620836 : _properties[i][p * _num_T + t] = _fp->k_from_p_T(_pressure[p], _temperature[t]);
2106 :
2107 698 : if (_interpolated_properties[i] == "c")
2108 6350 : for (unsigned int p = 0; p < _num_p; ++p)
2109 627080 : for (unsigned int t = 0; t < _num_T; ++t)
2110 620800 : _properties[i][p * _num_T + t] = _fp->c_from_p_T(_pressure[p], _temperature[t]);
2111 :
2112 698 : if (_interpolated_properties[i] == "cv")
2113 6357 : for (unsigned int p = 0; p < _num_p; ++p)
2114 627122 : for (unsigned int t = 0; t < _num_T; ++t)
2115 620836 : _properties[i][p * _num_T + t] = _fp->cv_from_p_T(_pressure[p], _temperature[t]);
2116 :
2117 698 : if (_interpolated_properties[i] == "cp")
2118 6357 : for (unsigned int p = 0; p < _num_p; ++p)
2119 627122 : for (unsigned int t = 0; t < _num_T; ++t)
2120 620836 : _properties[i][p * _num_T + t] = _fp->cp_from_p_T(_pressure[p], _temperature[t]);
2121 :
2122 698 : if (_interpolated_properties[i] == "entropy")
2123 6357 : for (unsigned int p = 0; p < _num_p; ++p)
2124 627122 : for (unsigned int t = 0; t < _num_T; ++t)
2125 620836 : _properties[i][p * _num_T + t] = _fp->s_from_p_T(_pressure[p], _temperature[t]);
2126 : }
2127 83 : }
2128 :
2129 : void
2130 3 : TabulatedFluidProperties::generateVETabulatedData()
2131 : {
2132 : mooseAssert(_fp, "We should not try to generate (v,e) tabulated data without a _fp user object");
2133 3 : _specific_volume.resize(_num_v);
2134 3 : _internal_energy.resize(_num_e);
2135 :
2136 : // Generate data for all properties entered in input file
2137 3 : _properties_ve.resize(_interpolated_properties_enum.size());
2138 3 : _interpolated_properties.resize(_interpolated_properties_enum.size());
2139 :
2140 : // This is filled from the user input, so it does not matter than this operation is performed
2141 : // for both the (p,T) and (v,e) tabulated data generation
2142 33 : for (std::size_t i = 0; i < _interpolated_properties_enum.size(); ++i)
2143 30 : _interpolated_properties[i] = _interpolated_properties_enum[i];
2144 :
2145 33 : for (const auto i : index_range(_properties_ve))
2146 30 : _properties_ve[i].resize(_num_v * _num_e);
2147 :
2148 : // Grids in (v,e) are not read, so we either use user input or rely on (p,T) data
2149 3 : createVEGridVectors();
2150 :
2151 : // Generate the tabulated data at the pressure and temperature points
2152 33 : for (const auto i : index_range(_properties_ve))
2153 : {
2154 30 : if (_interpolated_properties[i] == "density")
2155 303 : for (unsigned int v = 0; v < _num_v; ++v)
2156 30300 : for (unsigned int e = 0; e < _num_e; ++e)
2157 30000 : _properties_ve[i][v * _num_e + e] = 1. / _specific_volume[v];
2158 :
2159 30 : if (_interpolated_properties[i] == "enthalpy")
2160 303 : for (unsigned int v = 0; v < _num_v; ++v)
2161 30300 : for (unsigned int e = 0; e < _num_e; ++e)
2162 30000 : _properties_ve[i][v * _num_e + e] =
2163 30000 : _fp->h_from_v_e(_specific_volume[v], _internal_energy[e]);
2164 :
2165 30 : if (_interpolated_properties[i] == "internal_energy")
2166 0 : for (unsigned int v = 0; v < _num_v; ++v)
2167 0 : for (unsigned int e = 0; e < _num_e; ++e)
2168 0 : _properties_ve[i][v * _num_e + e] = _internal_energy[e];
2169 :
2170 30 : if (_interpolated_properties[i] == "viscosity")
2171 303 : for (unsigned int v = 0; v < _num_v; ++v)
2172 30300 : for (unsigned int e = 0; e < _num_e; ++e)
2173 30000 : _properties_ve[i][v * _num_e + e] =
2174 30000 : _fp->mu_from_v_e(_specific_volume[v], _internal_energy[e]);
2175 :
2176 30 : if (_interpolated_properties[i] == "k")
2177 303 : for (unsigned int v = 0; v < _num_v; ++v)
2178 30300 : for (unsigned int e = 0; e < _num_e; ++e)
2179 30000 : _properties_ve[i][v * _num_e + e] =
2180 30000 : _fp->k_from_v_e(_specific_volume[v], _internal_energy[e]);
2181 :
2182 30 : if (_interpolated_properties[i] == "c")
2183 303 : for (unsigned int v = 0; v < _num_v; ++v)
2184 30300 : for (unsigned int e = 0; e < _num_e; ++e)
2185 30000 : _properties_ve[i][v * _num_e + e] =
2186 30000 : _fp->c_from_v_e(_specific_volume[v], _internal_energy[e]);
2187 :
2188 30 : if (_interpolated_properties[i] == "cv")
2189 303 : for (unsigned int v = 0; v < _num_v; ++v)
2190 30300 : for (unsigned int e = 0; e < _num_e; ++e)
2191 30000 : _properties_ve[i][v * _num_e + e] =
2192 30000 : _fp->cv_from_v_e(_specific_volume[v], _internal_energy[e]);
2193 :
2194 30 : if (_interpolated_properties[i] == "cp")
2195 303 : for (unsigned int v = 0; v < _num_v; ++v)
2196 30300 : for (unsigned int e = 0; e < _num_e; ++e)
2197 30000 : _properties_ve[i][v * _num_e + e] =
2198 30000 : _fp->cp_from_v_e(_specific_volume[v], _internal_energy[e]);
2199 :
2200 30 : if (_interpolated_properties[i] == "entropy")
2201 303 : for (unsigned int v = 0; v < _num_v; ++v)
2202 30300 : for (unsigned int e = 0; e < _num_e; ++e)
2203 30000 : _properties_ve[i][v * _num_e + e] =
2204 30000 : _fp->s_from_v_e(_specific_volume[v], _internal_energy[e]);
2205 :
2206 30 : if (_interpolated_properties[i] == "pressure")
2207 303 : for (unsigned int v = 0; v < _num_v; ++v)
2208 30300 : for (unsigned int e = 0; e < _num_e; ++e)
2209 30000 : _properties_ve[i][v * _num_e + e] =
2210 30000 : _fp->p_from_v_e(_specific_volume[v], _internal_energy[e]);
2211 :
2212 30 : if (_interpolated_properties[i] == "temperature")
2213 303 : for (unsigned int v = 0; v < _num_v; ++v)
2214 30300 : for (unsigned int e = 0; e < _num_e; ++e)
2215 30000 : _properties_ve[i][v * _num_e + e] =
2216 30000 : _fp->T_from_v_e(_specific_volume[v], _internal_energy[e]);
2217 : }
2218 3 : }
2219 :
2220 : template <typename T>
2221 : void
2222 25377743 : TabulatedFluidProperties::checkInputVariables(T & pressure, T & temperature) const
2223 : {
2224 : using std::max, std::min;
2225 :
2226 25377743 : if (_OOBBehavior == Ignore)
2227 : return;
2228 25377311 : else if (MooseUtils::absoluteFuzzyGreaterThan(_pressure_min, pressure, libMesh::TOLERANCE) ||
2229 : MooseUtils::absoluteFuzzyGreaterThan(pressure, _pressure_max, libMesh::TOLERANCE))
2230 : {
2231 19437684 : if (_OOBBehavior == Throw)
2232 12 : throw MooseException("Pressure " + Moose::stringify(pressure) +
2233 : " is outside the range of tabulated pressure (" +
2234 2 : Moose::stringify(_pressure_min) + ", " +
2235 2 : Moose::stringify(_pressure_max) + ").");
2236 :
2237 : else
2238 : {
2239 25508362 : pressure = max(_pressure_min, min(pressure, _pressure_max));
2240 19437682 : if (_OOBBehavior == DeclareInvalid)
2241 146 : flagInvalidSolution("Pressure out of bounds");
2242 19437538 : else if (_OOBBehavior == WarnInvalid)
2243 436 : flagSolutionWarning("Pressure out of bounds");
2244 : }
2245 : }
2246 :
2247 25377309 : if (MooseUtils::absoluteFuzzyGreaterThan(_temperature_min, temperature, libMesh::TOLERANCE) ||
2248 : MooseUtils::absoluteFuzzyGreaterThan(temperature, _temperature_max, libMesh::TOLERANCE))
2249 : {
2250 7462533 : if (_OOBBehavior == Throw)
2251 12 : throw MooseException("Temperature " + Moose::stringify(temperature) +
2252 : " is outside the range of tabulated temperature (" +
2253 2 : Moose::stringify(_temperature_min) + ", " +
2254 2 : Moose::stringify(_temperature_max) + ").");
2255 : else
2256 : {
2257 8516453 : temperature = max(T(_temperature_min), min(temperature, T(_temperature_max)));
2258 7462531 : if (_OOBBehavior == DeclareInvalid)
2259 146 : flagInvalidSolution("Temperature out of bounds");
2260 7462387 : else if (_OOBBehavior == WarnInvalid)
2261 436 : flagSolutionWarning("Temperature out of bounds");
2262 : }
2263 : }
2264 : }
2265 :
2266 : template <typename T>
2267 : void
2268 8168 : TabulatedFluidProperties::checkInputVariablesVE(T & v, T & e) const
2269 : {
2270 : using std::max, std::min;
2271 :
2272 8168 : if (_OOBBehavior == Ignore)
2273 : return;
2274 8168 : else if (e < _e_min || e > _e_max)
2275 : {
2276 67 : if (_OOBBehavior == Throw)
2277 0 : throw MooseException("Specific internal energy " + Moose::stringify(e) +
2278 : " is outside the range of tabulated specific internal energies (" +
2279 0 : Moose::stringify(_e_min) + ", " + Moose::stringify(_e_max) + ").");
2280 : else
2281 : {
2282 79 : e = max(_e_min, min(e, _e_max));
2283 67 : if (_OOBBehavior == DeclareInvalid)
2284 0 : flagInvalidSolution("Specific internal energy out of bounds");
2285 67 : else if (_OOBBehavior == WarnInvalid)
2286 0 : flagSolutionWarning("Specific internal energy out of bounds");
2287 : }
2288 : }
2289 :
2290 8168 : if (v < _v_min || v > _v_max)
2291 : {
2292 45 : if (_OOBBehavior == Throw)
2293 0 : throw MooseException("Specific volume " + Moose::stringify(v) +
2294 : " is outside the range of tabulated specific volumes (" +
2295 0 : Moose::stringify(_v_min) + ", " + Moose::stringify(_v_max) + ").");
2296 : else
2297 : {
2298 45 : v = max(T(_v_min), min(v, T(_v_max)));
2299 45 : if (_OOBBehavior == DeclareInvalid)
2300 0 : flagInvalidSolution("Specific volume out of bounds");
2301 45 : else if (_OOBBehavior == WarnInvalid)
2302 0 : flagSolutionWarning("Specific volume out of bounds");
2303 : }
2304 : }
2305 : }
2306 :
2307 : void
2308 314 : TabulatedFluidProperties::checkInitialGuess(bool post_reading_tabulation) const
2309 : {
2310 : // First condition applies when generating a tabulation
2311 : // Second condition applies when using a pre-generated loaded tabulation
2312 314 : if ((!post_reading_tabulation && _fp && (_construct_pT_from_ve || _construct_pT_from_vh)) ||
2313 34 : (post_reading_tabulation && (_file_name_in != "" || _file_name_ve_in != "") &&
2314 366 : (_create_direct_ve_interpolations || isParamSetByUser("T_initial_guess") ||
2315 314 : isParamSetByUser("p_initial_guess"))))
2316 : {
2317 46 : if (_p_initial_guess < _pressure_min || _p_initial_guess > _pressure_max)
2318 20 : mooseWarning("Pressure initial guess for (p,T), (v,e) conversions " +
2319 18 : Moose::stringify(_p_initial_guess) +
2320 : " is outside the range of tabulated "
2321 10 : "pressure (" +
2322 28 : Moose::stringify(_pressure_min) + ", " + Moose::stringify(_pressure_max) + ").");
2323 :
2324 44 : if (_T_initial_guess < _temperature_min || _T_initial_guess > _temperature_max)
2325 20 : mooseWarning("Temperature initial guess for (p,T), (v,e) conversions " +
2326 18 : Moose::stringify(_T_initial_guess) +
2327 : " is outside the range of tabulated "
2328 10 : "temperature (" +
2329 28 : Moose::stringify(_temperature_min) + ", " + Moose::stringify(_temperature_max) +
2330 : ").");
2331 : }
2332 310 : }
2333 :
2334 : void
2335 39 : TabulatedFluidProperties::readFileTabulationData(const bool use_pT)
2336 : {
2337 : std::string file_name;
2338 39 : if (use_pT)
2339 : {
2340 23 : _console << name() + ": Reading tabulated properties from " << _file_name_in << std::endl;
2341 23 : _csv_reader.read();
2342 23 : file_name = _file_name_in;
2343 : }
2344 : else
2345 : {
2346 21 : _console << name() + ": Reading tabulated properties from " << _file_name_ve_in << std::endl;
2347 16 : _csv_reader.setFileName(_file_name_ve_in);
2348 16 : _csv_reader.read();
2349 : file_name = _file_name_ve_in;
2350 : }
2351 :
2352 39 : const std::vector<std::string> & column_names = _csv_reader.getNames();
2353 :
2354 : // These columns form the grid and must be present in the file
2355 : std::vector<std::string> required_columns;
2356 39 : if (use_pT)
2357 69 : required_columns = {"pressure", "temperature"};
2358 : else
2359 48 : required_columns = {"specific_volume", "internal_energy"};
2360 :
2361 : // Check that all required columns are present
2362 116 : for (std::size_t i = 0; i < required_columns.size(); ++i)
2363 : {
2364 78 : if (std::find(column_names.begin(), column_names.end(), required_columns[i]) ==
2365 : column_names.end())
2366 1 : mooseError("No ",
2367 : required_columns[i],
2368 : " data read in ",
2369 : file_name,
2370 : ". A column named ",
2371 : required_columns[i],
2372 : " must be present");
2373 : }
2374 :
2375 : // These columns can be present in the file
2376 : std::vector<std::string> property_columns = {
2377 38 : "density", "enthalpy", "viscosity", "k", "c", "cv", "cp", "entropy"};
2378 38 : if (use_pT)
2379 44 : property_columns.push_back("internal_energy");
2380 : else
2381 : {
2382 16 : property_columns.push_back("pressure");
2383 32 : property_columns.push_back("temperature");
2384 : }
2385 :
2386 : // Check that any property names read from the file are present in the list of possible
2387 : // properties, and if they are, add them to the list of read properties
2388 444 : for (std::size_t i = 0; i < column_names.size(); ++i)
2389 : {
2390 : // Only check properties not in _required_columns
2391 407 : if (std::find(required_columns.begin(), required_columns.end(), column_names[i]) ==
2392 : required_columns.end())
2393 : {
2394 331 : if (std::find(property_columns.begin(), property_columns.end(), column_names[i]) ==
2395 : property_columns.end())
2396 1 : mooseWarning(column_names[i],
2397 : " read in ",
2398 : file_name,
2399 : " tabulation file is not one of the properties that TabulatedFluidProperties "
2400 : "understands. It will be ignored.");
2401 : // We could be reading a (v,e) tabulation after having read a (p,T) tabulation, do not
2402 : // insert twice
2403 : // Also only allow properties specified as interpolated if user passed the parameter
2404 330 : else if (std::find(_interpolated_properties.begin(),
2405 : _interpolated_properties.end(),
2406 660 : column_names[i]) == _interpolated_properties.end() &&
2407 1310 : (!isParamSetByUser("interpolated_properties") ||
2408 320 : _interpolated_properties_enum.contains(column_names[i])))
2409 330 : _interpolated_properties.push_back(column_names[i]);
2410 : }
2411 : }
2412 :
2413 : std::map<std::string, unsigned int> data_index;
2414 440 : for (std::size_t i = 0; i < column_names.size(); ++i)
2415 : {
2416 403 : auto it = std::find(column_names.begin(), column_names.end(), column_names[i]);
2417 403 : data_index[column_names[i]] = std::distance(column_names.begin(), it);
2418 : }
2419 :
2420 37 : const std::vector<std::vector<Real>> & column_data = _csv_reader.getData();
2421 :
2422 : // Extract the pressure and temperature data vectors
2423 37 : if (use_pT)
2424 : {
2425 21 : _pressure = column_data[data_index.find("pressure")->second];
2426 42 : _temperature = column_data[data_index.find("temperature")->second];
2427 : }
2428 : else
2429 : {
2430 16 : _specific_volume = column_data[data_index.find("specific_volume")->second];
2431 32 : _internal_energy = column_data[data_index.find("internal_energy")->second];
2432 : }
2433 :
2434 37 : if (use_pT)
2435 42 : checkFileTabulationGrids(_pressure, _temperature, file_name, "pressure", "temperature");
2436 : else
2437 32 : checkFileTabulationGrids(_specific_volume,
2438 16 : _internal_energy,
2439 : file_name,
2440 : "specific volume",
2441 : "specific internal energy");
2442 :
2443 34 : if (use_pT)
2444 : {
2445 18 : _num_p = _pressure.size();
2446 18 : _num_T = _temperature.size();
2447 :
2448 : // Minimum and maximum pressure and temperature. Note that _pressure and
2449 : // _temperature are sorted
2450 18 : _pressure_min = _pressure.front();
2451 18 : _pressure_max = _pressure.back();
2452 18 : _temperature_min = _temperature.front();
2453 18 : _temperature_max = _temperature.back();
2454 18 : checkInitialGuess(true);
2455 :
2456 : // Extract the fluid property data from the file
2457 178 : for (std::size_t i = 0; i < _interpolated_properties.size(); ++i)
2458 160 : _properties.push_back(column_data[data_index.find(_interpolated_properties[i])->second]);
2459 : }
2460 : else
2461 : {
2462 16 : _num_v = _specific_volume.size();
2463 16 : _num_e = _internal_energy.size();
2464 :
2465 : // Minimum and maximum specific internal energy and specific volume
2466 16 : _v_min = _specific_volume.front();
2467 16 : _v_max = _specific_volume.back();
2468 16 : _e_min = _internal_energy.front();
2469 16 : _e_max = _internal_energy.back();
2470 :
2471 : // We cannot overwrite the tabulated data grid with a grid generated from user-input for the
2472 : // purpose of creating (p,T) to (v,e) interpolations
2473 16 : if (_construct_pT_from_ve)
2474 0 : paramError("construct_pT_from_ve",
2475 : "Reading a (v,e) tabulation and generating (p,T) to (v,e) interpolation tables is "
2476 : "not supported at this time.");
2477 :
2478 : // Make sure we use the tabulation bounds
2479 16 : _e_bounds_specified = true;
2480 16 : _v_bounds_specified = true;
2481 :
2482 : // Extract the fluid property data from the file
2483 16 : _properties_ve.reserve(_interpolated_properties.size());
2484 176 : for (std::size_t i = 0; i < _interpolated_properties.size(); ++i)
2485 160 : _properties_ve.push_back(column_data[data_index.find(_interpolated_properties[i])->second]);
2486 :
2487 : // Obtain the min/max T, p and check the initial guess
2488 16 : const auto & p_col = column_data[data_index.find("pressure")->second];
2489 16 : _pressure_min = *std::min_element(p_col.begin(), p_col.end());
2490 16 : _pressure_max = *std::max_element(p_col.begin(), p_col.end());
2491 19 : const auto & T_col = column_data[data_index.find("temperature")->second];
2492 16 : _temperature_min = *std::min_element(T_col.begin(), T_col.end());
2493 16 : _temperature_max = *std::max_element(T_col.begin(), T_col.end());
2494 16 : checkInitialGuess(true);
2495 : }
2496 155 : }
2497 :
2498 : void
2499 37 : TabulatedFluidProperties::checkFileTabulationGrids(std::vector<Real> & v1,
2500 : std::vector<Real> & v2,
2501 : const std::string & file_name,
2502 : const std::string & v1_name,
2503 : const std::string & v2_name)
2504 : {
2505 : // NOTE: We kept the comments in terms of pressure & temperature for clarity
2506 : // Pressure (v1) and temperature (v2) data contains duplicates due to the csv format.
2507 : // First, check that pressure (v1) is monotonically increasing
2508 37 : if (!std::is_sorted(v1.begin(), v1.end()))
2509 0 : mooseError("The column data for ", v1_name, " is not monotonically increasing in ", file_name);
2510 :
2511 : // The first pressure (v1) value is repeated for each temperature (v2) value. Counting the
2512 : // number of repeats provides the number of temperature (v2) values
2513 37 : auto num_v2 = std::count(v1.begin(), v1.end(), v1.front());
2514 :
2515 : // Now remove the duplicates in the pressure (v1) vector
2516 37 : auto last_unique = std::unique(v1.begin(), v1.end());
2517 : v1.erase(last_unique, v1.end());
2518 :
2519 : // Check that the number of rows in the csv file is equal to _num_v1 * _num_v2
2520 : // v2 is currently the same size as the column_data (will get trimmed at the end)
2521 37 : if (v2.size() != v1.size() * libMesh::cast_int<unsigned int>(num_v2))
2522 1 : mooseError("The number of rows in ",
2523 : file_name,
2524 : " is not equal to the number of unique ",
2525 : v1_name,
2526 : " values ",
2527 1 : v1.size(),
2528 : " multiplied by the number of unique ",
2529 : v2_name,
2530 : " values ",
2531 : num_v2);
2532 :
2533 : // Need to make sure that the temperature (v2) values are provided in ascending order
2534 36 : std::vector<Real> base_v2(v2.begin(), v2.begin() + num_v2);
2535 36 : if (!std::is_sorted(base_v2.begin(), base_v2.end()))
2536 1 : mooseError("The column data for ", v2_name, " is not monotonically increasing in ", file_name);
2537 :
2538 : // Need to make sure that the temperature (v2) are repeated for each pressure (v1) grid point
2539 35 : auto it_v2 = v2.begin() + num_v2;
2540 1772 : for (const auto i : make_range(v1.size() - 1))
2541 : {
2542 1739 : std::vector<Real> repeated_v2(it_v2, it_v2 + num_v2);
2543 1738 : if (repeated_v2 != base_v2)
2544 1 : mooseError(v2_name,
2545 : " values for ",
2546 : v1_name,
2547 : " ",
2548 1 : v1[i + 1],
2549 : " are not identical to values for ",
2550 : v1[0]);
2551 :
2552 : std::advance(it_v2, num_v2);
2553 1738 : }
2554 :
2555 : // At this point, all temperature (v2) data has been provided in ascending order
2556 : // identically for each pressure (v1) value, so we can just keep the first range
2557 : v2.erase(v2.begin() + num_v2, v2.end());
2558 36 : }
2559 :
2560 : void
2561 120 : TabulatedFluidProperties::computePropertyIndicesInInterpolationVectors()
2562 : {
2563 : // At this point, all properties read or generated are able to be used by
2564 : // TabulatedFluidProperties. Now set flags and indexes for each property in
2565 : //_interpolated_properties to use in property calculations
2566 1168 : for (std::size_t i = 0; i < _interpolated_properties.size(); ++i)
2567 : {
2568 1048 : if (_interpolated_properties[i] == "density")
2569 : {
2570 119 : _interpolate_density = true;
2571 119 : _density_idx = i;
2572 : }
2573 929 : else if (_interpolated_properties[i] == "enthalpy")
2574 : {
2575 119 : _interpolate_enthalpy = true;
2576 119 : _enthalpy_idx = i;
2577 : }
2578 810 : else if (_interpolated_properties[i] == "internal_energy")
2579 : {
2580 100 : _interpolate_internal_energy = true;
2581 100 : _internal_energy_idx = i;
2582 : }
2583 710 : else if (_interpolated_properties[i] == "viscosity")
2584 : {
2585 119 : _interpolate_viscosity = true;
2586 119 : _viscosity_idx = i;
2587 : }
2588 591 : else if (_interpolated_properties[i] == "k")
2589 : {
2590 108 : _interpolate_k = true;
2591 108 : _k_idx = i;
2592 : }
2593 483 : else if (_interpolated_properties[i] == "c")
2594 : {
2595 105 : _interpolate_c = true;
2596 105 : _c_idx = i;
2597 : }
2598 378 : else if (_interpolated_properties[i] == "cp")
2599 : {
2600 108 : _interpolate_cp = true;
2601 108 : _cp_idx = i;
2602 : }
2603 270 : else if (_interpolated_properties[i] == "cv")
2604 : {
2605 108 : _interpolate_cv = true;
2606 108 : _cv_idx = i;
2607 : }
2608 162 : else if (_interpolated_properties[i] == "entropy")
2609 : {
2610 108 : _interpolate_entropy = true;
2611 108 : _entropy_idx = i;
2612 : }
2613 54 : else if (_interpolated_properties[i] == "pressure")
2614 : {
2615 27 : _interpolate_pressure = true;
2616 27 : _p_idx = i;
2617 : }
2618 27 : else if (_interpolated_properties[i] == "temperature")
2619 : {
2620 27 : _interpolate_temperature = true;
2621 27 : _T_idx = i;
2622 : }
2623 : else
2624 0 : mooseError("Specified property '" + _interpolated_properties[i] +
2625 : "' is present in the tabulation but is not currently leveraged by the code in the "
2626 : "TabulatedFluidProperties. If it is spelled correctly, then please contact a "
2627 : "MOOSE or fluid properties module developer.");
2628 : }
2629 120 : }
2630 :
2631 : void
2632 138 : TabulatedFluidProperties::createVGridVector()
2633 : {
2634 : mooseAssert(_file_name_ve_in.empty(), "We should be reading the specific volume grid from file");
2635 138 : if (!_v_bounds_specified)
2636 : {
2637 : // if csv exists, get max and min values from csv file
2638 104 : if (_interpolate_density)
2639 : {
2640 : Real rho_max =
2641 200 : *std::max_element(_properties[_density_idx].begin(), _properties[_density_idx].end());
2642 : Real rho_min =
2643 100 : *std::min_element(_properties[_density_idx].begin(), _properties[_density_idx].end());
2644 100 : _v_max = 1 / rho_min;
2645 100 : _v_min = 1 / rho_max;
2646 : }
2647 4 : else if (_fp)
2648 : {
2649 : // extreme values of specific volume for the grid bounds
2650 4 : Real v1 = _fp->v_from_p_T(_pressure_min, _temperature_min);
2651 4 : Real v2 = _fp->v_from_p_T(_pressure_max, _temperature_min);
2652 4 : Real v3 = _fp->v_from_p_T(_pressure_min, _temperature_max);
2653 4 : Real v4 = _fp->v_from_p_T(_pressure_max, _temperature_max);
2654 4 : _v_min = std::min({v1, v2, v3, v4});
2655 4 : _v_max = std::max({v1, v2, v3, v4});
2656 : }
2657 : else
2658 0 : mooseWarning("Unable to compute grid bounds in specific volume. Please specify the v_min/max "
2659 : "parameters");
2660 :
2661 : // Prevent changing the bounds of the grid
2662 104 : _v_bounds_specified = true;
2663 : }
2664 :
2665 : // Create v grid for interpolation
2666 138 : _specific_volume.resize(_num_v);
2667 138 : if (_log_space_v)
2668 : {
2669 : // incrementing the exponent linearly will yield a log-spaced grid after taking the value to
2670 : // the power of 10
2671 16 : Real dv = (std::log10(_v_max) - std::log10(_v_min)) / ((Real)_num_v - 1);
2672 16 : Real log_v_min = std::log10(_v_min);
2673 1616 : for (unsigned int j = 0; j < _num_v; ++j)
2674 1600 : _specific_volume[j] = std::pow(10, log_v_min + j * dv);
2675 : }
2676 : else
2677 : {
2678 122 : Real dv = (_v_max - _v_min) / ((Real)_num_v - 1);
2679 12322 : for (unsigned int j = 0; j < _num_v; ++j)
2680 12200 : _specific_volume[j] = _v_min + j * dv;
2681 : }
2682 138 : }
2683 :
2684 : void
2685 112 : TabulatedFluidProperties::createVEGridVectors()
2686 : {
2687 112 : createVGridVector();
2688 112 : if (!_e_bounds_specified)
2689 : {
2690 : // if csv exists, get max and min values from csv file
2691 112 : if (_interpolate_internal_energy)
2692 : {
2693 108 : _e_min = *std::min_element(_properties[_internal_energy_idx].begin(),
2694 108 : _properties[_internal_energy_idx].end());
2695 108 : _e_max = *std::max_element(_properties[_internal_energy_idx].begin(),
2696 : _properties[_internal_energy_idx].end());
2697 : }
2698 4 : else if (_fp)
2699 : {
2700 : // extreme values of internal energy for the grid bounds
2701 4 : Real e1 = _fp->e_from_p_T(_pressure_min, _temperature_min);
2702 4 : Real e2 = _fp->e_from_p_T(_pressure_max, _temperature_min);
2703 4 : Real e3 = _fp->e_from_p_T(_pressure_min, _temperature_max);
2704 4 : Real e4 = _fp->e_from_p_T(_pressure_max, _temperature_max);
2705 4 : _e_min = std::min({e1, e2, e3, e4});
2706 4 : _e_max = std::max({e1, e2, e3, e4});
2707 : }
2708 : else
2709 0 : mooseWarning("Unable to compute grid bounds in internal energy. Please specify the e_min/max "
2710 : "parameters");
2711 : }
2712 :
2713 : // Create e grid for interpolation
2714 112 : _internal_energy.resize(_num_e);
2715 112 : if (_log_space_e)
2716 : {
2717 : // incrementing the exponent linearly will yield a log-spaced grid after taking the value to
2718 : // the power of 10
2719 16 : if (_e_min < 0)
2720 0 : mooseError("Logarithmic grid in specific energy can only be used with a positive specific "
2721 0 : "energy. Current minimum: " +
2722 : std::to_string(_e_min));
2723 16 : Real de = (std::log10(_e_max) - std::log10(_e_min)) / ((Real)_num_e - 1);
2724 16 : Real log_e_min = std::log10(_e_min);
2725 1616 : for (const auto j : make_range(_num_e))
2726 1600 : _internal_energy[j] = std::pow(10, log_e_min + j * de);
2727 : }
2728 : else
2729 : {
2730 96 : Real de = (_e_max - _e_min) / ((Real)_num_e - 1);
2731 9696 : for (const auto j : make_range(_num_e))
2732 9600 : _internal_energy[j] = _e_min + j * de;
2733 : }
2734 112 : }
2735 :
2736 : void
2737 26 : TabulatedFluidProperties::createVHGridVectors()
2738 : {
2739 26 : if (_file_name_ve_in.empty())
2740 26 : createVGridVector();
2741 26 : if (_fp)
2742 : {
2743 : // extreme values of enthalpy for the grid bounds
2744 8 : Real h1 = _fp->h_from_p_T(_pressure_min, _temperature_min);
2745 8 : Real h2 = _fp->h_from_p_T(_pressure_max, _temperature_min);
2746 8 : Real h3 = _fp->h_from_p_T(_pressure_min, _temperature_max);
2747 8 : Real h4 = _fp->h_from_p_T(_pressure_max, _temperature_max);
2748 8 : _h_min = std::min({h1, h2, h3, h4});
2749 8 : _h_max = std::max({h1, h2, h3, h4});
2750 : }
2751 : // if csv exists, get max and min values from csv file
2752 18 : else if (_properties.size())
2753 : {
2754 36 : _h_max = *max_element(_properties[_enthalpy_idx].begin(), _properties[_enthalpy_idx].end());
2755 18 : _h_min = *min_element(_properties[_enthalpy_idx].begin(), _properties[_enthalpy_idx].end());
2756 : }
2757 0 : else if (_properties_ve.size())
2758 : {
2759 0 : _h_max = *max_element(_properties[_enthalpy_idx].begin(), _properties[_enthalpy_idx].end());
2760 0 : _h_min = *min_element(_properties[_enthalpy_idx].begin(), _properties[_enthalpy_idx].end());
2761 : }
2762 : else
2763 0 : mooseError("Need a source to compute the enthalpy grid bounds: either a FP object, or a (p,T) "
2764 : "tabulation file or a (v,e) tabulation file");
2765 :
2766 : // Create h grid for interpolation
2767 : // enthalpy & internal energy use same # grid points
2768 26 : _enthalpy.resize(_num_e);
2769 26 : if (_log_space_h)
2770 : {
2771 : // incrementing the exponent linearly will yield a log-spaced grid after taking the value to
2772 : // the power of 10
2773 0 : if (_h_min < 0)
2774 0 : mooseError("Logarithmic grid in specific energy can only be used with a positive enthalpy. "
2775 0 : "Current minimum: " +
2776 : std::to_string(_h_min));
2777 0 : Real dh = (std::log10(_h_max) - std::log10(_h_min)) / ((Real)_num_e - 1);
2778 0 : Real log_h_min = std::log10(_h_min);
2779 0 : for (const auto j : make_range(_num_e))
2780 0 : _enthalpy[j] = std::pow(10, log_h_min + j * dh);
2781 : }
2782 : else
2783 : {
2784 26 : Real dh = (_h_max - _h_min) / ((Real)_num_e - 1);
2785 2626 : for (const auto j : make_range(_num_e))
2786 2600 : _enthalpy[j] = _h_min + j * dh;
2787 : }
2788 26 : }
2789 :
2790 : void
2791 0 : TabulatedFluidProperties::missingVEInterpolationError(const std::string & function_name) const
2792 : {
2793 0 : mooseError(function_name +
2794 : ": to call this function you must:\n-add this property to the list to the list of "
2795 : "'interpolated_properties'\n and then either:\n-construct (p, T) from (v, e) "
2796 : "tabulations using the 'construct_pT_from_ve' parameter\n-load (v,e) interpolation "
2797 : "tables using the 'fluid_property_ve_file' parameter");
2798 : }
2799 :
2800 : template void TabulatedFluidProperties::checkInputVariables(Real & pressure,
2801 : Real & temperature) const;
2802 : template void TabulatedFluidProperties::checkInputVariables(ADReal & pressure,
2803 : ADReal & temperature) const;
2804 : template void TabulatedFluidProperties::checkInputVariablesVE(Real & v, Real & e) const;
2805 : template void TabulatedFluidProperties::checkInputVariablesVE(ADReal & v, ADReal & e) const;
|