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 14617 : PiecewiseBilinear::validParams()
21 : {
22 14617 : InputParameters params = Function::validParams();
23 14617 : params.addParam<FileName>(
24 : "data_file", "", "File holding csv data for use with PiecewiseBilinear");
25 14617 : params.addParam<std::vector<Real>>("x", "The x abscissa values");
26 14617 : params.addParam<std::vector<Real>>("y", "The y abscissa values");
27 14617 : params.addParam<std::vector<Real>>("z", "The ordinate values");
28 14617 : params.addParam<int>("axis", -1, "The axis used (0, 1, or 2 for x, y, or z).");
29 43851 : params.addParam<int>(
30 29234 : "xaxis", -1, "The coordinate used for x-axis data (0, 1, or 2 for x, y, or z).");
31 43851 : params.addParam<int>(
32 29234 : "yaxis", -1, "The coordinate used for y-axis data (0, 1, or 2 for x, y, or z).");
33 43851 : params.addParam<Real>(
34 29234 : "scale_factor", 1.0, "Scale factor to be applied to the axis, yaxis, or xaxis values");
35 43851 : params.addParam<bool>("radial",
36 29234 : 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 14617 : params.addClassDescription("Interpolates values from a csv file");
41 14617 : return params;
42 0 : }
43 :
44 168 : PiecewiseBilinear::PiecewiseBilinear(const InputParameters & parameters)
45 : : Function(parameters),
46 168 : _data_file_name(getParam<FileName>("data_file")),
47 168 : _axis(getParam<int>("axis")),
48 168 : _yaxis(getParam<int>("yaxis")),
49 168 : _xaxis(getParam<int>("xaxis")),
50 168 : _axisValid(_axis > -1 && _axis < 3),
51 168 : _yaxisValid(_yaxis > -1 && _yaxis < 3),
52 168 : _xaxisValid(_xaxis > -1 && _xaxis < 3),
53 168 : _scale_factor(getParam<Real>("scale_factor")),
54 336 : _radial(getParam<bool>("radial"))
55 : {
56 :
57 168 : 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 168 : if (_axisValid && (_yaxisValid || _xaxisValid))
63 0 : mooseError("In PiecewiseBilinear ", _name, ": Cannot define axis with either yaxis or xaxis");
64 :
65 168 : if (_radial && (!_yaxisValid || !_xaxisValid))
66 0 : mooseError(
67 0 : "In PiecewiseBilinear ", _name, ": yaxis and xaxis must be defined when radial = true");
68 :
69 168 : std::vector<Real> x;
70 168 : std::vector<Real> y;
71 168 : ColumnMajorMatrix z;
72 168 : std::vector<Real> z_vec;
73 :
74 168 : if (!_data_file_name.empty())
75 : {
76 242 : if (parameters.isParamValid("x") || parameters.isParamValid("y") ||
77 160 : parameters.isParamValid("z"))
78 4 : 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 254 : else if (!(parameters.isParamValid("x") && parameters.isParamValid("y") &&
84 168 : parameters.isParamValid("z")))
85 4 : 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 82 : x = getParam<std::vector<Real>>("x");
91 82 : y = getParam<std::vector<Real>>("y");
92 82 : z_vec = getParam<std::vector<Real>>("z");
93 :
94 : // check that size of z = (size of x)*(size of y)
95 82 : if (z_vec.size() != x.size() * y.size())
96 4 : 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 312 : PiecewiseBilinear::~PiecewiseBilinear() {}
113 :
114 : Real
115 3072 : PiecewiseBilinear::value(Real t, const Point & p) const
116 : {
117 3072 : 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 3072 : PiecewiseBilinear::valueInternal(T t, const P & p) const
129 : {
130 3072 : T retVal = 0.0;
131 3072 : if (_yaxisValid && _xaxisValid && _radial)
132 : {
133 512 : const auto rx = p(_xaxis) * p(_xaxis);
134 512 : const auto ry = p(_yaxis) * p(_yaxis);
135 512 : const auto r = std::sqrt(rx + ry);
136 512 : retVal = _bilinear_interp->sample(r, t);
137 512 : }
138 2560 : else if (_axisValid)
139 1024 : retVal = _bilinear_interp->sample(p(_axis), t);
140 1536 : else if (_yaxisValid && !_radial)
141 : {
142 1024 : if (_xaxisValid)
143 512 : retVal = _bilinear_interp->sample(p(_xaxis), p(_yaxis));
144 : else
145 512 : retVal = _bilinear_interp->sample(t, p(_yaxis));
146 : }
147 : else
148 512 : retVal = _bilinear_interp->sample(p(_xaxis), t);
149 :
150 3072 : return retVal * _scale_factor;
151 0 : }
152 :
153 : void
154 78 : PiecewiseBilinear::parse(const std::string & data_file_name,
155 : std::vector<Real> & x,
156 : std::vector<Real> & y,
157 : ColumnMajorMatrix & z,
158 : const std::string & object_name)
159 : {
160 78 : std::ifstream file(data_file_name.c_str());
161 78 : if (!file.good())
162 0 : ::mooseError(object_name, " : Error opening file '", data_file_name, "'.");
163 :
164 78 : std::size_t num_lines = 0;
165 78 : std::size_t num_cols = libMesh::invalid_uint;
166 78 : std::vector<Real> data;
167 :
168 78 : std::string line;
169 78 : std::vector<Real> line_data;
170 390 : while (std::getline(file, line))
171 : {
172 312 : num_lines++;
173 312 : if (!MooseUtils::tokenizeAndConvert<double>(line, line_data, ", "))
174 0 : ::mooseError(object_name, " : Error parsing file '", data_file_name, "' on line ", num_lines);
175 :
176 312 : data.insert(data.end(), line_data.begin(), line_data.end());
177 :
178 312 : if (num_cols == libMesh::invalid_uint)
179 78 : num_cols = line_data.size();
180 234 : else if (line_data.size() != num_cols + 1)
181 0 : ::mooseError(object_name,
182 : " : Read ",
183 0 : line_data.size(),
184 : " columns of data but expected ",
185 0 : num_cols + 1,
186 : " columns in line ",
187 : num_lines);
188 : }
189 :
190 78 : x.resize(num_cols);
191 78 : y.resize(num_lines - 1);
192 78 : z.reshape(num_lines - 1, num_cols);
193 78 : std::size_t offset = 0;
194 :
195 : // Extract the first line's data (the x axis data)
196 312 : for (unsigned int j = 0; j < num_cols; ++j)
197 234 : x[j] = data[offset++];
198 :
199 312 : for (unsigned int i = 0; i < num_lines - 1; ++i)
200 : {
201 : // Extract the y axis entry for this line
202 234 : y[i] = data[offset++];
203 :
204 : // Extract the function values for this row in the matrix
205 936 : for (unsigned int j = 0; j < num_cols; ++j)
206 702 : z(i, j) = data[offset++];
207 : }
208 :
209 78 : if (data.size() != offset)
210 0 : ::mooseError(object_name, " : Inconsistency in data read from '", data_file_name, "'.");
211 78 : }
|