deal.II version GIT relicensing-6842-g793a97d2aa 2026-10-02 14:00:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
polynomial.h
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2000 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#ifndef dealii_polynomial_h
14#define dealii_polynomial_h
15
16
17
18#include <deal.II/base/config.h>
19
23#include <deal.II/base/point.h>
24#include <deal.II/base/types.h>
25
26#include <array>
27#include <limits>
28#include <memory>
29#include <shared_mutex>
30#include <vector>
31
33
43namespace Polynomials
44{
69 template <typename number>
71 {
72 public:
87 Polynomial(const std::vector<number> &coefficients);
88
92 Polynomial(const unsigned int n);
93
108 Polynomial(const std::vector<Point<1>> &lagrange_support_points,
109 const unsigned int j);
110
115
125 number
126 value(const number x) const;
127
138 void
139 value(const number x, std::vector<number> &values) const;
140
159 template <typename Number2>
160 void
161 value(const Number2 x,
162 const unsigned int n_derivatives,
163 Number2 *values) const;
164
177 template <std::size_t n_entries, typename Number2>
178#ifndef DEBUG
180#endif
181 void
182 values_of_array(const std::array<Number2, n_entries> &points,
183 const unsigned int n_derivatives,
184 std::array<Number2, n_entries> *values) const;
185
191 unsigned int
192 degree() const;
193
201 void
202 scale(const number factor);
203
219 template <typename number2>
220 void
221 shift(const number2 offset);
222
227 derivative() const;
228
234 primitive() const;
235
240 operator*=(const double s);
241
247
253
259
263 bool
264 operator==(const Polynomial<number> &p) const;
265
269 void
270 print(std::ostream &out) const;
271
277 template <class Archive>
278 void
279 serialize(Archive &ar, const unsigned int version);
280
284 virtual std::size_t
285 memory_consumption() const;
286
287 protected:
291 static void
292 scale(std::vector<number> &coefficients, const number factor);
293
297 template <typename number2>
298 static void
299 shift(std::vector<number> &coefficients, const number2 shift);
300
304 static void
305 multiply(std::vector<number> &coefficients, const number factor);
306
312 void
314
323 std::vector<number> coefficients;
324
330
335 std::vector<number> lagrange_support_points;
336
342 };
343
344
349 template <typename number>
350 class Monomial : public Polynomial<number>
351 {
352 public:
357 Monomial(const unsigned int n, const double coefficient = 1.);
358
365 static std::vector<Polynomial<number>>
366 generate_complete_basis(const unsigned int degree);
367
368 private:
376 static std::vector<Point<1>>
377 create_vector_of_roots(unsigned int n);
378 };
379
380
396 class LagrangeEquidistant : public Polynomial<double>
397 {
398 public:
404 LagrangeEquidistant(const unsigned int n, const unsigned int support_point);
405
414 static std::vector<Polynomial<double>>
415 generate_complete_basis(const unsigned int degree);
416
417 private:
422 static void
423 compute_coefficients(const unsigned int n,
424 const unsigned int support_point,
425 std::vector<double> &a);
426 };
427
428
429
436 std::vector<Polynomial<double>>
437 generate_complete_Lagrange_basis(const std::vector<Point<1>> &points);
438
439
440
454 class Legendre : public Polynomial<double>
455 {
456 public:
460 Legendre(const unsigned int p);
461
468 static std::vector<Polynomial<double>>
469 generate_complete_basis(const unsigned int degree);
470 };
471
491 class Lobatto : public Polynomial<double>
492 {
493 public:
498 Lobatto(const unsigned int p = 0);
499
504 static std::vector<Polynomial<double>>
505 generate_complete_basis(const unsigned int p);
506
507 private:
511 std::vector<double>
512 compute_coefficients(const unsigned int p);
513 };
514
515
516
554 class Hierarchical : public Polynomial<double>
555 {
556 public:
561 Hierarchical(const unsigned int p);
562
573 static std::vector<Polynomial<double>>
574 generate_complete_basis(const unsigned int degree);
575
576 private:
580 static void
581 compute_coefficients(const unsigned int p);
582
587 static const std::vector<double> &
588 get_coefficients(const unsigned int p);
589
598 static std::vector<std::unique_ptr<const std::vector<double>>>
600
605 static std::shared_mutex coefficients_lock;
606 };
607
608
609
637 class HermiteInterpolation : public Polynomial<double>
638 {
639 public:
644 HermiteInterpolation(const unsigned int p);
645
651 static std::vector<Polynomial<double>>
652 generate_complete_basis(const unsigned int p);
653 };
654
655
656
759 {
760 public:
765 HermiteLikeInterpolation(const unsigned int degree,
766 const unsigned int index);
767
772 static std::vector<Polynomial<double>>
773 generate_complete_basis(const unsigned int degree);
774 };
775
776
777
778 /*
779 * Evaluate a Jacobi polynomial @f$ P_n^{\alpha, \beta}(x) @f$ specified by the
780 * parameters @p alpha, @p beta, @p n, where @p n is the degree of the
781 * Jacobi polynomial.
782 *
783 * @note The Jacobi polynomials are not orthonormal and are defined on the
784 * unit interval @f$[0, 1]@f$ as usual for deal.II, rather than @f$[-1, +1]@f$ often
785 * used in literature. @p x is the point of evaluation. If instead the point
786 * @p x is given on the interval @f$[-1, +1]@f$ set
787 * @p rescale_to_dealii_unit_interval to false.
788 */
789 template <typename Number>
790 Number
791 jacobi_polynomial_value(const unsigned int degree,
792 const int alpha,
793 const int beta,
794 const Number x,
795 const bool rescale_to_dealii_unit_interval = true);
796
797 /*
798 * Evaluate the derivative of the Jacobi polynomial @f$ d P_n^{\alpha, \beta}(x)
799 * / dx @f$ specified by the
800 * parameters @p alpha, @p beta, @p n, where @p n is the degree of the
801 * Jacobi polynomial.
802 *
803 * @note The Jacobi polynomials are not orthonormal and are defined on the
804 * unit interval @f$[0, 1]@f$ as usual for deal.II, rather than @f$[-1, +1]@f$ often
805 * used in literature. @p x is the point of evaluation. If instead the point @p
806 * x is given on the interval @f$[-1, +1]@f$ set @p rescale_to_dealii_unit_interval
807 * to false.
808 */
809 template <typename Number>
810 Number
811 jacobi_polynomial_derivative(const unsigned int degree,
812 const int alpha,
813 const int beta,
814 const Number x,
815 const bool rescale_to_dealii_unit_interval);
816
817 /*
818 * Evaluate k-th derivative of the Jacobi polynomial
819 * @f$ d^k P_n^{\alpha, \beta}(x) / dx^k @f$, where k equals @p derivative_order,
820 * specified by the parameters @p alpha, @p beta, @p n, where @p n is the
821 * degree of the Jacobi polynomial and @k the degree of the derivative.
822 *
823 * @note The Jacobi polynomials are not orthonormal and are defined on the
824 * unit interval @f$[0, 1]@f$ as usual for deal.II, rather than @f$[-1, +1]@f$ often
825 * used in literature. @p x is the point of evaluation. If instead the point @p
826 * x is given on the interval @f$[-1, +1]@f$ set @p rescale_to_dealii_unit_interval
827 * to false.
828 */
829 template <typename Number>
830 Number
831 jacobi_polynomial_kth_derivative(const unsigned int derivative_order,
832 const unsigned int degree,
833 const int alpha,
834 const int beta,
835 const Number x,
836 const bool rescale_to_dealii_unit_interval);
837
856 template <typename Number>
857 std::vector<Number>
858 jacobi_polynomial_roots(const unsigned int degree,
859 const int alpha,
860 const int beta);
861
862 /*
863 * Evaluate the homogenized Jacobi polynomial
864 * @f$ Q_n^{\alpha, \beta}(x,s) = s^n P_n^{\alpha, \beta}(x/s) @f$
865 * specified by the parameters @p alpha, @p beta, @p n, where @p n is the
866 * degree of the Jacobi polynomial. The resulting polynomial has no
867 * singularity, the computation of @f$x/s@f$ is explicitly avoided.
868 *
869 * @note The homogenized Jacobi polynomials are defined on the unit interval
870 * @f$[0, 1]@f$ as usual for deal.II, rather than @f$[-1, +1]@f$ often used in
871 * literature. @p x is the point of evaluation, the shift to the interval
872 * @f$[-1, +1]@f$ is conducted as
873 * @f$ Q_n^{\alpha, \beta}(x,s) = s^n P_n^{\alpha, \beta}(2 x/s - 1) @f$.
874 */
875 template <typename Number>
876 Number
877 jacobi_polynomial_homogenized_value(const unsigned int degree,
878 const int alpha,
879 const int beta,
880 const Number x,
881 const Number s);
882
883 /*
884 * Evaluate (mixed) derivatives of the homogenized Jacobi polynomial
885 * @f$ d^k Q_n^{\alpha, \beta}(x,s) / dx^order_x ds^order_s @f$ specified by the
886 * parameters @p alpha, @p beta, @p n, where @p n is the degree of the
887 * Jacobi polynomial and @order_x and @order_s the degree of the derivative
888 * with respect to @p x and @p s.
889 */
890 template <typename Number>
891 Number
892 jacobi_polynomial_homogenized_derivative(const unsigned int order_x,
893 const unsigned int order_s,
894 const unsigned int degree,
895 const int alpha,
896 const int beta,
897 const Number x,
898 const Number s);
899} // namespace Polynomials
900
901
904/* -------------------------- inline functions --------------------- */
905
906namespace Polynomials
907{
908 template <typename number>
910 : in_lagrange_product_form(false)
911 , lagrange_weight(1.)
912 {}
913
914
915
916 template <typename number>
917 inline unsigned int
919 {
920 if (in_lagrange_product_form == true)
921 {
922 return lagrange_support_points.size();
923 }
924 else
925 {
926 Assert(coefficients.size() > 0, ExcEmptyObject());
927 return coefficients.size() - 1;
928 }
929 }
930
931
932
933 template <typename number>
934 inline number
935 Polynomial<number>::value(const number x) const
936 {
937 if (in_lagrange_product_form == false)
938 {
939 Assert(coefficients.size() > 0, ExcEmptyObject());
940
941 // Horner scheme
942 const unsigned int m = coefficients.size();
943 number value = coefficients.back();
944 for (int k = m - 2; k >= 0; --k)
945 value = value * x + coefficients[k];
946 return value;
947 }
948 else
949 {
950 // direct evaluation of Lagrange polynomial
951 const unsigned int m = lagrange_support_points.size();
952 number value = 1.;
953 for (unsigned int j = 0; j < m; ++j)
954 value *= x - lagrange_support_points[j];
955 value *= lagrange_weight;
956 return value;
957 }
958 }
959
960
961
962 template <typename number>
963 template <typename Number2>
964 inline void
966 const unsigned int n_derivatives,
967 Number2 *values) const
968 {
969 values_of_array(std::array<Number2, 1ul>{{x}},
970 n_derivatives,
971 reinterpret_cast<std::array<Number2, 1ul> *>(values));
972 }
973
974
975
976 template <typename number>
977 template <std::size_t n_entries, typename Number2>
978 inline
979#ifndef DEBUG
981#endif
982 void
984 const std::array<Number2, n_entries> &x,
985 const unsigned int n_derivatives,
986 std::array<Number2, n_entries> *values) const
987 {
988 // evaluate Lagrange polynomial and derivatives
989 if (in_lagrange_product_form == true)
990 {
991 // to compute the value and all derivatives of a polynomial of the
992 // form (x-x_1)*(x-x_2)*...*(x-x_n), expand the derivatives like
993 // automatic differentiation does.
994 const unsigned int n_supp = lagrange_support_points.size();
995 const number weight = lagrange_weight;
996 switch (n_derivatives)
997 {
998 default:
999 for (unsigned int e = 0; e < n_entries; ++e)
1000 values[0][e] = weight;
1001 for (unsigned int k = 1; k <= n_derivatives; ++k)
1002 for (unsigned int e = 0; e < n_entries; ++e)
1003 values[k][e] = 0.;
1004 for (unsigned int i = 0; i < n_supp; ++i)
1005 {
1006 std::array<Number2, n_entries> v = x;
1007 for (unsigned int e = 0; e < n_entries; ++e)
1008 v[e] -= lagrange_support_points[i];
1009
1010 // multiply by (x-x_i) and compute action on all derivatives,
1011 // too (inspired from automatic differentiation: implement the
1012 // product rule for the old value and the new variable 'v',
1013 // i.e., expand value v and derivative one). since we reuse a
1014 // value from the next lower derivative from the steps before,
1015 // need to start from the highest derivative
1016 for (unsigned int k = n_derivatives; k > 0; --k)
1017 for (unsigned int e = 0; e < n_entries; ++e)
1018 values[k][e] = (values[k][e] * v[e] + values[k - 1][e]);
1019 for (unsigned int e = 0; e < n_entries; ++e)
1020 values[0][e] *= v[e];
1021 }
1022 // finally, multiply derivatives by k! to transform the product
1023 // p_n = p^(n)(x)/k! into the actual form of the derivative
1024 {
1025 number k_factorial = 2;
1026 for (unsigned int k = 2; k <= n_derivatives; ++k)
1027 {
1028 for (unsigned int e = 0; e < n_entries; ++e)
1029 values[k][e] *= k_factorial;
1030 k_factorial *= static_cast<number>(k + 1);
1031 }
1032 }
1033 break;
1034
1035 // manually implement case 0 (values only), case 1 (value + first
1036 // derivative), and case 2 (up to second derivative) since they
1037 // might be called often. then, we can unroll the inner loop and
1038 // keep the temporary results as local variables to help the
1039 // compiler with the pointer aliasing analysis.
1040 case 0:
1041 {
1042 std::array<Number2, n_entries> value;
1043 for (unsigned int e = 0; e < n_entries; ++e)
1044 value[e] = weight;
1045 for (unsigned int i = 0; i < n_supp; ++i)
1046 for (unsigned int e = 0; e < n_entries; ++e)
1047 value[e] *= (x[e] - lagrange_support_points[i]);
1048
1049 for (unsigned int e = 0; e < n_entries; ++e)
1050 values[0][e] = value[e];
1051 break;
1052 }
1053
1054 case 1:
1055 {
1056 std::array<Number2, n_entries> value, derivative = {};
1057 for (unsigned int e = 0; e < n_entries; ++e)
1058 value[e] = weight;
1059 for (unsigned int i = 0; i < n_supp; ++i)
1060 for (unsigned int e = 0; e < n_entries; ++e)
1061 {
1062 const Number2 v = x[e] - lagrange_support_points[i];
1063 derivative[e] = derivative[e] * v + value[e];
1064 value[e] *= v;
1065 }
1066
1067 for (unsigned int e = 0; e < n_entries; ++e)
1068 {
1069 values[0][e] = value[e];
1070 values[1][e] = derivative[e];
1071 }
1072 break;
1073 }
1074
1075 case 2:
1076 {
1077 std::array<Number2, n_entries> value, derivative = {},
1078 second = {};
1079 for (unsigned int e = 0; e < n_entries; ++e)
1080 value[e] = weight;
1081 for (unsigned int i = 0; i < n_supp; ++i)
1082 for (unsigned int e = 0; e < n_entries; ++e)
1083 {
1084 const Number2 v = x[e] - lagrange_support_points[i];
1085 second[e] = second[e] * v + derivative[e];
1086 derivative[e] = derivative[e] * v + value[e];
1087 value[e] *= v;
1088 }
1089
1090 for (unsigned int e = 0; e < n_entries; ++e)
1091 {
1092 values[0][e] = value[e];
1093 values[1][e] = derivative[e];
1094 values[2][e] = static_cast<number>(2) * second[e];
1095 }
1096 break;
1097 }
1098 }
1099 return;
1100 }
1101
1102 Assert(coefficients.size() > 0, ExcEmptyObject());
1103
1104 // if derivatives are needed, then do it properly by the full
1105 // Horner scheme
1106 const unsigned int m = coefficients.size();
1107 std::vector<std::array<Number2, n_entries>> a(coefficients.size());
1108 for (unsigned int i = 0; i < coefficients.size(); ++i)
1109 for (unsigned int e = 0; e < n_entries; ++e)
1110 a[i][e] = coefficients[i];
1111
1112 unsigned int j_factorial = 1;
1113
1114 // loop over all requested derivatives. note that derivatives @p{j>m} are
1115 // necessarily zero, as they differentiate the polynomial more often than
1116 // the highest power is
1117 const unsigned int min_valuessize_m = std::min(n_derivatives + 1, m);
1118 for (unsigned int j = 0; j < min_valuessize_m; ++j)
1119 {
1120 for (int k = m - 2; k >= static_cast<int>(j); --k)
1121 for (unsigned int e = 0; e < n_entries; ++e)
1122 a[k][e] += x[e] * a[k + 1][e];
1123 for (unsigned int e = 0; e < n_entries; ++e)
1124 values[j][e] = static_cast<number>(j_factorial) * a[j][e];
1125
1126 j_factorial *= j + 1;
1127 }
1128
1129 // fill higher derivatives by zero
1130 for (unsigned int j = min_valuessize_m; j <= n_derivatives; ++j)
1131 for (unsigned int e = 0; e < n_entries; ++e)
1132 values[j][e] = 0.;
1133 }
1134
1135
1136
1137 template <typename number>
1138 template <class Archive>
1139 inline void
1140 Polynomial<number>::serialize(Archive &ar, const unsigned int)
1141 {
1142 // forward to serialization function in the base class.
1143 ar &static_cast<EnableObserverPointer &>(*this);
1144 ar &coefficients;
1145 ar &in_lagrange_product_form;
1146 ar &lagrange_support_points;
1147 ar &lagrange_weight;
1148 }
1149
1150
1151
1152 template <typename Number>
1153 Number
1154 jacobi_polynomial_value(const unsigned int degree,
1155 const int alpha,
1156 const int beta,
1157 const Number x,
1158 const bool rescale_to_dealii_unit_interval)
1159 {
1160 Assert(alpha >= 0 && beta >= 0,
1161 ExcNotImplemented("Negative alpha/beta coefficients not supported"));
1162 // the Jacobi polynomial is evaluated using a recursion formula.
1163 Number p0, p1;
1164
1165 // The recursion formula is defined for the interval [-1, 1], so rescale
1166 // to that interval here
1167 const Number xeval =
1168 rescale_to_dealii_unit_interval ? Number(-1) + 2. * x : x;
1169
1170 // initial values P_0(x), P_1(x):
1171 p0 = 1.0;
1172 if (degree == 0)
1173 return p0;
1174 p1 = ((alpha + beta + 2) * xeval + (alpha - beta)) / 2;
1175 if (degree == 1)
1176 return p1;
1177
1178 for (unsigned int i = 1; i < degree; ++i)
1179 {
1180 const Number v = 2 * i + (alpha + beta);
1181 const Number a1 = 2 * (i + 1) * (i + (alpha + beta + 1)) * v;
1182 const Number a2 = (v + 1) * (alpha * alpha - beta * beta);
1183 const Number a3 = v * (v + 1) * (v + 2);
1184 const Number a4 = 2 * (i + alpha) * (i + beta) * (v + 2);
1185
1186 const Number pn = ((a2 + a3 * xeval) * p1 - a4 * p0) / a1;
1187 p0 = p1;
1188 p1 = pn;
1189 }
1190 return p1;
1191 }
1192
1193
1194
1195 template <typename Number>
1196 Number
1197 jacobi_polynomial_derivative(const unsigned int degree,
1198 const int alpha,
1199 const int beta,
1200 const Number x,
1201 const bool rescale_to_dealii_unit_interval)
1202 {
1204 1, degree, alpha, beta, x, rescale_to_dealii_unit_interval);
1205 }
1206
1207
1208
1209 template <typename Number>
1210 Number
1211 jacobi_polynomial_kth_derivative(const unsigned int derivative_order,
1212 const unsigned int degree,
1213 const int alpha,
1214 const int beta,
1215 const Number x,
1216 const bool rescale_to_dealii_unit_interval)
1217 {
1218 Assert(alpha >= 0 && beta >= 0,
1219 ExcNotImplemented("Negative alpha/beta coefficients not supported"));
1220
1221 if (derivative_order > degree)
1222 return 0.0;
1223 // P_0 = 1, so the derivative is 0
1224 // special case when derivative_order = 0, then the value should be returned
1225 // and not 0
1226 if (degree == 0 && derivative_order != 0)
1227 return 0.0;
1228
1229 // The derivative of the Jacobi polynomial is evaluated using the recurrence
1230 // relations
1231 Number pre_factor = 1.0;
1232 for (unsigned int i = 1; i < derivative_order + 1; ++i)
1233 pre_factor *= (alpha + beta + degree + i);
1234
1235 if (rescale_to_dealii_unit_interval)
1236 return pre_factor * jacobi_polynomial_value(degree - derivative_order,
1237 alpha + derivative_order,
1238 beta + derivative_order,
1239 x,
1240 true);
1241
1242 return std::pow(0.5, derivative_order) * pre_factor *
1243 jacobi_polynomial_value(degree - derivative_order,
1244 alpha + derivative_order,
1245 beta + derivative_order,
1246 x,
1247 false);
1248 }
1249
1250
1251
1252 template <typename Number>
1253 std::vector<Number>
1254 jacobi_polynomial_roots(const unsigned int degree,
1255 const int alpha,
1256 const int beta)
1257 {
1258 std::vector<Number> x(degree, 0.5);
1259
1260 // compute zeros with a Newton algorithm.
1261
1262 // Set tolerance. For long double we might not always get the additional
1263 // precision in a run time environment (e.g. with valgrind), so we must
1264 // limit the tolerance to double. Since we do a Newton iteration, doing
1265 // one more iteration after the residual has indicated convergence will be
1266 // enough for all number types due to the quadratic convergence of
1267 // Newton's method
1268
1269 const Number tolerance =
1270 4 * std::max(static_cast<Number>(std::numeric_limits<double>::epsilon()),
1271 std::numeric_limits<Number>::epsilon());
1272
1273 // The following implementation follows closely the one given in the
1274 // appendix of the book by Karniadakis and Sherwin: Spectral/hp element
1275 // methods for computational fluid dynamics (Oxford University Press,
1276 // 2005)
1277
1278 // If symmetric, we only need to compute the half of points
1279 const unsigned int n_points = (alpha == beta ? degree / 2 : degree);
1280 for (unsigned int k = 0; k < n_points; ++k)
1281 {
1282 // we take the zeros of the Chebyshev polynomial (alpha=beta=-0.5) as
1283 // initial values, corrected by the initial value
1284 Number r = 0.5 - 0.5 * std::cos(static_cast<Number>(2 * k + 1) /
1285 (2 * degree) * numbers::PI);
1286 if (k > 0)
1287 r = (r + x[k - 1]) / 2;
1288
1289 unsigned int converged = numbers::invalid_unsigned_int;
1290 for (unsigned int it = 1; it < 1000; ++it)
1291 {
1292 Number s = 0.;
1293 for (unsigned int i = 0; i < k; ++i)
1294 s += 1. / (r - x[i]);
1295
1296 // derivative of P_n^{alpha,beta}, rescaled to [0, 1]
1297 const Number J_x =
1298 (alpha + beta + degree + 1) *
1299 jacobi_polynomial_value(degree - 1, alpha + 1, beta + 1, r);
1300
1301 // value of P_n^{alpha,beta}
1302 const Number f = jacobi_polynomial_value(degree, alpha, beta, r);
1303 const Number delta = f / (f * s - J_x);
1304 r += delta;
1305 if (converged == numbers::invalid_unsigned_int &&
1306 std::abs(delta) < tolerance)
1307 converged = it;
1308
1309 // do one more iteration to ensure accuracy also for tighter
1310 // types than double (e.g. long double)
1311 if (it == converged + 1)
1312 break;
1313 }
1314
1316 ExcMessage("Newton iteration for zero of Jacobi polynomial "
1317 "did not converge."));
1318
1319 x[k] = r;
1320 }
1321
1322 // in case we assumed symmetry, fill up the missing values
1323 for (unsigned int k = n_points; k < degree; ++k)
1324 x[k] = 1.0 - x[degree - k - 1];
1325
1326 return x;
1327 }
1328
1329
1330
1331 template <typename Number>
1332 Number
1333 jacobi_polynomial_homogenized_value(const unsigned int degree,
1334 const int alpha,
1335 const int beta,
1336 const Number x,
1337 const Number s)
1338 {
1339 Assert(alpha >= 0 && beta >= 0,
1340 ExcNotImplemented("Negative alpha/beta coefficients not supported"));
1341
1342 // the homogenized Jacobi polynomial is evaluated using a recursion formula
1343 // to get the recursion formula, the recursion rule for the Jacobi
1344 // polynomial is multiplied on both sides by s^degree
1345 Number p0, p1;
1346
1347 // initial values p0 = s^0 * P_0(2x/s-1) = 1 * 1 = 1, p1 = s * P_1(2x/s-1):
1348 p0 = 1.0;
1349 if (degree == 0)
1350 return p0;
1351 p1 = ((alpha + beta + 2.0) * (2.0 * x - s) + s * (alpha - beta)) / 2.0;
1352 if (degree == 1)
1353 return p1;
1354
1355 for (unsigned int i = 1; i < degree; ++i)
1356 {
1357 const Number v = 2 * i + (alpha + beta);
1358 const Number a1 = 2 * (i + 1) * (i + (alpha + beta + 1)) * v;
1359 const Number a2 = (v + 1) * (alpha * alpha - beta * beta);
1360 const Number a3 = v * (v + 1) * (v + 2);
1361 const Number a4 = 2 * (i + alpha) * (i + beta) * (v + 2);
1362
1363 const Number pn =
1364 ((a2 * s + a3 * (2.0 * x - s)) * p1 - a4 * s * s * p0) / a1;
1365 p0 = p1;
1366 p1 = pn;
1367 }
1368 return p1;
1369 }
1370
1371
1372
1373 template <typename Number>
1374 Number
1376 const unsigned int order_s,
1377 const unsigned int degree,
1378 const int alpha,
1379 const int beta,
1380 const Number x,
1381 const Number s)
1382 {
1383 Assert(alpha >= 0 && beta >= 0,
1384 ExcNotImplemented("Negative alpha/beta coefficients not supported"));
1385
1386 if (order_x + order_s > degree)
1387 return 0.0;
1388 if (degree == 0 && (order_x + order_s != 0))
1389 return 0.0;
1390
1391 // The derivative of the homogenized Jacobi polynomial is evaluated using
1392 // the recurrence relations
1393 Number pre_factor = 1.0;
1394 for (unsigned int i = 1; i < order_x + 1; ++i)
1395 pre_factor *= (alpha + beta + degree + i);
1396
1397 for (unsigned int i = 0; i < order_s; ++i)
1398 pre_factor *= (degree + beta - i);
1399
1400 const Number derivative =
1401 std::pow(-1.0, order_s) * pre_factor *
1402 jacobi_polynomial_homogenized_value<Number>(degree - order_x - order_s,
1403 alpha + order_x + order_s,
1404 beta + order_x,
1405 x,
1406 s);
1407
1408 return derivative;
1409 }
1410} // namespace Polynomials
1412
1413#endif
Definition point.h:111
static std::vector< Polynomial< double > > generate_complete_basis(const unsigned int p)
static std::vector< Polynomial< double > > generate_complete_basis(const unsigned int degree)
static std::vector< std::unique_ptr< const std::vector< double > > > recursive_coefficients
Definition polynomial.h:599
static void compute_coefficients(const unsigned int p)
static const std::vector< double > & get_coefficients(const unsigned int p)
static std::vector< Polynomial< double > > generate_complete_basis(const unsigned int degree)
static std::shared_mutex coefficients_lock
Definition polynomial.h:605
static void compute_coefficients(const unsigned int n, const unsigned int support_point, std::vector< double > &a)
static std::vector< Polynomial< double > > generate_complete_basis(const unsigned int degree)
static std::vector< Polynomial< double > > generate_complete_basis(const unsigned int degree)
std::vector< double > compute_coefficients(const unsigned int p)
static std::vector< Polynomial< double > > generate_complete_basis(const unsigned int p)
static std::vector< Polynomial< number > > generate_complete_basis(const unsigned int degree)
static std::vector< Point< 1 > > create_vector_of_roots(unsigned int n)
number value(const number x) const
Definition polynomial.h:935
bool operator==(const Polynomial< number > &p) const
std::vector< number > coefficients
Definition polynomial.h:323
Polynomial< number > primitive() const
Polynomial< number > & operator+=(const Polynomial< number > &p)
void values_of_array(const std::array< Number2, n_entries > &points, const unsigned int n_derivatives, std::array< Number2, n_entries > *values) const
Definition polynomial.h:983
Polynomial< number > derivative() const
void transform_into_standard_form()
Definition polynomial.cc:94
void scale(const number factor)
Polynomial< number > & operator-=(const Polynomial< number > &p)
std::vector< number > lagrange_support_points
Definition polynomial.h:335
void shift(const number2 offset)
void print(std::ostream &out) const
void serialize(Archive &ar, const unsigned int version)
static void multiply(std::vector< number > &coefficients, const number factor)
void value(const Number2 x, const unsigned int n_derivatives, Number2 *values) const
Definition polynomial.h:965
Polynomial< number > & operator*=(const double s)
virtual std::size_t memory_consumption() const
unsigned int degree() const
Definition polynomial.h:918
#define DEAL_II_ALWAYS_INLINE
Definition config.h:166
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
Point< 2 > second
Definition grid_out.cc:4640
static ::ExceptionBase & ExcNotImplemented()
static ::ExceptionBase & ExcEmptyObject()
#define Assert(cond, exc)
static ::ExceptionBase & ExcMessage(std::string arg1)
Number jacobi_polynomial_kth_derivative(const unsigned int derivative_order, const unsigned int degree, const int alpha, const int beta, const Number x, const bool rescale_to_dealii_unit_interval)
Number jacobi_polynomial_homogenized_derivative(const unsigned int order_x, const unsigned int order_s, const unsigned int degree, const int alpha, const int beta, const Number x, const Number s)
Number jacobi_polynomial_derivative(const unsigned int degree, const int alpha, const int beta, const Number x, const bool rescale_to_dealii_unit_interval)
std::vector< Polynomial< double > > generate_complete_Lagrange_basis(const std::vector< Point< 1 > > &points)
Number jacobi_polynomial_homogenized_value(const unsigned int degree, const int alpha, const int beta, const Number x, const Number s)
std::vector< Number > jacobi_polynomial_roots(const unsigned int degree, const int alpha, const int beta)
Number jacobi_polynomial_value(const unsigned int degree, const int alpha, const int beta, const Number x, const bool rescale_to_dealii_unit_interval=true)
constexpr double PI
Definition numbers.h:240
constexpr unsigned int invalid_unsigned_int
Definition types.h:228
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > cos(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > pow(const ::VectorizedArray< Number, width > &, const Number p)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)