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 77733 : PiecewiseTabularBase::validParams()
17 : {
18 77733 : InputParameters params = PiecewiseBase::validParams();
19 :
20 : // Parameters shared across all data input methods
21 310932 : MooseEnum axis("x=0 y=1 z=2");
22 310932 : params.addParam<MooseEnum>(
23 : "axis", axis, "The axis used (x, y, or z) if this is to be a function of position");
24 233199 : params.addParam<Real>("scale_factor", 1.0, "Scale factor to be applied to the output values");
25 233199 : params.declareControllable("scale_factor");
26 :
27 : // Data from input file parameters
28 310932 : params.addParam<std::vector<Real>>("xy_data",
29 : "All function data, supplied in abscissa, ordinate pairs");
30 310932 : params.addParam<std::vector<Real>>("x", "The abscissa values");
31 310932 : params.addParam<std::vector<Real>>("y", "The ordinate values");
32 :
33 : // Data from CSV file parameters
34 310932 : params.addParam<FileName>("data_file", "File holding CSV data");
35 310932 : params.addParam<unsigned int>("x_index_in_file", 0, "The abscissa index in the data file");
36 310932 : params.addParam<unsigned int>("y_index_in_file", 1, "The ordinate index in the data file");
37 310932 : params.addParam<std::string>(
38 : "x_title", "The title of the column/row containing the x data in the data file");
39 310932 : params.addParam<std::string>(
40 : "y_title", "The title of the column/row containing the y data in the data file");
41 233199 : params.addParam<bool>(
42 155466 : "xy_in_file_only", true, "If the data file only contains abscissa and ordinate data");
43 310932 : MooseEnum format("columns=0 rows=1", "rows");
44 310932 : 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 310932 : params.addParam<UserObjectName>("json_uo", "JSONFileReader holding the data");
49 310932 : params.addParam<std::vector<std::string>>(
50 : "x_keys", "Ordered vector of keys in the JSON tree to obtain the abscissa");
51 310932 : params.addParam<std::vector<std::string>>(
52 : "y_keys", "Ordered vector of keys in the JSON tree to obtain the ordinate");
53 :
54 310932 : params.addParamNamesToGroup("xy_data x y", "Data from input file");
55 310932 : 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 233199 : params.addParamNamesToGroup("json_uo x_keys y_keys", "Data from JSON");
59 155466 : return params;
60 77733 : }
61 :
62 2083 : PiecewiseTabularBase::PiecewiseTabularBase(const InputParameters & parameters)
63 : : PiecewiseBase(parameters),
64 2083 : _scale_factor(this->template getParam<Real>("scale_factor")),
65 4166 : _has_axis(isParamValid("axis")),
66 2083 : _raw_data_loaded(false)
67 : {
68 : // determine function argument
69 2083 : if (_has_axis)
70 708 : _axis = this->template getParam<MooseEnum>("axis");
71 :
72 : // Check all parameters for inconsistencies
73 10415 : if (isParamValid("data_file") + isParamValid("json_uo") +
74 11153 : (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 10375 : 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 10085 : if (!isParamValid("data_file") &&
82 11076 : (isParamSetByUser("x_index_in_file") || isParamSetByUser("y_index_in_file") ||
83 14662 : isParamValid("x_title") || isParamValid("y_title") || isParamSetByUser("xy_in_file_only") ||
84 7462 : 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 14405 : 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 6189 : if (isParamValid("data_file"))
96 270 : buildFromFile();
97 8791 : else if (isParamValid("x") && isParamValid("y"))
98 1706 : buildFromXandY();
99 261 : else if (isParamValid("xy_data"))
100 69 : buildFromXY();
101 54 : 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 2011 : }
105 :
106 : void
107 1933 : PiecewiseTabularBase::initialSetup()
108 : {
109 : // For JSON UO input, we need to wait for initialSetup to load the data
110 5799 : if (!isParamValid("json_uo"))
111 1919 : return;
112 : else
113 14 : buildFromJSON();
114 : }
115 :
116 : void
117 270 : PiecewiseTabularBase::buildFromFile()
118 : {
119 : // Input parameters
120 540 : const auto & data_file_name = this->template getParam<FileName>("data_file");
121 540 : 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 540 : bool xy_only = this->template getParam<bool>("xy_in_file_only");
127 1290 : if (isParamValid("x_title") || isParamValid("y_title"))
128 : {
129 90 : 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 30 : xy_only = false;
135 : }
136 :
137 : // Read the data from CSV file
138 270 : MooseUtils::DelimitedFileReader reader(data_file_name, &_communicator);
139 270 : reader.setFormatFlag(format.getEnum<MooseUtils::DelimitedFileReader::FormatFlag>());
140 270 : reader.setComment("#");
141 270 : reader.read();
142 :
143 266 : const auto & columns = reader.getNames();
144 266 : const auto & data = reader.getData();
145 :
146 266 : 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 250 : unsigned int x_index = libMesh::invalid_uint;
158 250 : unsigned int y_index = libMesh::invalid_uint;
159 492 : const auto setIndex = [&](unsigned int & index, const std::string & prefix)
160 : {
161 492 : if (isParamValid(prefix + "_title"))
162 : {
163 60 : const auto name = this->template getParam<std::string>(prefix + "_title");
164 240 : for (const auto i : index_range(columns))
165 180 : if (columns[i] == name)
166 60 : index = i;
167 :
168 60 : if (index == libMesh::invalid_uint)
169 0 : paramError(prefix + "_title",
170 : "None of the ",
171 : format,
172 : " in the data file has the title '",
173 : name,
174 : "'.");
175 60 : }
176 : else
177 432 : index = this->template getParam<unsigned int>(prefix + "_index_in_file");
178 :
179 492 : if (index >= data.size())
180 16 : 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 726 : };
189 :
190 492 : setIndex(x_index, "x");
191 242 : setIndex(y_index, "y");
192 :
193 234 : 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 230 : _raw_x = reader.getData(x_index);
199 230 : _raw_y = reader.getData(y_index);
200 :
201 : // Size mismatch error
202 230 : if (_raw_x.size() != _raw_y.size())
203 6 : mooseError("In ", _name, ": Lengths of x and y data do not match.");
204 :
205 224 : _raw_data_loaded = true;
206 228 : }
207 :
208 : void
209 14 : PiecewiseTabularBase::buildFromJSON()
210 : {
211 28 : auto & json_uo = getUserObject<JSONFileReader>("json_uo");
212 42 : if (!isParamValid("x_keys"))
213 0 : mooseError("Missing 'x_keys' parameters for loading data from JSON");
214 42 : if (!isParamValid("y_keys"))
215 0 : mooseError("Missing 'y_keys' parameters for loading data from JSON");
216 28 : json_uo.getVector<Real>(getParam<std::vector<std::string>>("x_keys"), _raw_x);
217 28 : json_uo.getVector<Real>(getParam<std::vector<std::string>>("y_keys"), _raw_y);
218 14 : _raw_data_loaded = true;
219 :
220 : // Size mismatch error
221 14 : 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 14 : }
224 :
225 : void
226 1706 : PiecewiseTabularBase::buildFromXandY()
227 : {
228 3412 : _raw_x = this->template getParam<std::vector<Real>>("x");
229 3412 : _raw_y = this->template getParam<std::vector<Real>>("y");
230 1706 : _raw_data_loaded = true;
231 1706 : }
232 :
233 : void
234 69 : PiecewiseTabularBase::buildFromXY()
235 : {
236 138 : const auto & xy = this->template getParam<std::vector<Real>>("xy_data");
237 69 : const auto xy_size = xy.size();
238 69 : 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 65 : const auto data_size = xy_size / 2;
242 65 : _raw_x.resize(data_size);
243 65 : _raw_y.resize(data_size);
244 310 : for (const auto i : make_range(data_size))
245 : {
246 245 : _raw_x[i] = xy[2 * i];
247 245 : _raw_y[i] = xy[2 * i + 1];
248 : }
249 65 : _raw_data_loaded = true;
250 65 : }
|