limes 3.1.0
Composable Calculus Expressions for C++20
Loading...
Searching...
No Matches
quadrature.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4#include <cmath>
5#include <numbers>
6#include "../concepts/concepts.hpp"
7
9
10// Base quadrature rule: stores N nodes and weights on [-1, 1]
11template<concepts::Field T, std::size_t N>
13 using value_type = T;
14 using size_type = std::size_t;
15
16 static constexpr size_type size() noexcept { return N; }
17
18 std::array<T, N> weights;
19 std::array<T, N> abscissas;
20
21 constexpr T weight(size_type i) const noexcept { return weights[i]; }
22 constexpr T abscissa(size_type i) const noexcept { return abscissas[i]; }
23};
24
25// Gauss-Legendre quadrature (primary template requires specialization)
26template<concepts::Field T, std::size_t N>
28 static_assert(N == 2 || N == 3 || N == 5 || N == 7 || N == 15,
29 "gauss_legendre is only specialized for N = 2, 3, 5, 7, 15");
30};
31
32// Specialized implementations for common orders
33template<concepts::Field T>
34struct gauss_legendre<T, 2> : quadrature_rule<T, 2> {
35 constexpr gauss_legendre() noexcept {
36 constexpr T sqrt3 = T(0.5773502691896257645091487805019574556);
37 this->abscissas = {-sqrt3, sqrt3};
38 this->weights = {T(1), T(1)};
39 }
40};
41
42template<concepts::Field T>
43struct gauss_legendre<T, 3> : quadrature_rule<T, 3> {
44 constexpr gauss_legendre() noexcept {
45 constexpr T sqrt35 = T(0.7745966692414833770358530799564799221);
46 this->abscissas = {-sqrt35, T(0), sqrt35};
47 this->weights = {T(5)/T(9), T(8)/T(9), T(5)/T(9)};
48 }
49};
50
51template<concepts::Field T>
52struct gauss_legendre<T, 5> : quadrature_rule<T, 5> {
53 constexpr gauss_legendre() noexcept {
54 constexpr T x1 = T(0.9061798459386639927976268782993929651);
55 constexpr T x2 = T(0.5384693101056830910363144207002088049);
56 constexpr T w1 = T(0.2369268850561890875142640407199173626);
57 constexpr T w2 = T(0.4786286704993664680412915148356381929);
58 constexpr T w3 = T(0.5688888888888888888888888888888888889);
59
60 this->abscissas = {-x1, -x2, T(0), x2, x1};
61 this->weights = {w1, w2, w3, w2, w1};
62 }
63};
64
65template<concepts::Field T>
66struct gauss_legendre<T, 7> : quadrature_rule<T, 7> {
67 constexpr gauss_legendre() noexcept {
68 constexpr T x1 = T(0.9491079123427585245261896840478512624);
69 constexpr T x2 = T(0.7415311855993944398638647732807884070);
70 constexpr T x3 = T(0.4058451513773971669066064120769614633);
71 constexpr T w1 = T(0.1294849661688696932706114326790820183);
72 constexpr T w2 = T(0.2797053914892766679014677714237795824);
73 constexpr T w3 = T(0.3818300505051189449503697754889751338);
74 constexpr T w4 = T(0.4179591836734693877551020408163265306);
75
76 this->abscissas = {-x1, -x2, -x3, T(0), x3, x2, x1};
77 this->weights = {w1, w2, w3, w4, w3, w2, w1};
78 }
79};
80
81template<concepts::Field T>
82struct gauss_legendre<T, 15> : quadrature_rule<T, 15> {
83 constexpr gauss_legendre() noexcept {
84 this->abscissas = {
85 T(-0.9879925180204854284895657185866125811),
86 T(-0.9372733924007059043077589477102094712),
87 T(-0.8482065834104272076884935534726048004),
88 T(-0.7244177313601700474161860546139379979),
89 T(-0.5709721726085388475372267372539106413),
90 T(-0.3941513470775633698972073709810454684),
91 T(-0.2011940939974345223006283033945962078),
92 T(0.0),
93 T(0.2011940939974345223006283033945962078),
94 T(0.3941513470775633698972073709810454684),
95 T(0.5709721726085388475372267372539106413),
96 T(0.7244177313601700474161860546139379979),
97 T(0.8482065834104272076884935534726048004),
98 T(0.9372733924007059043077589477102094712),
99 T(0.9879925180204854284895657185866125811)
100 };
101 this->weights = {
102 T(0.0307532419961172683546283935772044177),
103 T(0.0703660474881081247092674164506673384),
104 T(0.1071592204671719350118695466858693034),
105 T(0.1395706779261543144478047945110283225),
106 T(0.1662692058169939335532008604812088111),
107 T(0.1861610000155622110268005618664228245),
108 T(0.1984314853271115764561183264438393248),
109 T(0.2025782419255612728806201999675193148),
110 T(0.1984314853271115764561183264438393248),
111 T(0.1861610000155622110268005618664228245),
112 T(0.1662692058169939335532008604812088111),
113 T(0.1395706779261543144478047945110283225),
114 T(0.1071592204671719350118695466858693034),
115 T(0.0703660474881081247092674164506673384),
116 T(0.0307532419961172683546283935772044177)
117 };
118 }
119};
120
121// Gauss-Kronrod 7-15 rule (extends Gauss-Legendre with embedded error estimation)
122template<concepts::Field T>
124 constexpr gauss_kronrod_15() noexcept {
125 this->abscissas = {
126 T(-0.9914553711208126), T(-0.9491079123427585), T(-0.8648644233597691),
127 T(-0.7415311855993944), T(-0.5860872354676911), T(-0.4058451513773972),
128 T(-0.2077849550078985), T(0),
129 T(0.2077849550078985), T(0.4058451513773972), T(0.5860872354676911),
130 T(0.7415311855993944), T(0.8648644233597691), T(0.9491079123427585),
131 T(0.9914553711208126)
132 };
133
134 this->weights = {
135 T(0.0229353220105292), T(0.0630920926299785), T(0.1047900103222502),
136 T(0.1406532597155259), T(0.1690047266392679), T(0.1903505780647854),
137 T(0.2044329400752989), T(0.2094821410847278),
138 T(0.2044329400752989), T(0.1903505780647854), T(0.1690047266392679),
139 T(0.1406532597155259), T(0.1047900103222502), T(0.0630920926299785),
140 T(0.0229353220105292)
141 };
142 }
143
144 // Embedded 7-point Gauss rule for error estimation
145 static constexpr std::size_t gauss_size = 7;
146 std::array<T, gauss_size> gauss_weights = {
147 T(0.1294849661688697), T(0.2797053914892767), T(0.3818300505051189),
148 T(0.4179591836734694),
149 T(0.3818300505051189), T(0.2797053914892767), T(0.1294849661688697)
150 };
151 std::array<std::size_t, gauss_size> gauss_indices = {1, 3, 5, 7, 9, 11, 13};
152};
153
154// Clenshaw-Curtis quadrature
155template<concepts::Field T, std::size_t N>
157 constexpr clenshaw_curtis() noexcept {
158 compute_nodes();
159 }
160
161private:
162 constexpr void compute_nodes() noexcept {
163 constexpr T pi = std::numbers::pi_v<T>;
164 constexpr std::size_t n = N - 1;
165
166 for (std::size_t i = 0; i < N; ++i) {
167 T theta = pi * T(i) / T(n);
168 this->abscissas[i] = -std::cos(theta);
169
170 T w = T(0);
171 std::size_t max_j = n / 2;
172 for (std::size_t j = 0; j <= max_j; ++j) {
173 T cos_term = std::cos(T(2) * j * theta);
174 T b_j = (j == 0 || j == max_j) ? T(1) : T(2);
175
176 if (j == 0) {
177 w += b_j * cos_term;
178 } else {
179 w -= b_j * cos_term / (T(4) * j * j - T(1));
180 }
181 }
182
183 w *= T(2) / T(n);
184 if (i == 0 || i == n) {
185 w /= T(2);
186 }
187
188 this->weights[i] = w;
189 }
190 }
191};
192
193// Simpson's rule (3-point, exact for cubics)
194template<concepts::Field T>
196 constexpr simpson_rule() noexcept {
197 this->abscissas = {T(-1), T(0), T(1)};
198 this->weights = {T(1)/T(3), T(4)/T(3), T(1)/T(3)};
199 }
200};
201
202// Trapezoidal rule (2-point, exact for linear)
203template<concepts::Field T>
205 constexpr trapezoidal_rule() noexcept {
206 this->abscissas = {T(-1), T(1)};
207 this->weights = {T(1), T(1)};
208 }
209};
210
211// Midpoint rule (1-point, exact for linear)
212template<concepts::Field T>
214 constexpr midpoint_rule() noexcept {
215 this->abscissas = {T(0)};
216 this->weights = {T(2)};
217 }
218};
219
220// Tanh-sinh (double exponential) quadrature nodes
221template<concepts::Field T>
223public:
224 using value_type = T;
225
226 static constexpr std::size_t max_level = 10;
227
228 constexpr T abscissa(std::size_t level, std::size_t index) const noexcept {
229 T t = node_parameter(level, index);
230 return transform_abscissa(t);
231 }
232
233 constexpr T weight(std::size_t level, std::size_t index) const noexcept {
234 T h = T(1) / std::pow(T(2), level);
235 T t = node_parameter(level, index);
236 return h * transform_weight(t);
237 }
238
239private:
240 static constexpr T node_parameter(std::size_t level, std::size_t index) noexcept {
241 T h = T(1) / std::pow(T(2), level);
242 return (index == 0) ? T(0) : h * T(index);
243 }
244
245 static constexpr T transform_abscissa(T t) noexcept {
246 T expmt = std::exp(-t);
247 T u = std::exp(t - expmt);
248 return (u - T(1)/u) / (u + T(1)/u);
249 }
250
251 static constexpr T transform_weight(T t) noexcept {
252 T expmt = std::exp(-t);
253 T u = std::exp(t - expmt);
254 T cosh_val = (u + T(1)/u) / T(2);
255 return (T(1) + expmt) / (cosh_val * cosh_val);
256 }
257};
258
259} // namespace limes::algorithms::quadrature
constexpr T abscissa(std::size_t level, std::size_t index) const noexcept
constexpr T weight(std::size_t level, std::size_t index) const noexcept
std::array< std::size_t, gauss_size > gauss_indices
constexpr T abscissa(size_type i) const noexcept
static constexpr size_type size() noexcept
constexpr T weight(size_type i) const noexcept