https://mooseframework.inl.gov
PiecewiseTabularBase.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #include "PiecewiseTabularBase.h"
11 #include "DelimitedFileReader.h"
12 #include "JSONFileReader.h"
13 #include "libmesh/int_range.h"
14 
17 {
19 
20  // Parameters shared across all data input methods
21  MooseEnum axis("x=0 y=1 z=2");
22  params.addParam<MooseEnum>(
23  "axis", axis, "The axis used (x, y, or z) if this is to be a function of position");
24  params.addParam<Real>("scale_factor", 1.0, "Scale factor to be applied to the output values");
25  params.declareControllable("scale_factor");
26 
27  // Data from input file parameters
28  params.addParam<std::vector<Real>>("xy_data",
29  "All function data, supplied in abscissa, ordinate pairs");
30  params.addParam<std::vector<Real>>("x", "The abscissa values");
31  params.addParam<std::vector<Real>>("y", "The ordinate values");
32 
33  // Data from CSV file parameters
34  params.addParam<FileName>("data_file", "File holding CSV data");
35  params.addParam<unsigned int>("x_index_in_file", 0, "The abscissa index in the data file");
36  params.addParam<unsigned int>("y_index_in_file", 1, "The ordinate index in the data file");
37  params.addParam<std::string>(
38  "x_title", "The title of the column/row containing the x data in the data file");
39  params.addParam<std::string>(
40  "y_title", "The title of the column/row containing the y data in the data file");
41  params.addParam<bool>(
42  "xy_in_file_only", true, "If the data file only contains abscissa and ordinate data");
43  MooseEnum format("columns=0 rows=1", "rows");
44  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  params.addParam<UserObjectName>("json_uo", "JSONFileReader holding the data");
49  params.addParam<std::vector<std::string>>(
50  "x_keys", "Ordered vector of keys in the JSON tree to obtain the abscissa");
51  params.addParam<std::vector<std::string>>(
52  "y_keys", "Ordered vector of keys in the JSON tree to obtain the ordinate");
53 
54  params.addParamNamesToGroup("xy_data x y", "Data from input file");
55  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  params.addParamNamesToGroup("json_uo x_keys y_keys", "Data from JSON");
59  return params;
60 }
61 
63  : PiecewiseBase(parameters),
64  _scale_factor(this->template getParam<Real>("scale_factor")),
65  _has_axis(isParamValid("axis")),
66  _raw_data_loaded(false)
67 {
68  // determine function argument
69  if (_has_axis)
70  _axis = this->template getParam<MooseEnum>("axis");
71 
72  // Check all parameters for inconsistencies
73  if (isParamValid("data_file") + isParamValid("json_uo") +
74  (isParamValid("x") || isParamValid("y")) + isParamValid("xy_data") >
75  1)
76  mooseError("Either 'data_file' or 'json_uo' or 'x' and 'y' or 'xy_data' must be specified "
77  "exclusively.");
78  if ((isParamValid("x") + isParamValid("y")) % 2 != 0)
79  mooseError(
80  "Both 'x' and 'y' parameters or neither (for another input method) must be specified");
81  if (!isParamValid("data_file") &&
82  (isParamSetByUser("x_index_in_file") || isParamSetByUser("y_index_in_file") ||
83  isParamValid("x_title") || isParamValid("y_title") || isParamSetByUser("xy_in_file_only") ||
84  isParamSetByUser("format")))
85  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  if (!isParamValid("json_uo") && (isParamValid("x_keys") || isParamValid("y_keys")))
90  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  if (isParamValid("data_file"))
96  buildFromFile();
97  else if (isParamValid("x") && isParamValid("y"))
99  else if (isParamValid("xy_data"))
100  buildFromXY();
101  else if (!isParamValid("json_uo"))
102  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 }
105 
106 void
108 {
109  // For JSON UO input, we need to wait for initialSetup to load the data
110  if (!isParamValid("json_uo"))
111  return;
112  else
113  buildFromJSON();
114 }
115 
116 void
118 {
119  // Input parameters
120  const auto & data_file_name = this->template getParam<FileName>("data_file");
121  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  bool xy_only = this->template getParam<bool>("xy_in_file_only");
127  if (isParamValid("x_title") || isParamValid("y_title"))
128  {
129  if (this->_pars.isParamSetByUser("xy_in_file_only") && xy_only)
130  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  xy_only = false;
135  }
136 
137  // Read the data from CSV file
138  MooseUtils::DelimitedFileReader reader(data_file_name, &_communicator);
140  reader.setComment("#");
141  reader.read();
142 
143  const auto & columns = reader.getNames();
144  const auto & data = reader.getData();
145 
146  if (data.size() > 2 && xy_only)
147  mooseError("In ",
148  _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  format == "columns" ? "rows" : "columns",
155  "\" or set \"xy_in_file_only\" to false?");
156 
157  unsigned int x_index = libMesh::invalid_uint;
158  unsigned int y_index = libMesh::invalid_uint;
159  const auto setIndex = [&](unsigned int & index, const std::string & prefix)
160  {
161  if (isParamValid(prefix + "_title"))
162  {
163  const auto name = this->template getParam<std::string>(prefix + "_title");
164  for (const auto i : index_range(columns))
165  if (columns[i] == name)
166  index = i;
167 
168  if (index == libMesh::invalid_uint)
169  paramError(prefix + "_title",
170  "None of the ",
171  format,
172  " in the data file has the title '",
173  name,
174  "'.");
175  }
176  else
177  index = this->template getParam<unsigned int>(prefix + "_index_in_file");
178 
179  if (index >= data.size())
180  paramError(prefix + "_index_in_file",
181  "Index out-of-range of the available data in '",
182  data_file_name,
183  "', which contains ",
184  data.size(),
185  " ",
186  format,
187  " of data.");
188  };
189 
190  setIndex(x_index, "x");
191  setIndex(y_index, "y");
192 
193  if (x_index == y_index)
194  mooseError(
195  "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  _raw_x = reader.getData(x_index);
199  _raw_y = reader.getData(y_index);
200 
201  // Size mismatch error
202  if (_raw_x.size() != _raw_y.size())
203  mooseError("In ", _name, ": Lengths of x and y data do not match.");
204 
205  _raw_data_loaded = true;
206 }
207 
208 void
210 {
211  auto & json_uo = getUserObject<JSONFileReader>("json_uo");
212  if (!isParamValid("x_keys"))
213  mooseError("Missing 'x_keys' parameters for loading data from JSON");
214  if (!isParamValid("y_keys"))
215  mooseError("Missing 'y_keys' parameters for loading data from JSON");
216  json_uo.getVector<Real>(getParam<std::vector<std::string>>("x_keys"), _raw_x);
217  json_uo.getVector<Real>(getParam<std::vector<std::string>>("y_keys"), _raw_y);
218  _raw_data_loaded = true;
219 
220  // Size mismatch error
221  if (_raw_x.size() != _raw_y.size())
222  mooseError("Lengths of x (", _raw_x.size(), ") and y (", _raw_y.size(), ") data do not match.");
223 }
224 
225 void
227 {
228  _raw_x = this->template getParam<std::vector<Real>>("x");
229  _raw_y = this->template getParam<std::vector<Real>>("y");
230  _raw_data_loaded = true;
231 }
232 
233 void
235 {
236  const auto & xy = this->template getParam<std::vector<Real>>("xy_data");
237  const auto xy_size = xy.size();
238  if (xy_size % 2 != 0)
239  mooseError("In ", _name, ": Length of data provided in 'xy_data' must be a multiple of 2.");
240 
241  const auto data_size = xy_size / 2;
242  _raw_x.resize(data_size);
243  _raw_y.resize(data_size);
244  for (const auto i : make_range(data_size))
245  {
246  _raw_x[i] = xy[2 * i];
247  _raw_y[i] = xy[2 * i + 1];
248  }
249  _raw_data_loaded = true;
250 }
Function base which provides a piecewise approximation to a specified (x,y) point data set...
Definition: PiecewiseBase.h:20
const InputParameters & _pars
The object&#39;s parameters.
Definition: MooseBase.h:362
PiecewiseTabularBase(const InputParameters &parameters)
const unsigned int invalid_uint
const std::string & _name
The name of this class.
Definition: MooseBase.h:359
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition: MooseBase.h:435
void setComment(const std::string &value)
static InputParameters validParams()
Definition: PiecewiseBase.C:14
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const Parallel::Communicator & _communicator
void buildFromFile()
Reads data from supplied CSV file.
static InputParameters validParams()
const std::string & name() const
Get the name of the class.
Definition: MooseBase.h:99
std::vector< Real > _raw_x
raw function data as read
Definition: PiecewiseBase.h:39
void buildFromXandY()
Builds data from &#39;x&#39; and &#39;y&#39; parameters.
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition: MooseEnum.h:33
void initialSetup() override
Needed to load data from user objects that are not available at construction.
void read()
Perform the actual data reading.
const std::vector< std::vector< T > > & getData() const
Return the rows/columns of data.
int _axis
if _has_axis is true point component to use as function argument, otherwise use t ...
bool isParamSetByUser(const std::string &name) const
Method returns true if the parameter was set by the user.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Utility class for reading delimited data (e.g., CSV data).
IntRange< T > make_range(T beg, T end)
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
Definition: MooseBase.h:267
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object...
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition: MooseBase.h:195
std::vector< Real > _raw_y
Definition: PiecewiseBase.h:40
void buildFromJSON()
Reads data from supplied JSON reader.
const std::vector< std::string > & getNames() const
Return the column/row names.
bool _raw_data_loaded
Boolean to keep track of whether the data has been loaded.
bool isParamSetByUser(const std::string &name) const
Test if the supplied parameter is set by a user, as opposed to not set or set to default.
Definition: MooseBase.h:201
void declareControllable(const std::string &name, std::set< ExecFlagType > execute_flags={})
Declare the given parameters as controllable.
void buildFromXY()
Builds data from &#39;xy_data&#39; parameter.
auto index_range(const T &sizable)
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
This method takes a space delimited list of parameter names and adds them to the specified group name...