LCOV - code coverage report
Current view: top level - src/fluidproperties - TabulatedFluidProperties.C (source / functions) Hit Total Coverage
Test: idaholab/moose fluid_properties: #31405 (292dce) with base fef103 Lines: 973 1185 82.1 %
Date: 2025-09-04 07:53:14 Functions: 72 85 84.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14