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 "PiecewiseBilinear.h"
11 : #include "ColumnMajorMatrix.h"
12 : #include "BilinearInterpolation.h"
13 : #include "MooseUtils.h"
14 :
15 : #include <fstream>
16 :
17 : registerMooseObject("MooseApp", PiecewiseBilinear);
18 :
19 : InputParameters
20 3400 : PiecewiseBilinear::validParams()
21 : {
22 3400 : InputParameters params = Function::validParams();
23 13600 : params.addParam<FileName>(
24 : "data_file", "", "File holding csv data for use with PiecewiseBilinear");
25 13600 : params.addParam<std::vector<Real>>("x", "The x abscissa values");
26 13600 : params.addParam<std::vector<Real>>("y", "The y abscissa values");
27 13600 : params.addParam<std::vector<Real>>("z", "The ordinate values");
28 13600 : params.addParam<int>("axis", -1, "The axis used (0, 1, or 2 for x, y, or z).");
29 10200 : params.addParam<int>(
30 6800 : "xaxis", -1, "The coordinate used for x-axis data (0, 1, or 2 for x, y, or z).");
31 10200 : params.addParam<int>(
32 6800 : "yaxis", -1, "The coordinate used for y-axis data (0, 1, or 2 for x, y, or z).");
33 10200 : params.addParam<Real>(
34 6800 : "scale_factor", 1.0, "Scale factor to be applied to the axis, yaxis, or xaxis values");
35 10200 : params.addParam<bool>("radial",
36 6800 : false,
37 : "Set to true if you want to interpolate along a radius "
38 : "rather that along a specific axis, and note that you "
39 : "have to define xaxis and yaxis in the input file");
40 3400 : params.addClassDescription("Interpolates values from a csv file");
41 3400 : return params;
42 0 : }
43 :
44 165 : PiecewiseBilinear::PiecewiseBilinear(const InputParameters & parameters)
45 : : Function(parameters),
46 165 : _xaxis(getParam<int>("xaxis")),
47 330 : _yaxis(getParam<int>("yaxis")),
48 330 : _data_file_name(getParam<FileName>("data_file")),
49 330 : _axis(getParam<int>("axis")),
50 165 : _axisValid(_axis > -1 && _axis < 3),
51 165 : _yaxisValid(_yaxis > -1 && _yaxis < 3),
52 165 : _xaxisValid(_xaxis > -1 && _xaxis < 3),
53 330 : _scale_factor(getParam<Real>("scale_factor")),
54 660 : _radial(getParam<bool>("radial"))
55 : {
56 :
57 165 : if (!_axisValid && !_yaxisValid && !_xaxisValid)
58 0 : mooseError("In PiecewiseBilinear ",
59 0 : _name,
60 : ": None of axis, yaxis, or xaxis properly defined. Allowable range is 0-2");
61 :
62 165 : if (_axisValid && (_yaxisValid || _xaxisValid))
63 0 : mooseError("In PiecewiseBilinear ", _name, ": Cannot define axis with either yaxis or xaxis");
64 :
65 165 : if (_radial && (!_yaxisValid || !_xaxisValid))
66 0 : mooseError(
67 0 : "In PiecewiseBilinear ", _name, ": yaxis and xaxis must be defined when radial = true");
68 :
69 165 : std::vector<Real> x;
70 165 : std::vector<Real> y;
71 165 : ColumnMajorMatrix z;
72 165 : std::vector<Real> z_vec;
73 :
74 165 : if (!_data_file_name.empty())
75 : {
76 558 : if (parameters.isParamValid("x") || parameters.isParamValid("y") ||
77 237 : parameters.isParamValid("z"))
78 3 : mooseError("In PiecewiseBilinear: Cannot specify 'data_file' and 'x', 'y', or 'z' together.");
79 : else
80 78 : parse(_data_file_name, x, y, z, name());
81 : }
82 :
83 579 : else if (!(parameters.isParamValid("x") && parameters.isParamValid("y") &&
84 246 : parameters.isParamValid("z")))
85 3 : mooseError("In PiecewiseBilinear: 'x' and 'y' and 'z' must be specified if any one is "
86 : "specified or no 'data_file' is specified.");
87 :
88 : else
89 : {
90 162 : x = getParam<std::vector<Real>>("x");
91 162 : y = getParam<std::vector<Real>>("y");
92 162 : z_vec = getParam<std::vector<Real>>("z");
93 :
94 : // check that size of z = (size of x)*(size of y)
95 81 : if (z_vec.size() != x.size() * y.size())
96 3 : mooseError("In PiecewiseBilinear: Size of z should be the size of x times the size of y.");
97 :
98 : // reshape and populate z matrix
99 78 : z.reshape(y.size(), x.size());
100 78 : int idx = 0;
101 312 : for (unsigned int i = 0; i < y.size(); i++)
102 936 : for (unsigned int j = 0; j < x.size(); j++)
103 : {
104 702 : z(i, j) = z_vec[idx];
105 702 : idx += 1;
106 : }
107 : }
108 :
109 156 : _bilinear_interp = std::make_unique<BilinearInterpolation>(x, y, z);
110 156 : }
111 :
112 156 : PiecewiseBilinear::~PiecewiseBilinear() {}
113 :
114 : Real
115 3264 : PiecewiseBilinear::value(Real t, const Point & p) const
116 : {
117 3264 : return valueInternal(t, p);
118 : }
119 :
120 : ADReal
121 0 : PiecewiseBilinear::value(const ADReal & t, const ADPoint & p) const
122 : {
123 0 : return valueInternal(t, p);
124 : }
125 :
126 : template <typename T, typename P>
127 : T
128 3264 : PiecewiseBilinear::valueInternal(T t, const P & p) const
129 : {
130 3264 : T retVal = 0.0;
131 3264 : if (_yaxisValid && _xaxisValid && _radial)
132 : {
133 544 : const auto rx = p(_xaxis) * p(_xaxis);
134 544 : const auto ry = p(_yaxis) * p(_yaxis);
135 : using std::sqrt;
136 544 : const auto r = sqrt(rx + ry);
137 544 : retVal = _bilinear_interp->sample(r, t);
138 544 : }
139 2720 : else if (_axisValid)
140 1088 : retVal = _bilinear_interp->sample(p(_axis), t);
141 1632 : else if (_yaxisValid && !_radial)
142 : {
143 1088 : if (_xaxisValid)
144 544 : retVal = _bilinear_interp->sample(p(_xaxis), p(_yaxis));
145 : else
146 544 : retVal = _bilinear_interp->sample(t, p(_yaxis));
147 : }
148 : else
149 544 : retVal = _bilinear_interp->sample(p(_xaxis), t);
150 :
151 3264 : return retVal * _scale_factor;
152 0 : }
153 :
154 : void
155 78 : PiecewiseBilinear::parse(const std::string & data_file_name,
156 : std::vector<Real> & x,
157 : std::vector<Real> & y,
158 : ColumnMajorMatrix & z,
159 : const std::string & object_name)
160 : {
161 78 : std::ifstream file(data_file_name.c_str());
162 78 : if (!file.good())
163 0 : ::mooseError(object_name, " : Error opening file '", data_file_name, "'.");
164 :
165 78 : std::size_t num_lines = 0;
166 78 : std::size_t num_cols = libMesh::invalid_uint;
167 78 : std::vector<Real> data;
168 :
169 78 : std::string line;
170 78 : std::vector<Real> line_data;
171 390 : while (std::getline(file, line))
172 : {
173 312 : num_lines++;
174 624 : if (!MooseUtils::tokenizeAndConvert<double>(line, line_data, ", "))
175 0 : ::mooseError(object_name, " : Error parsing file '", data_file_name, "' on line ", num_lines);
176 :
177 312 : data.insert(data.end(), line_data.begin(), line_data.end());
178 :
179 312 : if (num_cols == libMesh::invalid_uint)
180 78 : num_cols = line_data.size();
181 234 : else if (line_data.size() != num_cols + 1)
182 0 : ::mooseError(object_name,
183 : " : Read ",
184 0 : line_data.size(),
185 : " columns of data but expected ",
186 0 : num_cols + 1,
187 : " columns in line ",
188 : num_lines);
189 : }
190 :
191 78 : x.resize(num_cols);
192 78 : y.resize(num_lines - 1);
193 78 : z.reshape(num_lines - 1, num_cols);
194 78 : std::size_t offset = 0;
195 :
196 : // Extract the first line's data (the x axis data)
197 312 : for (unsigned int j = 0; j < num_cols; ++j)
198 234 : x[j] = data[offset++];
199 :
200 312 : for (unsigned int i = 0; i < num_lines - 1; ++i)
201 : {
202 : // Extract the y axis entry for this line
203 234 : y[i] = data[offset++];
204 :
205 : // Extract the function values for this row in the matrix
206 936 : for (unsigned int j = 0; j < num_cols; ++j)
207 702 : z(i, j) = data[offset++];
208 : }
209 :
210 78 : if (data.size() != offset)
211 0 : ::mooseError(object_name, " : Inconsistency in data read from '", data_file_name, "'.");
212 78 : }
|