GLAMERDOC++
Gravitational Lensing Code Library
Loading...
Searching...
No Matches
quadrature.h
1#pragma once
2
3#include <vector>
4#include <algorithm>
5#include <cmath>
6
7namespace ISOP
8{
9 namespace detail
10 {
13 {
14 quadrature_task(double value, double error,
15 double a0, double b0, double a1, double b1,
16 double x00, double x0c, double x0n,
17 double xc0, double xcc, double xcn,
18 double xn0, double xnc, double xnn)
19 : value(value), error(error),
20 a0(a0), b0(b0), a1(a1), b1(b1),
21 x00(x00), x0c(x0c), x0n(x0n),
22 xc0(xc0), xcc(xcc), xcn(xcn),
23 xn0(xn0), xnc(xnc), xnn(xnn)
24 {
25 }
26
27 bool operator<(const quadrature_task& other) const
28 {
29 return std::abs(error) < std::abs(other.error);
30 }
31
32 double value;
33 double error;
34
35 double a0;
36 double b0;
37 double a1;
38 double b1;
39
40 double x00, x0c, x0n;
41 double xc0, xcc, xcn;
42 double xn0, xnc, xnn;
43 };
44 }
45
47 namespace Rules
48 {
50 template<int N>
52 {
53 static const int n = 2*N-1;
54 static const double p[n];
55 static const double w[n];
56 static const double e[n];
57 };
58
60 template<int N>
62 {
63 static const int n = 2*N-1;
64 static const double p[n];
65 static const double w[n];
66 static const double e[n];
67 };
68 }
69
72 {
73 double value;
74 double error;
75 };
76
77 template<typename Rule, typename Function>
78 inline quadrature_result quadrature(Function f, double a0, double b0, double a1, double b1, double pg, double ag)
79 {
81
82 // container type for queue
83 typedef std::vector<quadrature_task> queue_container;
84
85 // iterator types for queue
86 typedef queue_container::const_iterator queue_iterator;
87
88 // calculated function values
89 double values[Rule::n][Rule::n];
90
91 // constants for easier access
92 const int n = Rule::n-1;
93 const int c = (Rule::n-1)/2;
94
95 // do initial quadrature
96 for(int i = 0; i < Rule::n; ++i)
97 for(int j = 0; j < Rule::n; ++j)
98 values[i][j] = f(0.5*((b0-a0)*Rule::p[i]+a0+b0), 0.5*((b1-a1)*Rule::p[j]+a1+b1));
99
100 // calculate initial result
101 quadrature_result result = {0, 0};
102 for(int i = 0; i < Rule::n; ++i)
103 {
104 for(int j = 0; j < Rule::n; ++j)
105 {
106 result.value += Rule::w[i]*Rule::w[j]*values[i][j];
107 result.error += Rule::e[i]*Rule::e[j]*values[i][j];
108 }
109 }
110 result.value = 0.25*(b0-a0)*(b1-a1)*result.value;
111 result.error = 0.25*(b0-a0)*(b1-a1)*std::abs(result.error);
112
113 // queue of subdivisions to refine
114 queue_container queue;
115 std::make_heap(queue.begin(), queue.end());
116
117 // push initial task to queue
118 queue.push_back(quadrature_task(
119 result.value, result.error,
120 a0, b0, a1, b1,
121 values[0][0], values[0][c], values[0][n],
122 values[c][0], values[c][c], values[c][n],
123 values[n][0], values[n][c], values[n][n]
124 ));
125 std::push_heap(queue.begin(), queue.end());
126
127 // refine until accuracy or precision goal is reached
128 while(result.error > std::abs(result.value)*pg && result.error > ag)
129 {
130 // get top task from queue
131 quadrature_task task = queue.front();
132
133 // pop task from queue
134 std::pop_heap(queue.begin(), queue.end());
135 queue.pop_back();
136
137 // subdivide area
138 for(int k = 0; k < 4; ++k)
139 {
140 // four quadrants for subdivision
141 switch(k)
142 {
143 case 0:
144 a0 = task.a0;
145 b0 = 0.5*(task.a0+task.b0);
146 a1 = task.a1;
147 b1 = 0.5*(task.a1+task.b1);
148 values[0][0] = task.x00;
149 values[0][n] = task.x0c;
150 values[n][0] = task.xc0;
151 values[n][n] = task.xcc;
152 break;
153
154 case 1:
155 a0 = 0.5*(task.a0+task.b0);
156 b0 = task.b0;
157 a1 = task.a1;
158 b1 = 0.5*(task.a1+task.b1);
159 values[0][0] = task.xc0;
160 values[0][n] = task.xcc;
161 values[n][0] = task.xn0;
162 values[n][n] = task.xnc;
163 break;
164
165 case 2:
166 a0 = task.a0;
167 b0 = 0.5*(task.a0+task.b0);
168 a1 = 0.5*(task.a1+task.b1);
169 b1 = task.b1;
170 values[0][0] = task.x0c;
171 values[0][n] = task.x0n;
172 values[n][0] = task.xcc;
173 values[n][n] = task.xcn;
174 break;
175
176 case 3:
177 a0 = 0.5*(task.a0+task.b0);
178 b0 = task.b0;
179 a1 = 0.5*(task.a1+task.b1);
180 b1 = task.b1;
181 values[0][0] = task.xcc;
182 values[0][n] = task.xcn;
183 values[n][0] = task.xnc;
184 values[n][n] = task.xnn;
185 break;
186 }
187
188 // do subdivision quadrature
189 for(int j = 1; j < n; ++j)
190 values[0][j] = f(0.5*((b0-a0)*Rule::p[0]+a0+b0), 0.5*((b1-a1)*Rule::p[j]+a1+b1));
191 for(int i = 1; i < n; ++i)
192 for(int j = 0; j < Rule::n; ++j)
193 values[i][j] = f(0.5*((b0-a0)*Rule::p[i]+a0+b0), 0.5*((b1-a1)*Rule::p[j]+a1+b1));
194 for(int j = 1; j < n; ++j)
195 values[n][j] = f(0.5*((b0-a0)*Rule::p[n]+a0+b0), 0.5*((b1-a1)*Rule::p[j]+a1+b1));
196
197 // calculate subdivision result
198 quadrature_result sub = {0, 0};
199 for(int i = 0; i < Rule::n; ++i)
200 {
201 for(int j = 0; j < Rule::n; ++j)
202 {
203 sub.value += Rule::w[i]*Rule::w[j]*values[i][j];
204 sub.error += Rule::e[i]*Rule::e[j]*values[i][j];
205 }
206 }
207 sub.value = 0.25*(b0-a0)*(b1-a1)*sub.value;
208 sub.error = 0.25*(b0-a0)*(b1-a1)*sub.error;
209
210 // push subdivision task to queue
211 queue.push_back(quadrature_task(
212 sub.value, sub.error,
213 a0, b0, a1, b1,
214 values[0][0], values[0][c], values[0][n],
215 values[c][0], values[c][c], values[c][n],
216 values[n][0], values[n][c], values[n][n]
217 ));
218 std::push_heap(queue.begin(), queue.end());
219 }
220
221 // update result value and error
222 result.value = 0;
223 result.error = 0;
224 for(queue_iterator it = queue.begin(); it != queue.end(); ++it)
225 {
226 result.value += it->value;
227 result.error += it->error;
228 }
229 result.error = std::abs(result.error);
230 }
231
232 // done
233 return result;
234 }
235}
ISOP namespace is for functions related to isoparametric interpolation.
Definition isop.h:7
Clenshaw-Curtis quadrature data.
Definition quadrature.h:52
Lobatto-Kronrod quadrature data.
Definition quadrature.h:62
Subdivided area in quadrature with value and error estimate.
Definition quadrature.h:13
Result of numerical integration.
Definition quadrature.h:72