Loading [MathJax]/extensions/tex2jax.js
https://mooseframework.inl.gov
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends
TabulatedBicubicFluidProperties.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
11 #include "BicubicInterpolation.h"
12 #include "MooseUtils.h"
13 #include "Conversion.h"
14 #include "KDTree.h"
15 
16 // C++ includes
17 #include <fstream>
18 #include <ctime>
19 
21 registerMooseObjectRenamed("FluidPropertiesApp",
23  "01/01/2023 00:00",
25 
28 {
30  params.addClassDescription(
31  "Fluid properties using bicubic interpolation on tabulated values provided");
32  return params;
33 }
34 
36  : TabulatedFluidProperties(parameters)
37 {
38 }
39 
40 void
42 {
43  // Construct bicubic interpolants from tabulated data
44  std::vector<std::vector<Real>> data_matrix;
45 
47  {
48  _property_ipol.resize(_properties.size());
49  for (const auto i : index_range(_property_ipol))
50  {
51  reshapeData2D(_num_p, _num_T, _properties[i], data_matrix);
52  _property_ipol[i] =
53  std::make_unique<BicubicInterpolation>(_pressure, _temperature, data_matrix);
54  }
55  }
56 
58  {
59  _property_ve_ipol.resize(_properties_ve.size());
60 
61  for (const auto i : index_range(_property_ve_ipol))
62  {
63  reshapeData2D(_num_v, _num_e, _properties_ve[i], data_matrix);
65  std::make_unique<BicubicInterpolation>(_specific_volume, _internal_energy, data_matrix);
66  }
67  }
68 
69  bool conversion_succeeded = true;
70  unsigned int fail_counter_ve = 0;
71  unsigned int fail_counter_vh = 0;
72  // Create interpolations of (p,T) from (v,e)
74  {
75  // Grids in specific volume and internal energy can be either linear or logarithmic
76  // NOTE: this could have been called already when generating tabulated data
78 
79  // initialize vectors for interpolation
80  std::vector<std::vector<Real>> p_from_v_e(_num_v);
81  std::vector<std::vector<Real>> T_from_v_e(_num_v);
82 
83  unsigned int num_p_nans_ve = 0, num_T_nans_ve = 0, num_p_out_bounds_ve = 0,
84  num_T_out_bounds_ve = 0;
85 
86  for (unsigned int i = 0; i < _num_v; ++i)
87  {
88  Real p_guess = _p_initial_guess;
89  Real T_guess = _T_initial_guess;
90  p_from_v_e[i].resize(_num_e);
91  T_from_v_e[i].resize(_num_e);
92  for (unsigned int j = 0; j < _num_e; ++j)
93  {
94  Real p_ve, T_ve;
95  // Using an input fluid property instead of the tabulation will get more exact inversions
96  if (_fp)
101  p_ve,
102  T_ve,
103  conversion_succeeded);
104  else
105  {
106  // The inversion may step outside of the domain of definition of the interpolations,
107  // which are restricted to the range of the input CSV file
108  const auto old_error_behavior = _OOBBehavior;
112  p_guess,
113  T_guess,
114  p_ve,
115  T_ve,
116  conversion_succeeded);
117  _OOBBehavior = old_error_behavior;
118  // track number of times convergence failed
119  if (!conversion_succeeded)
120  ++fail_counter_ve;
121  }
122 
123  // check for NaNs in Newton Method
128  i,
129  p_ve,
130  T_ve,
131  num_p_nans_ve,
132  num_T_nans_ve);
133 
134  // replace out of bounds pressure values with pmax or pmin
135  checkOutofBounds(_pressure_min, _pressure_max, p_ve, num_p_out_bounds_ve);
136  // replace out of bounds temperature values with Tmax or Tmin
137  checkOutofBounds(_temperature_min, _temperature_max, T_ve, num_T_out_bounds_ve);
138 
139  p_from_v_e[i][j] = p_ve;
140  T_from_v_e[i][j] = T_ve;
141 
142  p_guess = p_ve;
143  T_guess = T_ve;
144  }
145  }
146  // output warning if nans or values out of bounds
147  outputWarnings(num_p_nans_ve,
148  num_T_nans_ve,
149  num_p_out_bounds_ve,
150  num_T_out_bounds_ve,
151  fail_counter_ve,
152  _num_e * _num_v,
153  "(v,e)");
154 
155  // the bicubic interpolation object are init'ed now
157  std::make_unique<BicubicInterpolation>(_specific_volume, _internal_energy, p_from_v_e);
159  std::make_unique<BicubicInterpolation>(_specific_volume, _internal_energy, T_from_v_e);
160  }
161 
162  // Create interpolations of (p,T) from (v,h)
164  {
165  // Grids in specific volume and enthalpy can be either linear or logarithmic
166  // NOTE: the specific volume grid could have been created when generating tabulated data
168 
169  // initialize vectors for interpolation
170  std::vector<std::vector<Real>> p_from_v_h(_num_v);
171  std::vector<std::vector<Real>> T_from_v_h(_num_v);
172 
173  unsigned int num_p_nans_vh = 0, num_T_nans_vh = 0, num_p_out_bounds_vh = 0,
174  num_T_out_bounds_vh = 0;
175 
176  for (unsigned int i = 0; i < _num_v; ++i)
177  {
178  Real p_guess = _p_initial_guess;
179  Real T_guess = _T_initial_guess;
180  p_from_v_h[i].resize(_num_e);
181  T_from_v_h[i].resize(_num_e);
182  for (unsigned int j = 0; j < _num_e; ++j)
183  {
184  Real p_vh, T_vh;
185  // Using an input fluid property instead of the tabulation will get more exact inversions
186  if (_fp)
188  _enthalpy[j],
191  p_vh,
192  T_vh,
193  conversion_succeeded);
194  else
195  {
196  // The inversion may step outside of the domain of definition of the interpolations,
197  // which are restricted to the range of the input CSV file
198  const auto old_error_behavior = _OOBBehavior;
201  _enthalpy[j],
202  p_guess,
203  T_guess,
204  p_vh,
205  T_vh,
206  conversion_succeeded);
207  _OOBBehavior = old_error_behavior;
208  // track number of times convergence failed
209  if (!conversion_succeeded)
210  ++fail_counter_vh;
211  }
212 
213  // check for NaNs in Newton Method
218  i,
219  p_vh,
220  T_vh,
221  num_p_nans_vh,
222  num_T_nans_vh);
223 
224  // replace out of bounds pressure values with pmax or pmin
225  checkOutofBounds(_pressure_min, _pressure_max, p_vh, num_p_out_bounds_vh);
226  // replace out of bounds temperature values with Tmax or Tmin
227  checkOutofBounds(_temperature_min, _temperature_max, T_vh, num_T_out_bounds_vh);
228 
229  p_from_v_h[i][j] = p_vh;
230  T_from_v_h[i][j] = T_vh;
231 
232  p_guess = p_vh;
233  T_guess = T_vh;
234  }
235  }
236  // output warnings if nans our values out of bounds
237  outputWarnings(num_p_nans_vh,
238  num_T_nans_vh,
239  num_p_out_bounds_vh,
240  num_T_out_bounds_vh,
241  fail_counter_vh,
242  _num_e * _num_v,
243  "(v,h)");
244 
245  // the bicubic interpolation object are init'ed now
247  std::make_unique<BicubicInterpolation>(_specific_volume, _enthalpy, p_from_v_h);
249  std::make_unique<BicubicInterpolation>(_specific_volume, _enthalpy, T_from_v_h);
250  }
251 }
252 
253 void
255  unsigned int ncol,
256  const std::vector<Real> & vec,
257  std::vector<std::vector<Real>> & mat)
258 {
259  if (!vec.empty())
260  {
261  mat.resize(nrow);
262  for (unsigned int i = 0; i < nrow; ++i)
263  mat[i].resize(ncol);
264 
265  for (unsigned int i = 0; i < nrow; ++i)
266  for (unsigned int j = 0; j < ncol; ++j)
267  mat[i][j] = vec[i * ncol + j];
268  }
269 }
270 
271 void
273  Real max_1,
274  Real min_2,
275  Real max_2,
276  unsigned int i,
277  Real & variable_1,
278  Real & variable_2,
279  unsigned int & num_nans_1,
280  unsigned int & num_nans_2)
281 {
282  // replace nan values with pmax or pmin
283  if (std::isnan(variable_1))
284  {
285  if (_specific_volume[i] > ((_v_min + _v_max) / 2))
286  variable_1 = min_1;
287  else if (_specific_volume[i] < ((_v_min + _v_max) / 2))
288  variable_1 = max_1;
289  num_nans_1++;
290  }
291  // replace nan values with Tmax or Tmin
292  if (std::isnan(variable_2))
293  {
294  if (_specific_volume[i] > ((_v_min + _v_max) / 2))
295  variable_2 = max_2;
296  else if (_specific_volume[i] < ((_v_min + _v_max) / 2))
297  variable_2 = min_2;
298  num_nans_2++;
299  }
300 }
301 
302 void
304  Real max,
305  Real & variable,
306  unsigned int & num_out_bounds)
307 {
308  if (variable < min)
309  {
310  variable = min;
311  num_out_bounds++;
312  }
313  else if (variable > max)
314  {
315  variable = max;
316  num_out_bounds++;
317  }
318 }
319 
320 void
322  unsigned int num_nans_T,
323  unsigned int num_out_bounds_p,
324  unsigned int num_out_bounds_T,
325  unsigned int convergence_failures,
326  unsigned int number_points,
327  std::string variable_set)
328 {
329  // make string variables before mooseWarning
330  std::string while_creating =
331  "While creating (p,T) from " + variable_set + " interpolation tables,\n";
332  std::string warning_message = while_creating;
333  std::string converge_fails = "Inversion to (p,T) from " + variable_set + " failed " +
334  std::to_string(convergence_failures) + " times\n";
335  std::string p_nans = "- " + std::to_string(num_nans_p) + " nans generated out of " +
336  std::to_string(number_points) + " points for pressure\n";
337  std::string T_nans = "- " + std::to_string(num_nans_T) + " nans generated out of " +
338  std::to_string(number_points) + " points for temperature\n";
339  std::string p_oob = "- " + std::to_string(num_out_bounds_p) + " of " +
340  std::to_string(number_points) + " pressure values were out of bounds\n";
341  std::string T_oob = "- " + std::to_string(num_out_bounds_T) + " of " +
342  std::to_string(number_points) + " temperature values were out of bounds\n";
343  std::string outcome = "The pressure and temperature values were replaced with their respective "
344  "min and max values.\n";
345 
346  // bounds are different depending on how the object is used
347  std::string source = (_fp ? "from input parameters" : "from tabulation file");
348 
349  // if any of these do not exist, do not want to print them
350  if (convergence_failures)
351  warning_message += converge_fails;
352  if (num_nans_p)
353  warning_message += p_nans;
354  if (num_nans_T)
355  warning_message += T_nans;
356  if (num_out_bounds_p)
357  {
358  warning_message += p_oob;
359  warning_message += ("Pressure bounds " + source + ": [" + std::to_string(_pressure_min) + ", " +
360  std::to_string(_pressure_max) + "]\n");
361  }
362  if (num_out_bounds_T)
363  {
364  warning_message += T_oob;
365  warning_message += ("Temperature bounds " + source + ": [" + std::to_string(_temperature_min) +
366  ", " + std::to_string(_temperature_max) + "]\n");
367  }
368  // print warning
369  if (num_nans_p || num_nans_T || num_out_bounds_p || num_out_bounds_T || convergence_failures)
370  mooseWarning(warning_message + outcome);
371 }
registerMooseObject("FluidPropertiesApp", TabulatedBicubicFluidProperties)
const bool _create_direct_ve_interpolations
Whether to create direct (v,e) interpolations.
Class for fluid properties read from a tabulation in a file.
std::unique_ptr< BidimensionalInterpolation > _p_from_v_h_ipol
Bidimensional interpolation of pressure from (v,h)
void p_T_from_v_h(const T &v, const T &h, Real p0, Real T0, T &pressure, T &temperature, bool &conversion_succeeded) const
Determines (p,T) from (v,h) using Newton Solve in 2D Useful for conversion between different sets of ...
const bool _create_direct_pT_interpolations
Whether to create direct (p,T) interpolations.
Real _temperature_max
Maximum temperature in tabulated data.
void checkNaNs(Real min_1, Real max_1, Real min_2, Real max_2, unsigned int i, Real &variable_1, Real &variable_2, unsigned int &num_nans_1, unsigned int &num_nans_2)
If Newton Method jacobian produces NaNs, set variable to min or max depending on situation.
virtual Real T_from_v_e(Real v, Real e) const override
Real _pressure_max
Maximum pressure in tabulated data.
MooseEnum _OOBBehavior
User-selected out-of-bounds behavior.
TabulatedBicubicFluidProperties(const InputParameters &parameters)
void mooseWarning(Args &&... args) const
std::vector< std::unique_ptr< BidimensionalInterpolation > > _property_ve_ipol
Vector of bi-dimensional interpolation of fluid properties directly in (v,e)
auto max(const L &left, const R &right)
void p_T_from_v_e(const CppType &v, const CppType &e, Real p0, Real T0, CppType &p, CppType &T, bool &conversion_succeeded) const
Determines (p,T) from (v,e) using Newton Solve in 2D Useful for conversion between different sets of ...
std::unique_ptr< BidimensionalInterpolation > _p_from_v_e_ipol
Bi-dimensional interpolation of pressure from (v,e)
std::unique_ptr< BidimensionalInterpolation > _T_from_v_e_ipol
Bi-dimensional interpolation of temperature from (v,e)
std::vector< Real > _enthalpy
Specific enthalpy vector.
unsigned int _num_v
Number of specific volume points in the tabulated data.
bool _construct_pT_from_ve
if the lookup table p(v, e) and T(v, e) should be constructed
Real _temperature_min
Minimum temperature in tabulated data.
void createVHGridVectors()
Create (or reset) the grid vectors for the specific volume and enthalpy interpolation The order of pr...
bool _construct_pT_from_vh
if the lookup table p(v, h) and T(v, h) should be constructed
static InputParameters validParams()
Real _v_min
Minimum specific volume in tabulated data (can be user-specified)
std::vector< Real > _pressure
Pressure vector.
std::vector< Real > _temperature
Temperature vector.
Class for fluid properties read from a file.
unsigned int _num_T
Number of temperature points in the tabulated data.
const SinglePhaseFluidProperties *const _fp
SinglePhaseFluidPropertiesPT UserObject.
registerMooseObjectRenamed("FluidPropertiesApp", TabulatedFluidProperties, "01/01/2023 00:00", TabulatedBicubicFluidProperties)
Real _pressure_min
Minimum pressure in tabulated data.
std::vector< std::vector< Real > > _properties
Tabulated fluid properties (read from file OR computed from _fp)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
unsigned int _num_p
Number of pressure points in the tabulated data.
std::vector< std::vector< Real > > _properties_ve
Tabulated fluid properties in (v,e) (read from file OR computed from _fp)
Real _v_max
Maximum specific volume in tabulated data (can be user-specified)
void checkOutofBounds(Real min, Real max, Real &variable, unsigned int &num_out_bounds)
If values go out of user defined range during Newton Method inversion, set variable to min or max dep...
const Real _p_initial_guess
Initial guess for pressure (or pressure used to compute the initial guess)
std::vector< Real > _specific_volume
Specific volume vector.
virtual Real p_from_v_e(Real v, Real e) const override
Derivatives like dc_dv & dc_de are computed using the chain rule dy/dx(p,T) = dy/dp * dp/dx + dy/dT *...
void addClassDescription(const std::string &doc_string)
std::vector< Real > _internal_energy
Specific internal energy vector.
std::unique_ptr< BidimensionalInterpolation > _T_from_v_h_ipol
Bi-dimensional interpolation of temperature from (v,h)
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
std::vector< std::unique_ptr< BidimensionalInterpolation > > _property_ipol
Vector of bi-dimensional interpolation of fluid properties.
auto min(const L &left, const R &right)
const Real _T_initial_guess
Initial guess for temperature (or temperature used to compute the initial guess)
void reshapeData2D(unsigned int nrow, unsigned int ncol, const std::vector< Real > &vec, std::vector< std::vector< Real >> &mat)
Forms a 2D matrix from a single std::vector.
auto index_range(const T &sizable)
void outputWarnings(unsigned int num_nans_p, unsigned int num_nans_T, unsigned int num_out_bounds_p, unsigned int num_out_bounds_T, unsigned int convergence_failures, unsigned int number_points, std::string variable_set)
unsigned int _num_e
Number of internal energy points in tabulated data.