https://mooseframework.inl.gov
Loading...
Searching...
No Matches
Legendre.C
Go to the documentation of this file.
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 "Legendre.h"
11#include <functional>
12
17#define MAX_DIRECT_CALCULATION_LEGENDRE 12
18
20
21Legendre::Legendre(const std::vector<MooseEnum> & domain,
22 const std::vector<std::size_t> & order,
25 : SingleSeriesBasisInterface(domain, order, calculatedNumberOfTermsBasedOnOrder(order))
26{
27 if (expansion_type == "orthonormal")
28 _evaluateExpansionWrapper = [this]() { this->evaluateOrthonormal(); };
29 else if (expansion_type == "sqrt_mu")
30 _evaluateExpansionWrapper = [this]() { this->evaluateSqrtMu(); };
31 else if (expansion_type == "standard")
32 _evaluateExpansionWrapper = [this]() { this->evaluateStandard(); };
33 else
34 mooseError("The specified type of normalization for expansion does not exist");
35
36 if (generation_type == "orthonormal")
37 _evaluateGenerationWrapper = [this]() { this->evaluateOrthonormal(); };
38 else if (generation_type == "sqrt_mu")
39 _evaluateGenerationWrapper = [this]() { this->evaluateSqrtMu(); };
40 else if (generation_type == "standard")
41 _evaluateGenerationWrapper = [this]() { this->evaluateStandard(); };
42 else
43 mooseError("The specified type of normalization for generation does not exist");
44}
45
46std::size_t
47Legendre::calculatedNumberOfTermsBasedOnOrder(const std::vector<std::size_t> & order) const
48{
49 return order[0] + 1;
50}
51
52void
53Legendre::checkPhysicalBounds(const std::vector<Real> & bounds) const
54{
55 // Each Legendre series should have a min and max bound
56 if (bounds.size() != 2)
57 mooseError("Legend: Invalid number of bounds specified for single series!");
58}
59
60void
62{
63 std::size_t k;
64 const Real & x = _standardized_location[0];
65 const Real x2 = x * x;
66
67 /*
68 * Use direct formula to efficiently evaluate the polynomials for n <= 12
69 *
70 * The performance benefit diminishes for higher n. It is expected that the cost of the direct
71 * calculation nears that of the recurrence relation in the neighborhood of n == 15, although this
72 * theory is untested due to only implementing the direct calculations up to n == 12.
73 *
74 * If you want to calculate the higher-order Legendre Coefficients and code them in then be my
75 * guest.
76 */
77 // clang-format off
78 switch (_orders[0])
79 {
80 default:
81 case MAX_DIRECT_CALCULATION_LEGENDRE: /* 12 */
82 save(12, ((((((676039 * x2 - 1939938) * x2 + 2078505) * x2 - 1021020) * x2 + 225225) * x2 - 18018) * x2 + 231) / 1024
83 * 12.5);
84 libmesh_fallthrough();
85
86 case 11:
87 save(11, (((((88179 * x2 - 230945) * x2 + 218790) * x2 - 90090) * x2 + 15015) * x2 - 693) * x / 256
88 * 11.5);
89 libmesh_fallthrough();
90
91 case 10:
92 save(10, (((((46189 * x2 - 109395) * x2 + 90090) * x2 - 30030) * x2 + 3465) * x2 - 63) / 256
93 * 10.5);
94 libmesh_fallthrough();
95
96 case 9:
97 save(9, ((((12155 * x2 - 25740) * x2 + 18018) * x2 - 4620) * x2 + 315) * x / 128
98 * 9.5);
99 libmesh_fallthrough();
100
101 case 8:
102 save(8, ((((6435 * x2 - 12012) * x2 + 6930) * x2 - 1260) * x2 + 35) / 128
103 * 8.5);
104 libmesh_fallthrough();
105
106 case 7:
107 save(7, (((429 * x2 - 693) * x2 + 315) * x2 - 35) * x / 16
108 * 7.5);
109 libmesh_fallthrough();
110
111 case 6:
112 save(6, (((231 * x2 - 315) * x2 + 105) * x2 - 5) / 16
113 * 6.5);
114 libmesh_fallthrough();
115
116 case 5:
117 save(5, ((63 * x2 - 70) * x2 + 15) * x / 8
118 * 5.5);
119 libmesh_fallthrough();
120
121 case 4:
122 save(4, ((35 * x2 - 30) * x2 + 3) / 8
123 * 4.5);
124 libmesh_fallthrough();
125
126 case 3:
127 save(3, (5 * x2 - 3) * x / 2
128 * 3.5);
129 libmesh_fallthrough();
130
131 case 2:
132 save(2, (3 * x2 - 1) / 2
133 * 2.5);
134 libmesh_fallthrough();
135
136 case 1:
137 save(1, x
138 * 1.5);
139 libmesh_fallthrough();
140
141 case 0:
142 save(0, 1
143 * 0.5);
144 }
145 // clang-format on
146
147 /*
148 * Evaluate any remaining polynomials.
149 *
150 * The original recurrence relation is:
151 * (2 * k - 1) * x * L_(k-1) - (k - 1) * L_(k-2)
152 * L_k = ---------------------------------------------
153 * k
154 *
155 * However, for FXs we are using a the orthonormalized version of the polynomials, so each
156 * polynomial L_k is multiplied by:
157 * (2 * k + 1)
158 * ----------- essentially: k + 0.5
159 * 2
160 * Reversing this in the previous polynomials and implementing for the current polynomial results
161 * in the orthonormalized recurrence:
162 * (2 * k + 1) / (k - 1) \
163 * L_k = ----------- * | x * L_(k-1) - ----------- * L_(k-2) |
164 * k \ (2 * k - 3) /
165 *
166 * The options are 1) to use this form, or 2) to not apply the orthonormalization at first, and
167 * then loop through all the values in a second loop and then apply the orthonormalization.
168 */
169 for (k = MAX_DIRECT_CALCULATION_LEGENDRE + 1; k <= _orders[0]; ++k)
170 save(k, ((k + k + 1) / Real(k)) * (x * load(k - 1) - ((k - 1) / (k + k - 3.0)) * load(k - 2)));
171}
172
173void
175{
176 std::size_t k;
177 const Real x = _standardized_location[0];
178 const Real x2 = x * x;
179
180 /*
181 * Use direct formula to efficiently evaluate the polynomials for n <= 12
182 *
183 * The performance benefit diminishes for higher n. It is expected that the cost of the direct
184 * calculation nears that of the recurrence relation in the neighborhood of n == 15, although this
185 * theory is untested due to only implementing the direct calculations up to n == 12.
186 *
187 * If you want to calculate the higher-order Legendre Coefficients and
188 * code them in then be my guest.
189 */
190 // clang-format off
191 switch (_orders[0])
192 {
193 default:
194 case MAX_DIRECT_CALCULATION_LEGENDRE: /* 12 */
195 save(12, ((((((676039 * x2 - 1939938) * x2 + 2078505) * x2 - 1021020) * x2 + 225225) * x2 - 18018) * x2 + 231) / 1024);
196 libmesh_fallthrough();
197
198 case 11:
199 save(11, (((((88179 * x2 - 230945) * x2 + 218790) * x2 - 90090) * x2 + 15015) * x2 - 693) * x / 256);
200 libmesh_fallthrough();
201
202 case 10:
203 save(10, (((((46189 * x2 - 109395) * x2 + 90090) * x2 - 30030) * x2 + 3465) * x2 - 63) / 256);
204 libmesh_fallthrough();
205
206 case 9:
207 save(9, ((((12155 * x2 - 25740) * x2 + 18018) * x2 - 4620) * x2 + 315) * x / 128);
208 libmesh_fallthrough();
209
210 case 8:
211 save(8, ((((6435 * x2 - 12012) * x2 + 6930) * x2 - 1260) * x2 + 35) / 128);
212 libmesh_fallthrough();
213
214 case 7:
215 save(7, (((429 * x2 - 693) * x2 + 315) * x2 - 35) * x / 16);
216 libmesh_fallthrough();
217
218 case 6:
219 save(6, (((231 * x2 - 315) * x2 + 105) * x2 - 5) / 16);
220 libmesh_fallthrough();
221
222 case 5:
223 save(5, ((63 * x2 - 70) * x2 + 15) * x / 8);
224 libmesh_fallthrough();
225
226 case 4:
227 save(4, ((35 * x2 - 30) * x2 + 3) / 8);
228 libmesh_fallthrough();
229
230 case 3:
231 save(3, (5 * x2 - 3) * x / 2);
232 libmesh_fallthrough();
233
234 case 2:
235 save(2, (3 * x2 - 1) / 2);
236 libmesh_fallthrough();
237
238 case 1:
239 save(1, x);
240 libmesh_fallthrough();
241
242 case 0:
243 save(0, 1);
244 }
245 // clang-format on
246
247 /*
248 * Evaluate any remaining polynomials.
249 * The recurrence relation is:
250 * (2 * k - 1) * x * L_(k-1) - (k - 1) * L_(k-2)
251 * L_k = ---------------------------------------------
252 * k
253 */
254 for (k = MAX_DIRECT_CALCULATION_LEGENDRE + 1; k <= _orders[0]; ++k)
255 save(k, (((2 * k - 1) * x * load(k - 1)) - ((k - 1) * load(k - 2))) / Real(k));
256}
257
258void
260{
262 for (size_t i = 0; i < getNumberOfTerms(); ++i)
263 save(i, load(i) * std::sqrt(i + 0.5));
264}
265
266const std::vector<Real> &
268{
269 // Lazily instantiate the function limits array
270 static const std::vector<Real> standardizedFunctionLimits = {-1, 1};
271
272 return standardizedFunctionLimits;
273}
274
275Real
277{
278 return 2.0; // Span of [-1, 1]
279}
280
281std::vector<Real>
282Legendre::getStandardizedLocation(const std::vector<Real> & location) const
283{
284 const Real difference = location[0] - _physical_bounds[0];
285 const Real span = _physical_bounds[1] - _physical_bounds[0];
286
287 // Convert to [0, 1] (assuming that location[0] is within _physical_bounds)
288 const Real ratio = difference / span;
289
290 // Legendre space is [-1, 1]
291 return {ratio * 2 - 1};
292}
293
294bool
295Legendre::isInPhysicalBounds(const Point & point) const
296{
297 std::vector<Real> location = extractLocationFromPoint(point);
298
299 if (location[0] < _physical_bounds[0] || _physical_bounds[1] < location[0])
300 return false;
301 else
302 return true;
303}
const std::vector< double > x
void mooseError(Args &&... args)
MooseEnum expansion_type
MooseEnum generation_type
std::size_t getNumberOfTerms() const
Returns the number of terms in the series.
Real load(std::size_t index) const
Helper function to load a value from #_series.
void save(std::size_t index, Real value)
Helper function to store a value in #_series.
virtual std::vector< Real > getStandardizedLocation(const std::vector< Real > &location) const override
Standardize the location according to the requirements of the underlying basis, which may actually co...
Definition Legendre.C:282
void evaluateSqrtMu()
Evaluates the 1/sqrt(mu) normalized form of the basis functions.
Definition Legendre.C:259
virtual void checkPhysicalBounds(const std::vector< Real > &bounds) const override
Checks the physical bounds according to the actual implementation.
Definition Legendre.C:53
virtual bool isInPhysicalBounds(const Point &point) const override
Determines if the point provided is in within the physical bounds.
Definition Legendre.C:295
void evaluateStandard()
Evaluates the standard form of the basis functions.
Definition Legendre.C:174
void evaluateOrthonormal()
Evaluates the orthonormal form of the basis functions.
Definition Legendre.C:61
virtual const std::vector< Real > & getStandardizedFunctionLimits() const override
Returns a vector of the lower and upper bounds of the standard functional space.
Definition Legendre.C:267
virtual Real getStandardizedFunctionVolume() const override
Returns the volume within the standardized function local_limits.
Definition Legendre.C:276
virtual std::size_t calculatedNumberOfTermsBasedOnOrder(const std::vector< std::size_t > &order) const override
Returns the number of terms in the single series given a value for the order.
Definition Legendre.C:47
Legendre()
Definition Legendre.C:19
This class is a simple wrapper around FunctionalBasisInterface, and intended for use by any single fu...
std::vector< Real > _physical_bounds
The physical bounds of the series.
std::vector< Real > extractLocationFromPoint(const Point &point) const
Convert a spatial point to a location that the series will use to determine the value at which to eva...
std::vector< std::size_t > _orders
The order of the series.
std::function< void()> _evaluateGenerationWrapper
The generation evaluation wrapper.
std::vector< Real > _standardized_location
The standardized location of evaluation.
std::function< void()> _evaluateExpansionWrapper
The expansion evaluation wrapper.