Skip to content

Commit 24f94ba

Browse files
author
Paul Miles
authored
Merge pull request #6 from prmiles/calc_fd
Added FD calculator
2 parents 9ee29a1 + e08f2b8 commit 24f94ba

14 files changed

+607
-205
lines changed

pyfod/GaussLaguerre.py

+69-38
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@
77
"""
88

99
import numpy as np
10-
import sys
1110
from sympy.integrals.quadrature import gauss_gen_laguerre as sp_gauss_laguerre
1211
import sympy as sp
12+
from pyfod.utilities import check_function
1313

1414

1515
class GaussLaguerre:
1616

1717
def __init__(self, N=5, start=0.0, finish=1.0, alpha=0.0,
1818
f=None, extend_precision=True, n_digits=30):
1919
self.description = 'Gaussian-Laguerre Quadrature'
20+
self.start = start
21+
self.finish = finish
22+
self.alpha = alpha
23+
self.f = f
2024
if extend_precision is False:
2125
points, weights = np.polynomial.laguerre.laggauss(deg=N)
2226
self.points = 1 - np.exp(-points)
@@ -29,73 +33,100 @@ def __init__(self, N=5, start=0.0, finish=1.0, alpha=0.0,
2933
np.ones(shape=len(points))) - points.applyfunc(sp.exp)
3034
weights = sp.Array(weights)
3135
self.weights = weights
32-
self.start = start
33-
self.finish = finish
34-
self.alpha = alpha
35-
self.f = f
36+
self.initial_weights = weights.copy()
37+
self.update_weights(alpha=alpha)
3638

37-
def integrate(self, f=None, alpha=None):
38-
if alpha is None:
39-
alpha = self.alpha
40-
if f is None:
41-
f = self.f
42-
if f is None:
43-
sys.exit('No function defined... provide function f')
39+
def integrate(self, f=None):
40+
f = check_function(f, self.f)
41+
self.f = f
4442
# transform kernel
4543
span = self.finish - self.start
4644
# check if sympy
4745
if isinstance(self.points, sp.Array):
4846
evalpoints = self.points.applyfunc(
4947
lambda x: span*x + self.start)
5048
feval = evalpoints.applyfunc(f)
51-
coef = self.points.applyfunc(
52-
lambda x: span**(1-alpha)*(1-x)**(-alpha))
5349
s = 0
54-
for ii, (w, f, t) in enumerate(zip(self.weights, feval, coef)):
55-
s += w*f*t
50+
for ii, (w, f) in enumerate(zip(self.weights, feval)):
51+
s += w*f
5652
return s
5753
else:
58-
coef = span**(1-alpha)*(1-self.points)**(-alpha)
59-
s = (self.weights*(coef*f(span*self.points + self.start))).sum()
54+
s = (self.weights*(f(span*self.points + self.start))).sum()
6055
return s
6156

57+
def update_weights(self, alpha=None):
58+
if alpha is None:
59+
alpha = self.alpha
60+
self.alpha = alpha
61+
span = self.finish - self.start
62+
# check if sympy
63+
if isinstance(self.points, sp.Array):
64+
coef = self.points.applyfunc(
65+
lambda x: span**(1-alpha)*(1-x)**(-alpha))
66+
wtmp = []
67+
for ii, (c, w) in enumerate(zip(coef, self.initial_weights)):
68+
wtmp.append(c*w)
69+
self.weights = sp.Array(wtmp)
70+
else:
71+
coef = span**(1-alpha)*(1-self.points)**(-alpha)
72+
self.weights = self.initial_weights*coef
73+
6274

6375
if __name__ == '__main__': # pragma: no cover
6476

6577
n_digits = 50
66-
alpha = 0.9
6778
start = 0.0
6879
finish = 1.0
69-
dt = 1e-6
7080
N = 24
81+
'''
82+
Test normal precision
83+
'''
84+
# f(t) = exp(2t)
85+
86+
def fexpnp(x):
87+
return np.exp(2*x)
7188

7289
def fcosnp(x):
73-
return np.cos(2*x) + 3
90+
return np.cos(2*x)
7491

92+
# Test alpha = 0.0
93+
alpha = 0.0
7594
GLag = GaussLaguerre(N=N, start=start, finish=finish,
76-
f=fcosnp, alpha=0, extend_precision=False)
95+
f=fexpnp, alpha=alpha, extend_precision=False)
7796
F1 = GLag.integrate()
78-
print('Int(cos(2t)+3) = {} ({})'.format(F1, 3.4546))
97+
F2 = GLag.integrate(f=fcosnp)
98+
print('Int(exp(2t)/(1-t)^{}) = {} ({})'.format(alpha, F1, 3.19453))
99+
print('Int(cos(2t)/(1-t)^{}) = {} ({})'.format(alpha, F2, 0.454649))
100+
101+
'''
102+
Test extended precision
103+
'''
79104

80105
def fexp(x):
81106
return sp.exp(2*x)
82-
GLag = GaussLaguerre(N=N, start=start, finish=finish,
83-
f=fexp, alpha=alpha, n_digits=n_digits)
84-
F1 = GLag.integrate()
85-
GLag = GaussLaguerre(N=N, start=start, finish=finish-dt,
86-
f=fexp, alpha=alpha, n_digits=n_digits)
87-
F2 = GLag.integrate()
88-
print('D[f(t)=exp(2t)] = {} ({})'.format(
89-
(F1-F2)/(dt*sp.gamma(1-0.9)), 13.815))
90107

91108
def fcos(x):
92109
return sp.cos(2*x)
93110

111+
# Test alpha = 0.0
112+
alpha = 0.0
94113
GLag = GaussLaguerre(N=N, start=start, finish=finish,
95-
f=fcos, alpha=alpha, n_digits=n_digits)
96-
F1 = GLag.integrate()
97-
GLag = GaussLaguerre(N=N, start=start, finish=finish-dt,
98-
f=fcos, alpha=alpha, n_digits=n_digits)
99-
F2 = GLag.integrate()
100-
print('D[f(t)=cos(2t)] = {} ({})'.format(
101-
(F1-F2)/(dt*sp.gamma(1-0.9)), -1.779))
114+
alpha=alpha, n_digits=n_digits)
115+
F1 = GLag.integrate(f=fexp)
116+
F2 = GLag.integrate(f=fcos)
117+
print('Int(exp(2t)/(1-t)^{}) = {} ({})'.format(alpha, F1, 3.19453))
118+
print('Int(cos(2t)/(1-t)^{}) = {} ({})'.format(alpha, F2, 0.454649))
119+
# Test alpha = 0.1
120+
alpha = 0.1
121+
GLag.update_weights(alpha=alpha)
122+
F1 = GLag.integrate(f=fexp)
123+
F2 = GLag.integrate(f=fcos)
124+
print('Int(exp(2t)/(1-t)^{}) = {} ({})'.format(alpha, F1, 3.749))
125+
print('Int(cos(2t)/(1-t)^{}) = {} ({})'.format(alpha, F2, 0.457653))
126+
# Test alpha = 0.9
127+
alpha = 0.9
128+
GLag.update_weights(alpha=alpha)
129+
F1 = GLag.integrate(f=fexp)
130+
F2 = GLag.integrate(f=fcos)
131+
print('Int(exp(2t)/(1-t)^{}) = {} ({})'.format(alpha, F1, 65.2162))
132+
print('Int(cos(2t)/(1-t)^{}) = {} ({})'.format(alpha, F2, -2.52045))

pyfod/GaussLegendre.py

+65-20
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,41 @@
77
"""
88

99
import numpy as np
10+
from pyfod.utilities import check_alpha
11+
from pyfod.utilities import check_function, check_singularity
1012

1113

1214
class GaussLegendre:
1315

14-
def __init__(self, N=5, start=0.0, finish=1.0):
16+
def __init__(self, N=5, start=0.0, finish=1.0,
17+
alpha=0.0, f=None, singularity=None):
1518
self.description = 'Gaussian-Legendre Quadrature'
19+
check_alpha(alpha)
1620
h = (finish - start)/N
17-
self.points = self.gauss_points(N=N, h=h, start=start)
18-
self.weights = self.gauss_weights(N=N, h=h)
19-
20-
def integrate(self, f):
21+
self.alpha = alpha
22+
self.f = f
23+
self.finish = finish
24+
self.singularity = check_singularity(singularity, self.finish)
25+
self.points = self._gauss_points(N=N, h=h, start=start)
26+
self.weights = self._gauss_weights(N=N, h=h)
27+
self.initial_weights = self.weights.copy()
28+
self.update_weights(alpha=alpha)
29+
30+
def update_weights(self, alpha=None):
31+
if alpha is None:
32+
alpha = self.alpha
33+
self.alpha = alpha
34+
# update weights based on alpha
35+
self.weights = self.initial_weights*(
36+
self.singularity - self.points)**(-alpha)
37+
38+
def integrate(self, f=None):
39+
f = check_function(f, self.f)
40+
self.f = f
2141
return (self.weights*f(self.points)).sum()
2242

2343
@classmethod
24-
def base_gauss_points(cls):
44+
def _base_gauss_points(cls):
2545

2646
# base points
2747
gpts = np.zeros([4])
@@ -32,7 +52,7 @@ def base_gauss_points(cls):
3252
return gpts
3353

3454
@classmethod
35-
def base_gauss_weights(cls, h):
55+
def _base_gauss_weights(cls, h):
3656
# define the Gauss weights for a four point quadrature rule
3757
w = np.zeros([4])
3858
w[0] = 49*h/(12*(18 + np.sqrt(30)))
@@ -42,7 +62,7 @@ def base_gauss_weights(cls, h):
4262
return w
4363

4464
@classmethod
45-
def interval_gauss_points(cls, base_gpts, N, h, start):
65+
def _interval_gauss_points(cls, base_gpts, N, h, start):
4666
# determines the Gauss points for all N intervals.
4767
Gpts = np.zeros([4*N])
4868
for gct in range(N):
@@ -51,16 +71,16 @@ def interval_gauss_points(cls, base_gpts, N, h, start):
5171
+ base_gpts[ell]*h + start)
5272
return Gpts
5373

54-
def gauss_points(self, N, h, start):
74+
def _gauss_points(self, N, h, start):
5575
# base points
56-
gpts = self.base_gauss_points()
76+
gpts = self._base_gauss_points()
5777
# determines the Gauss points for all N intervals.
58-
Gpts = self.interval_gauss_points(gpts, N, h, start)
78+
Gpts = self._interval_gauss_points(gpts, N, h, start)
5979
return Gpts
6080

61-
def gauss_weights(self, N, h):
81+
def _gauss_weights(self, N, h):
6282
# determine the Gauss weights for a four point quadrature rule
63-
w = self.base_gauss_weights(h)
83+
w = self._base_gauss_weights(h)
6484
# copy the weights to form a vector for all N intervals
6585
weights = w.copy()
6686
for gct in range(N-1):
@@ -70,10 +90,35 @@ def gauss_weights(self, N, h):
7090

7191
if __name__ == '__main__': # pragma: no cover
7292

73-
GQ = GaussLegendre(N=10, start=1.0, finish=12.0)
74-
75-
def f(t):
76-
return np.cos(2*t) + 3
77-
78-
a = GQ.integrate(f)
79-
print('a = {}'.format(a))
93+
start = 0.0
94+
finish = 1.0
95+
N = 2400
96+
GQ = GaussLegendre(N=N, start=start, finish=finish)
97+
98+
def fexp(x):
99+
return np.exp(2*x)
100+
101+
def fcos(x):
102+
return np.cos(2*x)
103+
104+
# Test alpha = 0.0
105+
alpha = 0.0
106+
GLeg = GaussLegendre(N=N, start=start, finish=finish, alpha=alpha)
107+
F1 = GLeg.integrate(f=fexp)
108+
F2 = GLeg.integrate(f=fcos)
109+
print('Int(exp(2t)/(1-t)^{}) = {} ({})'.format(alpha, F1, 3.19453))
110+
print('Int(cos(2t)/(1-t)^{}) = {} ({})'.format(alpha, F2, 0.454649))
111+
# Test alpha = 0.1
112+
alpha = 0.1
113+
GLeg.update_weights(alpha=alpha)
114+
F1 = GLeg.integrate(f=fexp)
115+
F2 = GLeg.integrate(f=fcos)
116+
print('Int(exp(2t)/(1-t)^{}) = {} ({})'.format(alpha, F1, 3.749))
117+
print('Int(cos(2t)/(1-t)^{}) = {} ({})'.format(alpha, F2, 0.457653))
118+
# Test alpha = 0.9
119+
alpha = 0.9
120+
GLeg.update_weights(alpha=alpha)
121+
F1 = GLeg.integrate(f=fexp)
122+
F2 = GLeg.integrate(f=fcos)
123+
print('Int(exp(2t)/(1-t)^{}) = {} ({})'.format(alpha, F1, 65.2162))
124+
print('Int(cos(2t)/(1-t)^{}) = {} ({})'.format(alpha, F2, -2.52045))

pyfod/GaussLegendreRiemannSum.py

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
"""
4+
Created on Mon Mar 25 14:51:32 2019
5+
6+
@author: prmiles
7+
"""
8+
9+
from pyfod.GaussLegendre import GaussLegendre
10+
from pyfod.RiemannSum import RiemannSum
11+
from pyfod.utilities import check_function
12+
import numpy as np
13+
14+
15+
class GaussLegendreRiemannSum(object):
16+
17+
def __init__(self, NGQ=5, NRS=20, pGQ=0.9,
18+
start=0.0, finish=1.0, alpha=0.0, f=None):
19+
self.description = 'Gaussian Quadrature, Riemann-Sum'
20+
# setup GQ points/weights
21+
switch_time = (finish - start)*pGQ
22+
self.GQ = GaussLegendre(N=NGQ, start=start, finish=switch_time,
23+
alpha=alpha, singularity=finish, f=f)
24+
# setup RS points/weights
25+
self.RS = RiemannSum(N=NRS, start=switch_time,
26+
finish=finish, alpha=alpha, f=f)
27+
self.alpha = alpha
28+
self.pGQ = pGQ
29+
self.f = f
30+
31+
def integrate(self, f=None):
32+
f = check_function(f, self.f)
33+
self.f = f
34+
return self.GQ.integrate(f=f) + self.RS.integrate(f=f)
35+
36+
def update_weights(self, alpha=None):
37+
if alpha is None:
38+
alpha = self.alpha
39+
self.alpha = alpha
40+
self.GQ.update_weights(alpha=alpha)
41+
self.RS.update_weights(alpha=alpha)
42+
43+
44+
if __name__ == '__main__': # pragma: no cover
45+
46+
start = 0.0
47+
finish = 1.0
48+
NGQ = 100
49+
NRS = 2400
50+
pGQ = 0.95
51+
52+
def fexp(x):
53+
return np.exp(2*x)
54+
55+
def fcos(x):
56+
return np.cos(2*x)
57+
58+
# Test alpha = 0.0
59+
alpha = 0.0
60+
GRS = GaussLegendreRiemannSum(pGQ=pGQ, NGQ=NGQ, NRS=NRS, start=start,
61+
finish=finish)
62+
F1 = GRS.integrate(f=fexp)
63+
F2 = GRS.integrate(f=fcos)
64+
print('Int(exp(2t)/(1-t)^{}) = {} ({})'.format(alpha, F1, 3.19453))
65+
print('Int(cos(2t)/(1-t)^{}) = {} ({})'.format(alpha, F2, 0.454649))
66+
# Test alpha = 0.1
67+
alpha = 0.1
68+
GRS.update_weights(alpha=alpha)
69+
F1 = GRS.integrate(f=fexp)
70+
F2 = GRS.integrate(f=fcos)
71+
print('Int(exp(2t)/(1-t)^{}) = {} ({})'.format(alpha, F1, 3.749))
72+
print('Int(cos(2t)/(1-t)^{}) = {} ({})'.format(alpha, F2, 0.457653))
73+
# Test alpha = 0.9
74+
alpha = 0.9
75+
GRS.update_weights(alpha=alpha)
76+
F1 = GRS.integrate(f=fexp)
77+
F2 = GRS.integrate(f=fcos)
78+
print('Int(exp(2t)/(1-t)^{}) = {} ({})'.format(alpha, F1, 65.2162))
79+
print('Int(cos(2t)/(1-t)^{}) = {} ({})'.format(alpha, F2, -2.52045))

0 commit comments

Comments
 (0)