stocproc/tests/test_method_kle.py
2016-11-11 16:14:57 +01:00

285 lines
9.7 KiB
Python

import sys
import os
import numpy as np
from scipy.linalg import eig
try:
import matplotlib.pyplot as plt
except ImportError:
print("matplotlib not found -> any plotting will crash")
import pathlib
p = pathlib.PosixPath(os.path.abspath(__file__))
sys.path.insert(0, str(p.parent.parent))
from scipy.special import gamma
from scipy.integrate import quad
import stocproc as sp
from stocproc import tools
from stocproc import method_kle
from stocproc import stocproc_c
import logging
_S_ = 0.6
_GAMMA_S_PLUS_1 = gamma(_S_ + 1)
_WC_ = 2
def oac(tau):
"""ohmic bath correlation function"""
return (1 + 1j * (tau)) ** (-(_S_ + 1)) * _GAMMA_S_PLUS_1 / np.pi
def osd(omega):
return omega ** _S_ * np.exp(-omega)
def lac(t):
"""lorenzian bath correlation function"""
return np.exp(- np.abs(t) - 1j * _WC_ * t)
def lsd(w):
return 1 / (1 + (w - _WC_) ** 2)
def my_intp(ti, corr, w, t, u, lam):
return np.sum(corr(ti - t) * w * u) / lam
def test_weights(plot=False):
"""
here we check for the correct scaling of the various integration schemas
"""
def f(x):
return x/(1+x**2)
tm = 10
meth = [method_kle.get_mid_point_weights_times,
method_kle.get_trapezoidal_weights_times,
method_kle.get_simpson_weights_times,
method_kle.get_four_point_weights_times,
method_kle.get_gauss_legendre_weights_times,
method_kle.get_tanh_sinh_weights_times]
cols = ['r', 'b', 'g', 'm', 'c', 'lime']
errs = [5e-3, 6e-5, 2e-8, 7e-11, 5e-16, 8e-15]
I_exact = np.log(tm**2 + 1)/2
ng = 401
for i, _meth in enumerate(meth):
t, w = _meth(t_max=tm, num_grid_points=ng)
err = abs(I_exact - np.sum(w * f(t)))
print(_meth.__name__, err)
assert err < errs[i], "err={} >= {}".format(err, errs[i])
if plot:
for i, _meth in enumerate(meth):
xdata = []
ydata = []
for k in np.logspace(0, 2.5, 30):
ng = 4 * int(k) + 1
t, w = _meth(t_max=tm, num_grid_points=ng)
I = np.sum(w*f(t))
xdata.append(ng)
ydata.append(abs(I - I_exact))
plt.plot(xdata, ydata, marker='o', color=cols[i], label=_meth.__name__)
x = np.logspace(1, 3, 50)
plt.plot(x, 1 / x, color='0.5')
plt.plot(x, 6 / x ** 2, color='0.5')
plt.plot(x, 200 / x ** 4, color='0.5')
plt.plot(x, 200000 / x ** 6, color='0.5')
plt.legend(loc = 'lower left')
plt.xscale('log')
plt.yscale('log')
plt.grid()
plt.tight_layout()
plt.show()
def test_is_axis_equidistant():
t, w = method_kle.get_mid_point_weights_times(1, 51)
assert method_kle.is_axis_equidistant(t)
t, w = method_kle.get_trapezoidal_weights_times(1, 51)
assert method_kle.is_axis_equidistant(t)
t, w = method_kle.get_simpson_weights_times(1, 51)
assert method_kle.is_axis_equidistant(t)
t, w = method_kle.get_four_point_weights_times(1, 53)
assert method_kle.is_axis_equidistant(t)
t, w = method_kle.get_gauss_legendre_weights_times(1, 51)
assert not method_kle.is_axis_equidistant(t)
t, w = method_kle.get_tanh_sinh_weights_times(1, 51)
assert not method_kle.is_axis_equidistant(t)
def test_subdevide_axis():
t = [0, 1, 3]
tf1 = method_kle.subdevide_axis(t, ngfac=1)
assert np.max(np.abs(tf1 - np.asarray([0, 1, 3]))) < 1e-15
tf2 = method_kle.subdevide_axis(t, ngfac=2)
assert np.max(np.abs(tf2 - np.asarray([0, 0.5, 1, 2, 3]))) < 1e-15
tf3 = method_kle.subdevide_axis(t, ngfac=3)
assert np.max(np.abs(tf3 - np.asarray([0, 1 / 3, 2 / 3, 1, 1 + 2 / 3, 1 + 4 / 3, 3]))) < 1e-15
tf4 = method_kle.subdevide_axis(t, ngfac=4)
assert np.max(np.abs(tf4 - np.asarray([0, 0.25, 0.5, 0.75, 1, 1.5, 2, 2.5, 3]))) < 1e-15
def test_analytic_lorentzian_eigenfunctions():
tmax = 15
gamma = 2.3
w = 10.3
num = 10
corr = lambda x: np.exp(-gamma * np.abs(x) - 1j * w * x)
lef = tools.LorentzianEigenFunctions(tmax, gamma, w, num)
t = np.linspace(0, tmax, 55)
for idx in range(num):
u = lef.get_eigfunc(idx)
u_kernel_re = np.asarray([quad(lambda s: np.real(corr(ti - s) * u(s)), 0, tmax)[0] for ti in t])
u_kernel_im = np.asarray([quad(lambda s: np.imag(corr(ti - s) * u(s)), 0, tmax)[0] for ti in t])
u_kernel = u_kernel_re + 1j * u_kernel_im
c = 1 / lef.get_eigval(idx)
md = np.max(np.abs(u(t) - c * u_kernel))
assert md < 1e-6
norm = quad(lambda s: np.abs(u(s)) ** 2, 0, tmax)[0]
assert abs(1 - norm) < 1e-15
def test_solve_fredholm():
"""
here we compare the fredholm eigenvalue problem solver
(which maps the non hermetian eigenvalue problem to a hermetian one)
with a straigt forward non hermetian eigenvalue solver
"""
t_max = 15
corr = lac
meth = [method_kle.get_mid_point_weights_times,
method_kle.get_simpson_weights_times,
method_kle.get_four_point_weights_times]
ng = 41
for _meth in meth:
t, w = _meth(t_max, ng)
r = corr(t.reshape(-1, 1) - t.reshape(1, -1))
_eig_val, _eig_vec = method_kle.solve_hom_fredholm(r, w)
eval, evec = eig(r*w.reshape(1,-1))
max_imag = np.max(np.abs(np.imag(eval)))
assert max_imag < 1e-15 # make sure the evals are real
eval = np.real(eval)
idx_sort = np.argsort(eval)[::-1]
eval = eval[idx_sort]
evec = evec[:,idx_sort]
max_eval_diff = np.max(np.abs(eval - _eig_val))
assert max_eval_diff < 1e-13 # compare evals with fredholm evals
for i in range(ng-5):
phase = np.arctan2(np.imag(_eig_vec[0,i]), np.real(_eig_vec[0,i]))
_eig_vec[:, i] *= np.exp(-1j * phase)
norm = np.sqrt(np.sum(w*np.abs(_eig_vec[:, i]) ** 2))
assert abs(1-norm) < 1e-14 # fredholm should return vectors with integral norm 1
phase = np.arctan2(np.imag(evec[0, i]), np.real(evec[0, i]))
evec[:, i] *= np.exp(-1j * phase)
norm = np.sqrt(np.sum(w* np.abs(evec[:, i])**2))
evec[:, i] /= norm
diff_evec = np.max(np.abs(_eig_vec[:,i] - evec[:,i]))
assert diff_evec < 1e-10, "diff_evec {} = {} {}".format(i, diff_evec, _meth.__name__)
def test_cython_interpolation():
"""
"""
t_max = 15
corr = oac
meth = method_kle.get_four_point_weights_times
def my_intp(ti, corr, w, t, u, lam):
return np.sum(u * corr(ti - t) * w) / lam
k = 40
ng = 4*k+1
t, w = meth(t_max, ng)
r = corr(t.reshape(-1, 1) - t.reshape(1, -1))
_eig_val, _eig_vec = method_kle.solve_hom_fredholm(r, w)
method_kle.align_eig_vec(_eig_vec)
ngfac = 4
tfine = np.linspace(0, t_max, (ng-1)*ngfac+1)
bcf_n_plus = corr(tfine - tfine[0])
alpha_k = np.hstack((np.conj(bcf_n_plus[-1:0:-1]), bcf_n_plus))
for i in range(ng//2):
evec = _eig_vec[:,i]
sqrt_eval = np.sqrt(_eig_val[i])
ui_fine = np.asarray([my_intp(ti, corr, w, t, evec, sqrt_eval) for ti in tfine])
ui_fine2 = stocproc_c.eig_func_interp(delta_t_fac = ngfac,
time_axis = t,
alpha_k = alpha_k,
weights = w,
eigen_val = sqrt_eval,
eigen_vec = evec)
assert np.max(np.abs(ui_fine - ui_fine2)) < 2e-11
def test_solve_fredholm_reconstr_ac():
"""
here we see that the reconstruction quality is independent of the integration weights
differences occur when checking validity of the interpolated time continuous Fredholm equation
"""
_WC_ = 2
def lac(t):
return np.exp(- np.abs(t) - 1j*_WC_*t)
t_max = 10
tol = 2e-10
for ng in range(11,500,30):
t, w = sp.method_kle.get_mid_point_weights_times(t_max, ng)
r = lac(t.reshape(-1,1)-t.reshape(1,-1))
_eig_val, _eig_vec = sp.method_kle.solve_hom_fredholm(r, w)
_eig_vec_ast = np.conj(_eig_vec) # (N_gp, N_ev)
tmp = _eig_val.reshape(1, -1) * _eig_vec # (N_gp, N_ev)
recs_bcf = np.tensordot(tmp, _eig_vec_ast, axes=([1], [1]))
rd = np.max(np.abs(recs_bcf - r) / np.abs(r))
assert rd < tol, "rd={} >= {}".format(rd, tol)
t, w = sp.method_kle.get_simpson_weights_times(t_max, ng)
r = lac(t.reshape(-1, 1) - t.reshape(1, -1))
_eig_val, _eig_vec = sp.method_kle.solve_hom_fredholm(r, w)
_eig_vec_ast = np.conj(_eig_vec) # (N_gp, N_ev)
tmp = _eig_val.reshape(1, -1) * _eig_vec # (N_gp, N_ev)
recs_bcf = np.tensordot(tmp, _eig_vec_ast, axes=([1], [1]))
rd = np.max(np.abs(recs_bcf - r) / np.abs(r))
assert rd < tol, "rd={} >= {}".format(rd, tol)
def test_auto_ng():
corr = oac
t_max = 8
ng_fac = 1
meth = [method_kle.get_mid_point_weights_times,
method_kle.get_trapezoidal_weights_times,
method_kle.get_simpson_weights_times,
method_kle.get_four_point_weights_times]
#method_kle.get_gauss_legendre_weights_times]
#method_kle.get_tanh_sinh_weights_times]
for _meth in meth:
ui, t = method_kle.auto_ng(corr, t_max, ngfac=ng_fac, meth = _meth)
print(_meth.__name__, ui.shape)
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
test_weights(plot=False)
test_is_axis_equidistant()
test_subdevide_axis()
test_analytic_lorentzian_eigenfunctions()
test_solve_fredholm()
test_cython_interpolation()
test_solve_fredholm()
test_solve_fredholm_reconstr_ac()
test_auto_ng()
pass