LCOV - code coverage report
Current view: top level - src/functions - PiecewiseTabularBase.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 127 133 95.5 %
Date: 2025-07-17 01:28:37 Functions: 8 8 100.0 %
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 "PiecewiseTabularBase.h"
      11             : #include "DelimitedFileReader.h"
      12             : #include "JSONFileReader.h"
      13             : #include "libmesh/int_range.h"
      14             : 
      15             : InputParameters
      16       74959 : PiecewiseTabularBase::validParams()
      17             : {
      18       74959 :   InputParameters params = PiecewiseBase::validParams();
      19             : 
      20             :   // Parameters shared across all data input methods
      21       74959 :   MooseEnum axis("x=0 y=1 z=2");
      22       74959 :   params.addParam<MooseEnum>(
      23             :       "axis", axis, "The axis used (x, y, or z) if this is to be a function of position");
      24       74959 :   params.addParam<Real>("scale_factor", 1.0, "Scale factor to be applied to the output values");
      25       74959 :   params.declareControllable("scale_factor");
      26             : 
      27             :   // Data from input file parameters
      28       74959 :   params.addParam<std::vector<Real>>("xy_data",
      29             :                                      "All function data, supplied in abscissa, ordinate pairs");
      30       74959 :   params.addParam<std::vector<Real>>("x", "The abscissa values");
      31       74959 :   params.addParam<std::vector<Real>>("y", "The ordinate values");
      32             : 
      33             :   // Data from CSV file parameters
      34       74959 :   params.addParam<FileName>("data_file", "File holding CSV data");
      35       74959 :   params.addParam<unsigned int>("x_index_in_file", 0, "The abscissa index in the data file");
      36       74959 :   params.addParam<unsigned int>("y_index_in_file", 1, "The ordinate index in the data file");
      37       74959 :   params.addParam<std::string>(
      38             :       "x_title", "The title of the column/row containing the x data in the data file");
      39       74959 :   params.addParam<std::string>(
      40             :       "y_title", "The title of the column/row containing the y data in the data file");
      41      224877 :   params.addParam<bool>(
      42      149918 :       "xy_in_file_only", true, "If the data file only contains abscissa and ordinate data");
      43       74959 :   MooseEnum format("columns=0 rows=1", "rows");
      44       74959 :   params.addParam<MooseEnum>(
      45             :       "format", format, "Format of csv data file that is in either in columns or rows");
      46             : 
      47             :   // Data from JSON parameters
      48       74959 :   params.addParam<UserObjectName>("json_uo", "JSONFileReader holding the data");
      49       74959 :   params.addParam<std::vector<std::string>>(
      50             :       "x_keys", "Ordered vector of keys in the JSON tree to obtain the abscissa");
      51       74959 :   params.addParam<std::vector<std::string>>(
      52             :       "y_keys", "Ordered vector of keys in the JSON tree to obtain the ordinate");
      53             : 
      54       74959 :   params.addParamNamesToGroup("xy_data x y", "Data from input file");
      55       74959 :   params.addParamNamesToGroup(
      56             :       "data_file x_index_in_file y_index_in_file x_title y_title xy_in_file_only format",
      57             :       "Data from CSV file");
      58       74959 :   params.addParamNamesToGroup("json_uo x_keys y_keys", "Data from JSON");
      59      149918 :   return params;
      60       74959 : }
      61             : 
      62        1912 : PiecewiseTabularBase::PiecewiseTabularBase(const InputParameters & parameters)
      63             :   : PiecewiseBase(parameters),
      64        1912 :     _scale_factor(this->template getParam<Real>("scale_factor")),
      65        1912 :     _has_axis(isParamValid("axis")),
      66        1912 :     _raw_data_loaded(false)
      67             : {
      68             :   // determine function argument
      69        1912 :   if (_has_axis)
      70         220 :     _axis = this->template getParam<MooseEnum>("axis");
      71             : 
      72             :   // Check all parameters for inconsistencies
      73        3824 :   if (isParamValid("data_file") + isParamValid("json_uo") +
      74        1912 :           (isParamValid("x") || isParamValid("y")) + isParamValid("xy_data") >
      75             :       1)
      76           8 :     mooseError("Either 'data_file' or 'json_uo' or 'x' and 'y' or 'xy_data' must be specified "
      77             :                "exclusively.");
      78        1904 :   if ((isParamValid("x") + isParamValid("y")) % 2 != 0)
      79           4 :     mooseError(
      80             :         "Both 'x' and 'y' parameters or neither (for another input method) must be specified");
      81        5461 :   if (!isParamValid("data_file") &&
      82        3561 :       (isParamSetByUser("x_index_in_file") || isParamSetByUser("y_index_in_file") ||
      83        3561 :        isParamValid("x_title") || isParamValid("y_title") || isParamSetByUser("xy_in_file_only") ||
      84        3557 :        isParamSetByUser("format")))
      85           4 :     mooseError(
      86             :         "A parameter was passed for an option using data from a CSV file but the "
      87             :         "'data_file' parameter has not been set. This is not allowed. Please check the parameter "
      88             :         "groups in the documentation for the list of parameters for each data input method.");
      89        1896 :   if (!isParamValid("json_uo") && (isParamValid("x_keys") || isParamValid("y_keys")))
      90           4 :     mooseError("A parameter was passed for a JSON input option but the 'json_uo' parameter has not "
      91             :                "been set. This is not allowed. Please check the parameter groups in the "
      92             :                "documentation for the list of parameters for each data input method.");
      93             : 
      94             :   // load the data
      95        1892 :   if (isParamValid("data_file"))
      96         239 :     buildFromFile();
      97        1653 :   else if (isParamValid("x") && isParamValid("y"))
      98        1576 :     buildFromXandY();
      99          77 :   else if (isParamValid("xy_data"))
     100          60 :     buildFromXY();
     101          17 :   else if (!isParamValid("json_uo"))
     102           4 :     mooseError("Unknown X-Y data source. Are you missing a parameter? Did you misspell one?");
     103             :   // JSON data is not available at construction as we rely on a user object
     104        1840 : }
     105             : 
     106             : void
     107        1790 : PiecewiseTabularBase::initialSetup()
     108             : {
     109             :   // For JSON UO input, we need to wait for initialSetup to load the data
     110        1790 :   if (!isParamValid("json_uo"))
     111        1777 :     return;
     112             :   else
     113          13 :     buildFromJSON();
     114             : }
     115             : 
     116             : void
     117         239 : PiecewiseTabularBase::buildFromFile()
     118             : {
     119             :   // Input parameters
     120         239 :   const auto & data_file_name = this->template getParam<FileName>("data_file");
     121         239 :   const MooseEnum format = this->template getParam<MooseEnum>("format");
     122             : 
     123             :   // xy_in_file_only does not make sense here as it restricts the file to exactly
     124             :   // two cows/columns, which is not a likely scenario when looking up data by name.
     125             :   // A wrong 'format' parameter would be caught by the failing name resolution anyways.
     126         239 :   bool xy_only = this->template getParam<bool>("xy_in_file_only");
     127         239 :   if (isParamValid("x_title") || isParamValid("y_title"))
     128             :   {
     129          26 :     if (this->_pars.isParamSetByUser("xy_in_file_only") && xy_only)
     130           0 :       paramError(
     131             :           "xy_in_file_only",
     132             :           "When accessing data through 'x_title' or 'y_title' this parameter should not be used");
     133             :     else
     134          26 :       xy_only = false;
     135             :   }
     136             : 
     137             :   // Read the data from CSV file
     138         239 :   MooseUtils::DelimitedFileReader reader(data_file_name, &_communicator);
     139         239 :   reader.setFormatFlag(format.getEnum<MooseUtils::DelimitedFileReader::FormatFlag>());
     140         239 :   reader.setComment("#");
     141         239 :   reader.read();
     142             : 
     143         235 :   const auto & columns = reader.getNames();
     144         235 :   const auto & data = reader.getData();
     145             : 
     146         235 :   if (data.size() > 2 && xy_only)
     147          32 :     mooseError("In ",
     148          16 :                _name,
     149             :                ": Read more than two ",
     150             :                format,
     151             :                " of data from file '",
     152             :                data_file_name,
     153             :                "'.  Did you mean to use \"format = ",
     154          16 :                format == "columns" ? "rows" : "columns",
     155             :                "\" or set \"xy_in_file_only\" to false?");
     156             : 
     157         219 :   unsigned int x_index = libMesh::invalid_uint;
     158         219 :   unsigned int y_index = libMesh::invalid_uint;
     159         430 :   const auto setIndex = [&](unsigned int & index, const std::string & prefix)
     160             :   {
     161         430 :     if (isParamValid(prefix + "_title"))
     162             :     {
     163          52 :       const auto name = this->template getParam<std::string>(prefix + "_title");
     164         208 :       for (const auto i : index_range(columns))
     165         156 :         if (columns[i] == name)
     166          52 :           index = i;
     167             : 
     168          52 :       if (index == libMesh::invalid_uint)
     169           0 :         paramError(prefix + "_title",
     170             :                    "None of the ",
     171           0 :                    format,
     172             :                    " in the data file has the title '",
     173             :                    name,
     174             :                    "'.");
     175          52 :     }
     176             :     else
     177         378 :       index = this->template getParam<unsigned int>(prefix + "_index_in_file");
     178             : 
     179         430 :     if (index >= data.size())
     180          32 :       paramError(prefix + "_index_in_file",
     181             :                  "Index out-of-range of the available data in '",
     182          16 :                  data_file_name,
     183             :                  "', which contains ",
     184             :                  data.size(),
     185             :                  " ",
     186             :                  format,
     187             :                  " of data.");
     188         414 :   };
     189             : 
     190         219 :   setIndex(x_index, "x");
     191         211 :   setIndex(y_index, "y");
     192             : 
     193         203 :   if (x_index == y_index)
     194           4 :     mooseError(
     195           4 :         "In ", _name, ": 'x_index_in_file' and 'y_index_in_file' are set to the same value.");
     196             : 
     197             :   // Update the input vectors to contained the desired data
     198         199 :   _raw_x = reader.getData(x_index);
     199         199 :   _raw_y = reader.getData(y_index);
     200             : 
     201             :   // Size mismatch error
     202         199 :   if (_raw_x.size() != _raw_y.size())
     203           4 :     mooseError("In ", _name, ": Lengths of x and y data do not match.");
     204             : 
     205         195 :   _raw_data_loaded = true;
     206         195 : }
     207             : 
     208             : void
     209          13 : PiecewiseTabularBase::buildFromJSON()
     210             : {
     211          13 :   auto & json_uo = getUserObject<JSONFileReader>("json_uo");
     212          13 :   if (!isParamValid("x_keys"))
     213           0 :     mooseError("Missing 'x_keys' parameters for loading data from JSON");
     214          13 :   if (!isParamValid("y_keys"))
     215           0 :     mooseError("Missing 'y_keys' parameters for loading data from JSON");
     216          13 :   json_uo.getVector<Real>(getParam<std::vector<std::string>>("x_keys"), _raw_x);
     217          13 :   json_uo.getVector<Real>(getParam<std::vector<std::string>>("y_keys"), _raw_y);
     218          13 :   _raw_data_loaded = true;
     219             : 
     220             :   // Size mismatch error
     221          13 :   if (_raw_x.size() != _raw_y.size())
     222           0 :     mooseError("Lengths of x (", _raw_x.size(), ") and y (", _raw_y.size(), ") data do not match.");
     223          13 : }
     224             : 
     225             : void
     226        1576 : PiecewiseTabularBase::buildFromXandY()
     227             : {
     228        1576 :   _raw_x = this->template getParam<std::vector<Real>>("x");
     229        1576 :   _raw_y = this->template getParam<std::vector<Real>>("y");
     230        1576 :   _raw_data_loaded = true;
     231        1576 : }
     232             : 
     233             : void
     234          60 : PiecewiseTabularBase::buildFromXY()
     235             : {
     236          60 :   const auto & xy = this->template getParam<std::vector<Real>>("xy_data");
     237          60 :   const auto xy_size = xy.size();
     238          60 :   if (xy_size % 2 != 0)
     239           4 :     mooseError("In ", _name, ": Length of data provided in 'xy_data' must be a multiple of 2.");
     240             : 
     241          56 :   const auto data_size = xy_size / 2;
     242          56 :   _raw_x.resize(data_size);
     243          56 :   _raw_y.resize(data_size);
     244         256 :   for (const auto i : make_range(data_size))
     245             :   {
     246         200 :     _raw_x[i] = xy[2 * i];
     247         200 :     _raw_y[i] = xy[2 * i + 1];
     248             :   }
     249          56 :   _raw_data_loaded = true;
     250          56 : }

Generated by: LCOV version 1.14