www.mooseframework.org
FunctionSeries.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 <numeric> // Provides accumulate()
11 
12 #include "FunctionalBasisInterface.h" // Provides _domain_options
13 #include "FunctionSeries.h"
14 #include "Cartesian.h"
15 #include "CylindricalDuo.h"
16 
17 registerMooseObject("FunctionalExpansionToolsApp", FunctionSeries);
18 
21 {
23 
24  params.addClassDescription("This function uses a convolution of functional series (functional "
25  "expansion or FX) to create a 1D, 2D, or 3D function");
26 
27  // The available composite series types.
28  // Cartesian: 1D, 2D, or 3D, depending on which of x, y, and z are present
29  // CylindricalDuo: planar disc expansion and axial expansion
30  MooseEnum series_types("Cartesian CylindricalDuo");
33 
35  "series_type", series_types, "The type of function series to construct.");
36 
37  /*
38  * This needs to use `unsigned int` instead of `std::size_t` because otherwise MOOSE errors at
39  * runtime
40  */
41  params.addRequiredParam<std::vector<unsigned int>>("orders",
42  "The order of each series. These must be "
43  "defined as \"x y z\" for Cartesian, and \"z "
44  "disc\" for CylindricalDuo.");
45 
46  params.addParam<std::vector<Real>>("physical_bounds",
47  "The physical bounds of the function series. These must be "
48  "defined as \"x_min x_max y_min y_max z_min z_max\" for "
49  "Cartesian, and \"axial_min axial_max disc_center1 "
50  "disc_center2 radius\" for CylindricalDuo");
51 
52  params.addParam<MooseEnum>("x", single_series_types_1D, "The series to use for the x-direction.");
53  params.addParam<MooseEnum>("y", single_series_types_1D, "The series to use for the y-direction.");
54  params.addParam<MooseEnum>("z", single_series_types_1D, "The series to use for the z-direction.");
55 
56  params.addParam<MooseEnum>("disc",
58  "The series to use for the disc. Its direction is determined by "
59  "orthogonality to the declared direction of the axis.");
60 
61  std::string normalization_types = "orthonormal sqrt_mu standard";
62  MooseEnum expansion_type(normalization_types, "standard");
63  MooseEnum generation_type(normalization_types, "orthonormal");
64  params.addParam<MooseEnum>("expansion_type",
66  "The normalization used for expansion of the basis functions");
67  params.addParam<MooseEnum>(
68  "generation_type",
70  "The normalization used for generation of the basis function coefficients");
71  return params;
72 }
73 
75  : MutableCoefficientsFunctionInterface(this, parameters),
76  _orders(convertOrders(getParam<std::vector<unsigned int>>("orders"))),
77  _physical_bounds(getParam<std::vector<Real>>("physical_bounds")),
78  _series_type_name(getParam<MooseEnum>("series_type")),
79  _x(getParam<MooseEnum>("x")),
80  _y(getParam<MooseEnum>("y")),
81  _z(getParam<MooseEnum>("z")),
82  _disc(getParam<MooseEnum>("disc")),
83  _expansion_type(getParam<MooseEnum>("expansion_type")),
84  _generation_type(getParam<MooseEnum>("generation_type"))
85 {
86  std::vector<MooseEnum> domains;
87  std::vector<MooseEnum> types;
88 
89  if (_series_type_name == "Cartesian")
90  {
91  /*
92  * For Cartesian series, at least one of 'x', 'y', and 'z' must be specified.
93  *
94  * The individual series are always stored in x, y, z order (independent of the order in which
95  * they appear in the input file). Hence, the 'orders' and 'physical_bounds' vectors must always
96  * be specified in x, y, z order.
97  */
98  if (isParamValid("x"))
99  {
100  domains.push_back(FunctionalBasisInterface::_domain_options = "x");
101  types.push_back(_x);
102  }
103  if (isParamValid("y"))
104  {
105  domains.push_back(FunctionalBasisInterface::_domain_options = "y");
106  types.push_back(_y);
107  }
108  if (isParamValid("z"))
109  {
110  domains.push_back(FunctionalBasisInterface::_domain_options = "z");
111  types.push_back(_z);
112  }
113  if (types.size() == 0)
114  mooseError("Must specify one of 'x', 'y', or 'z' for 'Cartesian' series!");
115  _series_type = std::make_unique<Cartesian>(
116  domains, _orders, types, name(), _expansion_type, _generation_type);
117  }
118  else if (_series_type_name == "CylindricalDuo")
119  {
120  /*
121  * CylindricalDuo represents a disc-axial expansion, where the disc is described by a single
122  * series, such as Zernike (as opposed to a series individually representing r and a second
123  * series independently representing theta. For CylindricalDuo series, the series are always
124  * stored in the axial, planar order, independent of which order the series appear in the input
125  * file. Therefore, the _orders and _physical_bounds vectors must always appear in axial, planar
126  * order. The first entry in _domains is interpreted as the axial direction, and the following
127  * two as the planar.
128  */
129  if (isParamValid("x"))
130  {
134  types.push_back(_x);
135  }
136  if (isParamValid("y"))
137  {
141  types.push_back(_y);
142  }
143  if (isParamValid("z"))
144  {
148  types.push_back(_z);
149  }
150 
151  if (types.size() == 0)
152  mooseError("Must specify one of 'x', 'y', or 'z' for 'CylindricalDuo' series!");
153 
154  if (types.size() > 1)
155  mooseError("Cannot specify more than one of 'x', 'y', or 'z' for 'CylindricalDuo' series!");
156 
157  types.push_back(_disc);
158  _series_type = std::make_unique<CylindricalDuo>(
159  domains, _orders, types, name(), _expansion_type, _generation_type);
160  }
161  else
162  mooseError("Unknown functional series type \"", _series_type_name, "\"");
163 
164  // Set the physical bounds of each of the single series if defined
165  if (isParamValid("physical_bounds"))
166  _series_type->setPhysicalBounds(_physical_bounds);
167 
168  // Resize the coefficient array as needed
169  enforceSize(false), resize(getNumberOfTerms(), 0.0), enforceSize(true);
171 }
172 
175  const std::string & typeName,
176  const std::string & objectName)
177 {
178  const FunctionSeries * test = dynamic_cast<const FunctionSeries *>(&function);
179  if (!test)
180  ::mooseError("In ",
181  typeName,
182  "-type object \"",
183  objectName,
184  "\": the named Function \"",
185  function.name(),
186  "\" must be a FunctionSeries-type object.");
187 
188  return *const_cast<FunctionSeries *>(test);
189 }
190 
191 Real
193 {
194  return _series_type->getStandardizedFunctionVolume();
195 }
196 
197 std::size_t
199 {
200  return _series_type->getNumberOfTerms();
201 }
202 
203 const std::vector<size_t> &
205 {
206  return _orders;
207 }
208 
209 /*
210  * getAllGeneration() is defined in the FunctionalBasisInterface, which calls the pure virtual
211  * evaluateGeneration() method of the CompositeSeriesBasisInterface class, which then calls the
212  * getAllGeneration() method of each of the single series.
213  */
214 const std::vector<Real> &
216 {
217  return _series_type->getAllGeneration();
218 }
219 
220 /*
221  * getAllExpansion() is defined in the FunctionalBasisInterface, which calls the pure virtual
222  * evaluateExpansion() method of the CompositeSeriesBasisInterface class, which then calls the
223  * getAllExpansion() method of each of the single series.
224  */
225 const std::vector<Real> &
227 {
228  return _series_type->getAllExpansion();
229 }
230 
231 /*
232  * isInPhysicalBounds() is a pure virtual method of the FunctionalBasisInterface that is defined in
233  * the CompositeSeriesBasisInterface class because it is agnostic to the underlying types of the
234  * single series.
235  */
236 bool
237 FunctionSeries::isInPhysicalBounds(const Point & point) const
238 {
239  return _series_type->isInPhysicalBounds(point);
240 }
241 
242 void
243 FunctionSeries::setLocation(const Point & point)
244 {
245  _series_type->setLocation(point);
246 }
247 
248 Real
249 FunctionSeries::evaluateValue(Real, const Point & point)
250 {
251  // Check that the point is within the physical bounds of the series
252  if (!isInPhysicalBounds(point))
253  return 0.0;
254 
255  // Set the location at which to evaluate the series
256  setLocation(point);
257 
258  return expand();
259 }
260 
261 Real
263 {
264  return expand(_coefficients);
265 }
266 
267 Real
268 FunctionSeries::expand(const std::vector<Real> & coefficients)
269 {
270  // Evaluate all of the terms in the series
271  const std::vector<Real> & terms = getExpansion();
272 
273  return std::inner_product(terms.begin(), terms.end(), coefficients.begin(), 0.0);
274 }
275 
276 std::ostream &
277 operator<<(std::ostream & stream, const FunctionSeries & me)
278 {
279  stream << "\n\n"
280  << "FunctionSeries: " << me.name() << "\n"
281  << " Terms: " << me.getNumberOfTerms() << "\n";
282  me._series_type->formatCoefficients(stream, me._coefficients);
283  stream << "\n\n" << std::flush;
284 
285  return stream;
286 }
287 
288 std::vector<std::size_t>
289 FunctionSeries::convertOrders(const std::vector<unsigned int> & orders)
290 {
291  return std::vector<std::size_t>(orders.begin(), orders.end());
292 }
std::unique_ptr< CompositeSeriesBasisInterface > _series_type
Stores a pointer to the functional series object.
Interface for a type of functions using coefficients that may be changed before or after a solve...
MooseEnum single_series_types_2D
void setLocation(const Point &point)
Set the current evaluation location.
const MooseEnum & _x
Stores the name of the single function series to use in the x direction.
const std::vector< Real > & getExpansion()
Returns a vector of the expansion-evaluated functional series at the current location.
const std::vector< std::size_t > _orders
The vector holding the orders of each single series.
FunctionSeries(const InputParameters &parameters)
const MooseEnum & _generation_type
The normalization type for generation.
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
const std::vector< Real > & getGeneration()
Returns a vector of the generation-evaluated functional series at the current location.
std::ostream & operator<<(std::ostream &stream, const FunctionSeries &me)
static MooseEnum _domain_options
An enumeration of the domains available to each functional series.
virtual Real evaluateValue(Real t, const Point &p) override
Used in derived classes, equivalent to Function::value()
void setCharacteristics(const std::vector< std::size_t > &new_characteristics)
Sets the characteristics array.
virtual const std::string & name() const
void addRequiredParam(const std::string &name, const std::string &doc_string)
bool isParamValid(const std::string &name) const
const MooseEnum & _z
Stores the name of the single function series to use in the z direction.
const MooseEnum & _series_type_name
Stores the name of the current functional series type.
MooseEnum expansion_type
MooseEnum single_series_types_1D
This class uses implementations of CompositeSeriesBasisInterface to generate a function based on conv...
Real expand()
Expand the function series at the current location and with the current coefficients.
static InputParameters validParams()
static FunctionSeries & checkAndConvertFunction(const Function &function, const std::string &typeName, const std::string &objectName)
Static function to cast a Function to SeriesFunction.
std::vector< Real > & _coefficients
The coefficient array.
std::size_t getNumberOfTerms() const
Returns the number of terms (coefficients) in the underlying function series.
const std::vector< Real > _physical_bounds
The physical bounds of the function series.
static std::vector< std::size_t > convertOrders(const std::vector< unsigned int > &orders)
Static function to convert an array of unsigned int to std::size_t.
const MooseEnum & _disc
Stores the name of the single function series to use for a unit disc.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const MooseEnum & _y
Stores the name of the single function series to use in the y direction.
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
const std::vector< std::size_t > & getOrders() const
Returns a vector of the functional orders in the underlying functional series.
void resize(std::size_t size, Real fill=0.0, bool fill_out_to_size=true)
Resize the array, using the value for fill if the new size is larger.
const MooseEnum & _expansion_type
The normalization type for expansion.
bool isInPhysicalBounds(const Point &point) const
Returns true if the provided point is within the set physical boundaries.
void ErrorVector unsigned int
Real getStandardizedFunctionVolume() const
Returns the volume of evaluation in the functional series standardized space.
registerMooseObject("FunctionalExpansionToolsApp", FunctionSeries)
MooseEnum generation_type
void enforceSize(bool enforce)
Toggle whether the size of the coefficient array can be changed.