ViennaSHE 1.3.0
Free open-source semiconductor device simulator using spherical harmonics expansions techniques.
integrator.hpp
Go to the documentation of this file.
1#ifndef VIENNASHE_MATH_INTEGRATOR_HPP
2#define VIENNASHE_MATH_INTEGRATOR_HPP
3
4/* ============================================================================
5 Copyright (c) 2011-2022, Institute for Microelectronics,
6 Institute for Analysis and Scientific Computing,
7 TU Wien.
8
9 -----------------
10 ViennaSHE - The Vienna Spherical Harmonics Expansion Boltzmann Solver
11 -----------------
12
13 http://viennashe.sourceforge.net/
14
15 License: MIT (X11), see file LICENSE in the base directory
16=============================================================================== */
17
21
22#include <math.h>
23#include <iostream>
24
25#include "viennashe/forwards.h"
26
27#include "viennashe/log/log.hpp"
29
36namespace viennashe
37{
39 namespace math
40 {
41
42
43 //Tags:
50
57 template <typename IntRule>
59
66 template <int int_points>
67 class IntGauss {};
68
69
74 template <typename T>
76 {
77 public:
78 BindFirst(T const & func, double value) : func_(func), value_(value) {}
79
80 double operator()(double x) const { return func_(value_, x); }
81 double operator()(double x1, double x2) const { return func_(value_, x1, x2); }
82 double operator()(double x1, double x2, double x3) const { return func_(value_, x1, x2, x3); }
83 double operator()(double x1, double x2, double x3, double x4) const { return func_(value_, x1, x2, x3, x4); }
84
85 operator double() const { return func_(value_); }
86
87 private:
88 T const & func_;
89 double value_;
90 };
91
96 template <typename T>
98 {
99 public:
100 BindSecond(T const & func, double value) : func_(func), value_(value) {}
101
102 double operator()(double x) const { return func_(x, value_); }
103 double operator()(double x1, double x2) const { return func_(x1, value_, x2); }
104 double operator()(double x1, double x2, double x3) const { return func_(x1, value_, x2, x3); }
105 double operator()(double x1, double x2, double x3, double x4) const { return func_(x1, value_, x2, x3, x4); }
106
107 //operator double() const { return func_(value_); } //meaningless in this case!
108
109 private:
110 T const & func_;
111 double value_;
112 };
113
114
115
117 template <typename T>
118 double integrate(T const & f, double a, double b, IntMidPointRule)
119 {
120 //log::debug<log_integrate>() << "Midpoint: " << f( (a+b)/2.0 ) << ", " << a << "," << b << std::endl;
121 return ( f( (a+b)/2.0 ) ) * fabs(b-a);
122 }
123
125 template <typename T>
126 double integrate(T const & f, double a, double b, IntTrapezoidalRule)
127 {
128 return ( f(a) + f(b) ) * fabs(b-a) / 2.0;
129 }
130
132 template <typename T>
133 double integrate(T const & f, double a, double b, IntSimpsonRule)
134 {
135 return (f( a ) + 4.0 * f( (a+b)/2.0 ) + f(b)) * fabs(b-a) / 6.0;
136 }
137
139 template <typename T>
140 double integrate(T const & f, double a, double b, IntGauss<1>)
141 {
142 return f( (a + b) / 2.0 ) * fabs(b-a);
143 }
144
146 template <typename T>
147 double integrate(T const & f, double a, double b, IntGauss<2>)
148 {
149 double xmid = (a + b) / 2.0;
150 double xdiff = (b - a) * 0.288675135;
151 //log::debug<log_integrate>() << f( xmid - xdiff ) << ", " << f( xmid + xdiff ) << std::endl;
152 return (f( xmid - xdiff ) + f( xmid + xdiff )) * fabs(b-a) / 2.0;
153 }
154
156 template <typename T>
157 double integrate(T const & f, double a, double b, IntGauss<3>)
158 {
159 double xmid = (a + b) / 2.0;
160 double xdiff = (b - a) * 0.387298335;
161 return ( f(xmid - xdiff ) * 5.0/9.0
162 + f(xmid) * 8.0/9.0
163 + f(xmid + xdiff ) * 5.0/9.0) * fabs(b-a) / 2.0;
164 }
165
167 template <typename T>
168 double integrate(T const & f, double a, double b, IntGauss<4>)
169 {
170 double xmid = (a + b) / 2.0;
171 double xdiff = (b - a) / 2.0;
172
173 return ( f(xmid - xdiff * 0.8611363115940525752239465 ) * 0.3478548451374538573730639
174 + f(xmid - xdiff * 0.3399810435848562648026658 ) * 0.6521451548625461426269361
175 + f(xmid + xdiff * 0.3399810435848562648026658 ) * 0.6521451548625461426269361
176 + f(xmid + xdiff * 0.8611363115940525752239465 ) * 0.3478548451374538573730639) * xdiff;
177 }
178
180 template <typename T>
181 double integrate(T const & f, double a, double b, IntGauss<5>)
182 {
183 double xmid = (a + b) / 2.0;
184 double xdiff = (b - a) / 2.0;
185
186 return ( f(xmid - xdiff * 0.90617985 ) * 0.23692689
187 + f(xmid - xdiff * 0.53846931 ) * 0.47862867
188 + f(xmid ) * 0.56888888888889
189 + f(xmid + xdiff * 0.53846931 ) * 0.47862867
190 + f(xmid + xdiff * 0.90617985 ) * 0.23692689) * xdiff;
191 }
192
193
195 template <typename T>
196 double integrate(T const & f, double a, double b, IntGauss<6>)
197 {
198 double xmid = (a + b) / 2.0;
199 double xdiff = (b - a) / 2.0;
200
201 return ( f(xmid - xdiff * 0.9324695142031520278123016 ) * 0.1713244923791703450402961
202 + f(xmid - xdiff * 0.6612093864662645136613996 ) * 0.3607615730481386075698335
203 + f(xmid - xdiff * 0.2386191860831969086305017 ) * 0.4679139345726910473898703
204 + f(xmid + xdiff * 0.2386191860831969086305017 ) * 0.4679139345726910473898703
205 + f(xmid + xdiff * 0.6612093864662645136613996 ) * 0.3607615730481386075698335
206 + f(xmid + xdiff * 0.9324695142031520278123016 ) * 0.1713244923791703450402961) * xdiff;
207 }
208
210 template <typename T>
211 double integrate(T const & f, double a, double b, IntGauss<7>)
212 {
213 double xmid = (a + b) / 2.0;
214 double xdiff = (b - a) / 2.0;
215
216 return ( f(xmid - xdiff * 0.9491079123427585245261897 ) * 0.1294849661688696932706114
217 + f(xmid - xdiff * 0.7415311855993944398638648 ) * 0.2797053914892766679014678
218 + f(xmid - xdiff * 0.4058451513773971669066064 ) * 0.3818300505051189449503698
219 + f(xmid ) * 0.4179591836734693877551020
220 + f(xmid + xdiff * 0.4058451513773971669066064 ) * 0.3818300505051189449503698
221 + f(xmid + xdiff * 0.7415311855993944398638648 ) * 0.2797053914892766679014678
222 + f(xmid + xdiff * 0.9491079123427585245261897 ) * 0.1294849661688696932706114) * xdiff;
223 }
224
225
227 template <typename T>
228 double integrate(T const & f, double a, double b, IntGauss<8>)
229 {
230 double xmid = (a + b) / 2.0;
231 double xdiff = (b - a) / 2.0;
232
233 return ( f(xmid - xdiff * 0.96028986 ) * 0.10122854
234 + f(xmid - xdiff * 0.79666648 ) * 0.22238103
235 + f(xmid - xdiff * 0.52553241 ) * 0.31370665
236 + f(xmid - xdiff * 0.18343464 ) * 0.36268378
237 + f(xmid + xdiff * 0.18343464 ) * 0.36268378
238 + f(xmid + xdiff * 0.52553241 ) * 0.31370665
239 + f(xmid + xdiff * 0.79666648 ) * 0.22238103
240 + f(xmid + xdiff * 0.96028986 ) * 0.10122854) * xdiff;
241 }
242
244 template <typename T>
245 double integrate(T const & f, double a, double b, IntGauss<9>)
246 {
247 double xmid = (a + b) / 2.0;
248 double xdiff = (b - a) / 2.0;
249
250 return ( f(xmid - xdiff * 0.9681602395076260898355762 ) * 0.0812743883615744119718922
251 + f(xmid - xdiff * 0.8360311073266357942994298 ) * 0.1806481606948574040584720
252 + f(xmid - xdiff * 0.6133714327005903973087020 ) * 0.2606106964029354623187429
253 + f(xmid - xdiff * 0.3242534234038089290385380 ) * 0.3123470770400028400686304
254 + f(xmid ) * 0.3302393550012597631645251
255 + f(xmid + xdiff * 0.3242534234038089290385380 ) * 0.3123470770400028400686304
256 + f(xmid + xdiff * 0.6133714327005903973087020 ) * 0.2606106964029354623187429
257 + f(xmid + xdiff * 0.8360311073266357942994298 ) * 0.1806481606948574040584720
258 + f(xmid + xdiff * 0.9681602395076260898355762 ) * 0.0812743883615744119718922) * xdiff;
259 }
260
262 template <typename T>
263 double integrate(T const & f, double a, double b, IntGauss<10>)
264 {
265 double xmid = (a + b) / 2.0;
266 double xdiff = (b - a) / 2.0;
267
268 return ( f(xmid - xdiff * 0.9739065285171717200779640 ) * 0.0666713443086881375935688
269 + f(xmid - xdiff * 0.8650633666889845107320967 ) * 0.1494513491505805931457763
270 + f(xmid - xdiff * 0.6794095682990244062343274 ) * 0.2190863625159820439955349
271 + f(xmid - xdiff * 0.4333953941292471907992659 ) * 0.2692667193099963550912269
272 + f(xmid - xdiff * 0.1488743389816312108848260 ) * 0.2955242247147528701738930
273 + f(xmid + xdiff * 0.1488743389816312108848260 ) * 0.2955242247147528701738930
274 + f(xmid + xdiff * 0.4333953941292471907992659 ) * 0.2692667193099963550912269
275 + f(xmid + xdiff * 0.6794095682990244062343274 ) * 0.2190863625159820439955349
276 + f(xmid + xdiff * 0.8650633666889845107320967 ) * 0.1494513491505805931457763
277 + f(xmid + xdiff * 0.9739065285171717200779640 ) * 0.0666713443086881375935688) * xdiff;
278 }
279
280
282 template <typename T, typename U>
283 double integrate(T const & f, double a, double b, IntAdaptiveRule<U> adaptiverule, long recursion_depth = 0)
284 {
285 double direct = integrate(f, a, b, U());
286
287 //log::debug<log_integrate>() << "Calling adaptive with a=" << a << ", b=" << b << " and recursion_depth=" << recursion_depth << std::endl;
288
289 if (recursion_depth == 10)
290 {
291 //double half_left = integrate(f, a, (a+b)/2.0, U());
292 //double half_right = integrate(f, (a+b)/2.0, b, U());
293
294 //log::warn<log_integrate>() << "Recursion depth reached. a: " << a << ", b: " << b << ". Error: " << (direct - half_left - half_right) / direct << std::endl;
295 return direct;
296 }
297
298 double half_left = integrate(f, a, (a+b)/2.0, U());
299 double half_right = integrate(f, (a+b)/2.0, b, U());
300
301 if ( fabs(direct) > 1e-8 )
302 {
303 //check relative tolerance:
304 if ( fabs( (direct - half_left - half_right) / direct) > 1e-8 )
305 {
306 //relative tolerance too large - split integration interval:
307 return integrate(f, a, (a+b)/2.0, adaptiverule, recursion_depth + 1) + integrate(f, (a+b)/2.0, b, adaptiverule, recursion_depth + 1);
308 }
309
310 log::warn<log_integrate>() << "Precision reached: a: " << a << ", b: " << b << std::endl;
311 return half_left + half_right;
312 }
313
314 if ( fabs(direct - (half_left + half_right)) > 1e-8 )
315 {
316 //absolute tolerance too large - split integration interval:
317 return integrate(f, a, (a+b)/2.0, adaptiverule, recursion_depth + 1) + integrate(f, (a+b)/2.0, b, adaptiverule, recursion_depth + 1);
318 }
319
320 return half_left + half_right;
321 }
322
324 template <typename T, typename IntRule>
326 {
327 public:
328 IntegrationBinder(T const & func, double a, double b) : func_(func), a_(a), b_(b) {};
329
330 double operator()(double x) const
331 {
332 BindFirst<T> integrand(func_, x);
333 return integrate(integrand, a_, b_, IntRule());
334 }
335
336
337 private:
338 T const & func_;
339 double a_;
340 double b_;
341 };
342
343
344
356 template <typename T, typename IntRuleTag>
357 double integrate2D(double a1, double b1,
358 double a2, double b2, T const & func2integrate, IntRuleTag)
359 {
360 IntegrationBinder<T, IntRuleTag> innerIntegral(func2integrate, a2, b2);
361
362 double result = integrate(innerIntegral, a1, b1, IntRuleTag());
363 log::debug<log_integrate>() << "check 0.25: " << innerIntegral(0.25) << std::endl;
364 log::debug<log_integrate>() << "check 0.5: " << innerIntegral(0.5) << std::endl;
365 log::debug<log_integrate>() << "check 0.75: " << innerIntegral(0.75) << std::endl;
366
367 return result;
368 }
369
370 } //namespace math
371} //namespace viennashe
372#endif
Binds the first argument of a function of functor to a certain value.
Definition: integrator.hpp:76
double operator()(double x1, double x2, double x3, double x4) const
Definition: integrator.hpp:83
BindFirst(T const &func, double value)
Definition: integrator.hpp:78
double operator()(double x1, double x2, double x3) const
Definition: integrator.hpp:82
double operator()(double x) const
Definition: integrator.hpp:80
double operator()(double x1, double x2) const
Definition: integrator.hpp:81
Binds the second argument of a function or functor to a certain value.
Definition: integrator.hpp:98
double operator()(double x1, double x2) const
Definition: integrator.hpp:103
BindSecond(T const &func, double value)
Definition: integrator.hpp:100
double operator()(double x1, double x2, double x3) const
Definition: integrator.hpp:104
double operator()(double x1, double x2, double x3, double x4) const
Definition: integrator.hpp:105
double operator()(double x) const
Definition: integrator.hpp:102
Tag for an adaptive integration rule.
Definition: integrator.hpp:58
Gaussian integration rule.
Definition: integrator.hpp:67
Tag for the midpoint rule.
Definition: integrator.hpp:45
Tag for the simpson rule.
Definition: integrator.hpp:49
Tag for the trapezoidal rule.
Definition: integrator.hpp:47
A binder for reducing an n-ary function to an n-1-ary function by integration over one variable.
Definition: integrator.hpp:326
double operator()(double x) const
Definition: integrator.hpp:330
IntegrationBinder(T const &func, double a, double b)
Definition: integrator.hpp:328
Contains forward declarations and definition of small classes that must be defined at an early stage.
A logging facility providing fine-grained control over logging in ViennaSHE.
double integrate2D(double a1, double b1, double a2, double b2, T const &func2integrate, IntRuleTag)
Convenience overload for two-dimensional integration.
Definition: integrator.hpp:357
double integrate(T const &f, double a, double b, IntMidPointRule)
Integration of a function using the mid point rule.
Definition: integrator.hpp:118
The main ViennaSHE namespace. All functionality resides inside this namespace.
Definition: accessors.hpp:40
Defines the log keys used within the viennashe::math namespace.