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 "PiecewiseTabularInterface.h"
11 : #include "DelimitedFileReader.h"
12 : #include "JSONFileReader.h"
13 :
14 : #include "libmesh/int_range.h"
15 :
16 : InputParameters
17 84305 : PiecewiseTabularInterface::validParams()
18 : {
19 84305 : InputParameters params = emptyInputParameters();
20 :
21 : // Parameters shared across all data input methods
22 337220 : MooseEnum axis("x=0 y=1 z=2");
23 337220 : params.addParam<MooseEnum>(
24 : "axis", axis, "The axis used (x, y, or z) if this is to be a function of position");
25 :
26 : // Data from input file parameters
27 337220 : params.addParam<std::vector<Real>>("xy_data",
28 : "All function data, supplied in abscissa, ordinate pairs");
29 337220 : params.addParam<std::vector<Real>>("x", "The abscissa values");
30 337220 : params.addParam<std::vector<Real>>("y", "The ordinate values");
31 :
32 : // Data from CSV file parameters
33 337220 : params.addParam<FileName>("data_file", "File holding CSV data");
34 337220 : params.addParam<unsigned int>("x_index_in_file", 0, "The abscissa index in the data file");
35 337220 : params.addParam<unsigned int>("y_index_in_file", 1, "The ordinate index in the data file");
36 337220 : params.addParam<std::string>(
37 : "x_title", "The title of the column/row containing the x data in the data file");
38 337220 : params.addParam<std::string>(
39 : "y_title", "The title of the column/row containing the y data in the data file");
40 252915 : params.addParam<bool>(
41 168610 : "xy_in_file_only", true, "If the data file only contains abscissa and ordinate data");
42 337220 : MooseEnum format("columns=0 rows=1", "rows");
43 337220 : params.addParam<MooseEnum>(
44 : "format", format, "Format of csv data file that is in either in columns or rows");
45 :
46 : // Data from JSON parameters
47 337220 : params.addParam<UserObjectName>("json_uo", "JSONFileReader holding the data");
48 337220 : params.addParam<std::vector<std::string>>(
49 : "x_keys", "Ordered vector of keys in the JSON tree to obtain the abscissa");
50 337220 : params.addParam<std::vector<std::string>>(
51 : "y_keys", "Ordered vector of keys in the JSON tree to obtain the ordinate");
52 :
53 337220 : params.addParamNamesToGroup("xy_data x y", "Data from input file");
54 337220 : params.addParamNamesToGroup(
55 : "data_file x_index_in_file y_index_in_file x_title y_title xy_in_file_only format",
56 : "Data from CSV file");
57 252915 : params.addParamNamesToGroup("json_uo x_keys y_keys", "Data from JSON");
58 :
59 168610 : return params;
60 84305 : }
61 :
62 2253 : PiecewiseTabularInterface::PiecewiseTabularInterface(const MooseObject & object,
63 : std::vector<Real> & data_x,
64 2253 : std::vector<Real> & data_y)
65 4506 : : _has_axis(object.isParamValid("axis")),
66 2253 : _object(object),
67 2253 : _parameters(object.parameters()),
68 2253 : _data_x(data_x),
69 2253 : _data_y(data_y)
70 : {
71 : // determine function argument
72 2253 : if (_has_axis)
73 236 : _axis = _parameters.get<MooseEnum>("axis");
74 :
75 : // Check all parameters for inconsistencies
76 11265 : if (_parameters.isParamValid("data_file") + _parameters.isParamValid("json_uo") +
77 9966 : (_parameters.isParamValid("x") || _parameters.isParamValid("y")) +
78 6759 : _parameters.isParamValid("xy_data") >
79 : 1)
80 8 : _object.mooseError(
81 : "Either 'data_file' or 'json_uo' or 'x' and 'y' or 'xy_data' must be specified "
82 : "exclusively.");
83 11225 : if ((_parameters.isParamValid("x") + _parameters.isParamValid("y")) % 2 != 0)
84 4 : _object.mooseError(
85 : "Both 'x' and 'y' parameters or neither (for another input method) must be specified");
86 10899 : if (!_parameters.isParamValid("data_file") &&
87 8046 : (_parameters.isParamSetByUser("x_index_in_file") ||
88 13851 : _parameters.isParamSetByUser("y_index_in_file") || _parameters.isParamValid("x_title") ||
89 11896 : _parameters.isParamValid("y_title") || _parameters.isParamSetByUser("xy_in_file_only") ||
90 8034 : _parameters.isParamSetByUser("format")))
91 4 : _object.mooseError(
92 : "A parameter was passed for an option using data from a CSV file but the "
93 : "'data_file' parameter has not been set. This is not allowed. Please check the parameter "
94 : "groups in the documentation for the list of parameters for each data input method.");
95 11135 : if (!_parameters.isParamValid("json_uo") &&
96 13164 : (_parameters.isParamValid("x_keys") || _parameters.isParamValid("y_keys")))
97 4 : _object.mooseError(
98 : "A parameter was passed for a JSON input option but the 'json_uo' parameter has not "
99 : "been set. This is not allowed. Please check the parameter groups in the "
100 : "documentation for the list of parameters for each data input method.");
101 2233 : }
102 :
103 : void
104 306 : PiecewiseTabularInterface::buildFromFile(const libMesh::Parallel::Communicator & comm)
105 : {
106 : // Input parameters
107 306 : const auto & data_file_name = _parameters.get<FileName>("data_file");
108 306 : const MooseEnum & format = _parameters.get<MooseEnum>("format");
109 :
110 : // xy_in_file_only does not make sense here as it restricts the file to exactly
111 : // two cows/columns, which is not a likely scenario when looking up data by name.
112 : // A wrong 'format' parameter would be caught by the failing name resolution anyways.
113 306 : bool xy_only = _parameters.get<bool>("xy_in_file_only");
114 1470 : if (_parameters.isParamValid("x_title") || _parameters.isParamValid("y_title"))
115 : {
116 90 : if (_parameters.isParamSetByUser("xy_in_file_only") && xy_only)
117 0 : _parameters.paramError(
118 : "xy_in_file_only",
119 : "When accessing data through 'x_title' or 'y_title' this parameter should not be used");
120 : else
121 30 : xy_only = false;
122 : }
123 :
124 : // Read the data from CSV file
125 306 : MooseUtils::DelimitedFileReader reader(data_file_name, &comm);
126 306 : reader.setFormatFlag(format.getEnum<MooseUtils::DelimitedFileReader::FormatFlag>());
127 306 : reader.setComment("#");
128 306 : reader.read();
129 :
130 302 : const auto & columns = reader.getNames();
131 302 : const auto & data = reader.getData();
132 :
133 302 : if (data.size() > 2 && xy_only)
134 16 : _object.mooseError("In ",
135 16 : _object.name(),
136 : ": Read more than two ",
137 : format,
138 : " of data from file '",
139 : data_file_name,
140 : "'. Did you mean to use \"format = ",
141 16 : format == "columns" ? "rows" : "columns",
142 : "\" or set \"xy_in_file_only\" to false?");
143 :
144 286 : unsigned int x_index = libMesh::invalid_uint;
145 286 : unsigned int y_index = libMesh::invalid_uint;
146 564 : const auto setIndex = [&](unsigned int & index, const std::string & prefix)
147 : {
148 564 : if (_parameters.isParamValid(prefix + "_title"))
149 : {
150 60 : const auto name = _parameters.get<std::string>(prefix + "_title");
151 240 : for (const auto i : index_range(columns))
152 180 : if (columns[i] == name)
153 60 : index = i;
154 :
155 60 : if (index == libMesh::invalid_uint)
156 0 : _parameters.paramError(prefix + "_title",
157 : "None of the ",
158 : format,
159 : " in the data file has the title '",
160 : name,
161 : "'.");
162 60 : }
163 : else
164 504 : index = _parameters.get<unsigned int>(prefix + "_index_in_file");
165 :
166 564 : if (index >= data.size())
167 16 : _parameters.paramError(prefix + "_index_in_file",
168 : "Index out-of-range of the available data in '",
169 : data_file_name,
170 : "', which contains ",
171 : data.size(),
172 : " ",
173 : format,
174 : " of data.");
175 834 : };
176 :
177 564 : setIndex(x_index, "x");
178 278 : setIndex(y_index, "y");
179 :
180 270 : if (x_index == y_index)
181 4 : _object.mooseError("In ",
182 4 : _object.name(),
183 : ": 'x_index_in_file' and 'y_index_in_file' are set to the same value.");
184 :
185 : // Update the input vectors to contained the desired data
186 266 : _data_x = reader.getData(x_index);
187 266 : _data_y = reader.getData(y_index);
188 :
189 : // Size mismatch error
190 266 : if (_data_x.size() != _data_y.size())
191 6 : _object.mooseError("In ", _object.name(), ": Lengths of x and y data do not match.");
192 :
193 260 : _raw_data_loaded = true;
194 262 : }
195 :
196 : void
197 50 : PiecewiseTabularInterface::buildFromJSON(const JSONFileReader & json_uo)
198 : {
199 150 : if (!_parameters.isParamValid("x_keys"))
200 0 : _object.mooseError("Missing 'x_keys' parameters for loading data from JSON");
201 150 : if (!_parameters.isParamValid("y_keys"))
202 0 : _object.mooseError("Missing 'y_keys' parameters for loading data from JSON");
203 50 : json_uo.getVector<Real>(_parameters.get<std::vector<std::string>>("x_keys"), _data_x);
204 50 : json_uo.getVector<Real>(_parameters.get<std::vector<std::string>>("y_keys"), _data_y);
205 50 : _raw_data_loaded = true;
206 :
207 : // Size mismatch error
208 50 : if (_data_x.size() != _data_y.size())
209 0 : _object.mooseError(
210 0 : "Lengths of x (", _data_x.size(), ") and y (", _data_y.size(), ") data do not match.");
211 50 : }
212 :
213 : void
214 1768 : PiecewiseTabularInterface::buildFromXandY()
215 : {
216 1768 : _data_x = _parameters.get<std::vector<Real>>("x");
217 1768 : _data_y = _parameters.get<std::vector<Real>>("y");
218 1768 : _raw_data_loaded = true;
219 1768 : }
220 :
221 : void
222 105 : PiecewiseTabularInterface::buildFromXY()
223 : {
224 105 : const auto & xy = _parameters.get<std::vector<Real>>("xy_data");
225 105 : const auto xy_size = xy.size();
226 105 : if (xy_size % 2 != 0)
227 4 : _object.mooseError(
228 4 : "In ", _object.name(), ": Length of data provided in 'xy_data' must be a multiple of 2.");
229 :
230 101 : const auto data_size = xy_size / 2;
231 101 : _data_x.resize(data_size);
232 101 : _data_y.resize(data_size);
233 418 : for (const auto i : make_range(data_size))
234 : {
235 317 : _data_x[i] = xy[2 * i];
236 317 : _data_y[i] = xy[2 * i + 1];
237 : }
238 101 : _raw_data_loaded = true;
239 101 : }
|