www.mooseframework.org
CompositeSeriesBasisInterface.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 
11 #include "Legendre.h"
12 
13 #include <memory>
14 
15 /*
16  * Default constructor creates a functional basis with one term. In order for the _series member to
17  * be initialized, we initialized it with a Legendre series.
18  */
20  : FunctionalBasisInterface(1), _who_is_using_me(who_is_using_me)
21 {
22  _series.push_back(std::make_unique<Legendre>());
23 }
24 
25 /*
26  * The non-default constructor is where we actually loop over the series_types and initialize
27  * pointers to those members. Because we won't know the number of terms until the end of the body
28  * of the constructor, we need to call the default FunctionalBasisInterface constructor.
29  */
31  const std::vector<std::size_t> & orders,
32  std::vector<MooseEnum> series_types,
33  const std::string & who_is_using_me)
34  : FunctionalBasisInterface(), _series_types(series_types), _who_is_using_me(who_is_using_me)
35 {
36  if (orders.size() != _series_types.size())
38  " calling CSBI::CSBI(...): Incorrect number of 'orders' specified for "
39  "'FunctionSeries'! Check that 'orders' is the correct length and no invalid "
40  "enumerations are specified for the series.");
41 }
42 
43 void
45 {
46  /*
47  * Evaluate the generation versions of each of the single series, and collect the results before
48  * passing them to evaluateSeries, where they will be multiplied together correctly and stored in
49  * the composite series basis evaluation.
50  */
51  std::vector<std::vector<Real>> single_series_basis_evaluation;
52  for (auto & series : _series)
53  single_series_basis_evaluation.push_back(series->getAllGeneration());
54 
55  evaluateSeries(single_series_basis_evaluation);
56 }
57 
58 void
60  const std::vector<std::vector<Real>> & single_series_basis_evaluations)
61 {
62  /*
63  * Appropriate number of loops based on 1-D, 2-D, or 3-D to multiply the basis evaluations of the
64  * single series together to form the basis evaluation of the entire composite series.
65  */
66  Real f1, f2, f3;
67  std::size_t term = 0;
68 
69  if (single_series_basis_evaluations.size() == 1)
70  for (std::size_t i = 0; i < _series[0]->getNumberOfTerms(); ++i, ++term)
71  save(term, single_series_basis_evaluations[0][i]);
72 
73  if (single_series_basis_evaluations.size() == 2)
74  for (std::size_t i = 0; i < _series[0]->getNumberOfTerms(); ++i)
75  {
76  f1 = single_series_basis_evaluations[0][i];
77  for (std::size_t j = 0; j < _series[1]->getNumberOfTerms(); ++j, ++term)
78  {
79  f2 = single_series_basis_evaluations[1][j];
80  save(term, f1 * f2);
81  }
82  }
83 
84  if (single_series_basis_evaluations.size() == 3)
85  for (std::size_t i = 0; i < _series[0]->getNumberOfTerms(); ++i)
86  {
87  f1 = single_series_basis_evaluations[0][i];
88  for (std::size_t j = 0; j < _series[1]->getNumberOfTerms(); ++j)
89  {
90  f2 = single_series_basis_evaluations[1][j];
91  for (std::size_t k = 0; k < _series[2]->getNumberOfTerms(); ++k, ++term)
92  {
93  f3 = single_series_basis_evaluations[2][k];
94  save(term, f1 * f2 * f3);
95  }
96  }
97  }
98 }
99 
100 void
102 {
103  /*
104  * Evaluate the expansion versions of each of the single series, and collect the results before
105  * passing them to evaluateSeries, where they will be multiplied together correctly and stored in
106  * the composite series basis evaluation.
107  */
108  std::vector<std::vector<Real>> single_series_basis_evaluation;
109  for (auto & series : _series)
110  single_series_basis_evaluation.push_back(series->getAllExpansion());
111 
112  evaluateSeries(single_series_basis_evaluation);
113 }
114 
115 const std::vector<Real> &
117 {
118  static const std::vector<Real> function_limits = combineStandardizedFunctionLimits();
119 
120  return function_limits;
121 }
122 
123 Real
125 {
126  Real function_volume = 1.0;
127 
128  for (auto & series : _series)
129  function_volume *= series->getStandardizedFunctionVolume();
130 
131  return function_volume;
132 }
133 
134 std::vector<Real>
136 {
137  std::vector<Real> function_limits;
138 
139  for (auto & series : _series)
140  {
141  std::vector<Real> local_limits = series->getStandardizedFunctionLimits();
142  for (auto & limit : local_limits)
143  function_limits.push_back(limit);
144  }
145 
146  return function_limits;
147 }
148 
149 void
151  const std::vector<Real> & coefficients) const
152 {
153  // clang-format off
154  std::ostringstream formatted, domains, orders;
155  std::size_t term = 0;
156 
157  stream << "---------------- Coefficients ----------------\n"
158  << " == Subindices ==\n";
159 
160  if (_series_types.size() == 1)
161  {
162  orders << " Orders: " << std::setw(3) << _series[0]->getOrder(0) << "\n";
163  domains << " == Index == " << std::setw(3) << _series[0]->_domains[0]
164  << " === Value ===\n"
165  << "----------------------------------------------\n";
166 
167  for (std::size_t i = 0; i < _series[0]->getNumberOfTerms(); ++i, ++term)
168  formatted << " " << std::setw(4) << term
169  << " " << std::setw(3) << i
170  << " " << std::setw(12) << coefficients[term] << "\n";
171  }
172  else if (_series_types.size() == 2)
173  {
174  orders << " Orders: " << std::setw(3) << _series[0]->getOrder(0)
175  << " " << std::setw(3) << _series[1]->getOrder(0) << "\n";
176  domains << " == Index == " << std::setw(3) << _series[0]->_domains[0]
177  << " " << std::setw(3) << _series[1]->_domains[0]
178  << " === Value ===\n"
179  << "----------------------------------------------\n";
180 
181  for (std::size_t i = 0; i < _series[0]->getNumberOfTerms(); ++i)
182  {
183  for (std::size_t j = 0; j < _series[1]->getNumberOfTerms(); ++j, ++term)
184  formatted << " " << std::setw(4) << term
185  << " " << std::setw(3) << i
186  << " " << std::setw(3) << j
187  << " " << std::setw(12) << coefficients[term] << "\n";
188  }
189  }
190  else if (_series_types.size() == 3)
191  {
192  orders << " Orders: " << std::setw(3) << _series[0]->getOrder(0)
193  << " " << std::setw(3) << _series[1]->getOrder(0)
194  << " " << std::setw(3) << _series[2]->getOrder(0) << "\n";
195  domains << " == Index == " << std::setw(3) << _series[0]->_domains[0]
196  << " " << std::setw(3) << _series[1]->_domains[0]
197  << " " << std::setw(3) << _series[2]->_domains[0]
198  << " === Value ===\n"
199  << "----------------------------------------------\n";
200 
201  for (std::size_t i = 0; i < _series[0]->getNumberOfTerms(); ++i)
202  {
203  for (std::size_t j = 0; j < _series[1]->getNumberOfTerms(); ++j)
204  {
205  for (std::size_t k = 0; k < _series[2]->getNumberOfTerms(); ++k, ++term)
206  formatted << " " << std::setw(4) << term
207  << " " << std::setw(3) << i
208  << " " << std::setw(3) << j
209  << " " << std::setw(3) << k
210  << " " << std::setw(12) << coefficients[term] << "\n";
211  }
212  }
213  }
214  // clang-format on
215 
216  stream << orders.str() << domains.str() << formatted.str() << std::flush;
217 }
218 
219 bool
221 {
222  /*
223  * If any one of the single series have an invalid cache, then we need to re-evaluate the entire
224  * composite series because the terms are multiplied.
225  */
226  for (auto & series : _series)
227  if (series->isCacheInvalid())
228  return true;
229 
230  return false;
231 }
232 
233 bool
235 {
236  /*
237  * A point is in the physical bounds of the composite series if it is in the physical bounds of
238  * each of the single series
239  */
240  for (auto & series : _series)
241  if (!series->isInPhysicalBounds(point))
242  return false;
243 
244  return true;
245 }
246 
247 void
249 {
250  unsigned int number_of_terms = 1;
251 
252  // Accumulate the number of terms for each series
253  for (auto & series : _series)
254  number_of_terms *= series->getNumberOfTerms();
255 
256  _number_of_terms = number_of_terms;
257 
258  /*
259  * The length of the _basis_evaluation depends on the number of terms, so we need to clear the
260  * entries because the number of terms in the composite series may have changed.
261  */
263 }
264 
265 void
266 CompositeSeriesBasisInterface::setOrder(const std::vector<std::size_t> & orders)
267 {
268  // One order must be specified for each single series
269  if (orders.size() != _series.size())
271  " calling CSBI::setOrder(): Mismatch between the orders provided and the number of "
272  "series in the functional basis!");
273 
274  // Update the orders of each of the single series
275  for (std::size_t i = 0; i < _series.size(); ++i)
276  _series[i]->setOrder({orders[i]});
277 
278  /*
279  * After changing the order of each single series, we need to recompute the number of terms by
280  * looping over those single series. This also clears the basis evaluation of the composite
281  * series.
282  */
284 }
285 
286 void
288 {
289  // Return if this point is the same as the last at which the composite series was evaluated
290  if (point.absolute_fuzzy_equals(_previous_point))
291  return;
292 
293  // Set the location of each of the single series
294  for (auto & series : _series)
295  series->setLocation(point);
296 
297  // Store the previous point
298  _previous_point = point;
299 }
300 
std::vector< MooseEnum > _series_types
The series types in this composite series.
virtual bool isInPhysicalBounds(const Point &point) const final
Determines if the point provided is in within the physical bounds.
CompositeSeriesBasisInterface(const std::string &who_is_using_me)
virtual void evaluateGeneration() final
Evaluate the generation form of the functional basis.
void mooseError(Args &&... args)
unsigned int _number_of_terms
The number of terms in the series.
virtual const std::vector< Real > & getStandardizedFunctionLimits() const final
Returns a vector of the lower and upper bounds of the standard functional space.
virtual void clearBasisEvaluation(const unsigned int &number_of_terms)
Set all entries of the basis evaluation to zero.
void save(std::size_t index, Real value)
Helper function to store a value in #_series.
virtual void setOrder(const std::vector< std::size_t > &orders) final
Set the order of the series.
void setNumberOfTerms()
Initialize the number of terms in the composite series by looping over the single series...
virtual void setLocation(const Point &p) final
Set the location that will be used by the series to compute values.
void evaluateSeries(const std::vector< std::vector< Real >> &single_series_basis_evaluations)
Evaluates the values of _basis_evaluation for either evaluateGeneration() or evaluateExpansion() ...
virtual void formatCoefficients(std::ostream &stream, const std::vector< Real > &coefficients) const
Appends a tabulated form of the coefficients to the stream.
std::vector< std::unique_ptr< SingleSeriesBasisInterface > > _series
A pointer to the single series type (one for each entry in _domains)
virtual bool isCacheInvalid() const final
Whether the cached values correspond to the current point.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual void evaluateExpansion() final
Evaluate the expansion form of the functional basis.
const std::string & _who_is_using_me
The name of the MooseObject that is using this class.
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
std::vector< Real > combineStandardizedFunctionLimits() const
Get the function limits by looping over each of the single series.
Point _previous_point
The previous point at which the series was evaluated.
static const std::string k
Definition: NS.h:124
virtual Real getStandardizedFunctionVolume() const final
Returns the volume within the standardized function local_limits.
This class provides the basis for any custom functional basis, and is the parent class of both Single...