testing, cleaning and docs

This commit is contained in:
Richard Hartmann 2016-11-07 18:44:51 +01:00
parent 9f6bdbbc62
commit 8c117e4468
7 changed files with 398 additions and 420 deletions

View file

@ -1,4 +1,4 @@
StocProc_FFT_tol
----------------
StocProc_FFT
------------
.. autoclass:: stocproc.stocproc.StocProc_FFT_tol
.. autoclass:: stocproc.stocproc.StocProc_FFT

View file

@ -1,9 +1,18 @@
StocProc_KLE_tol
----------------
StocProc_KLE
------------
.. py:currentmodule:: stocproc
.. autoclass:: StocProc_KLE_tol
.. autoclass:: StocProc_KLE
:members:
:inherited-members:
:undoc-members:
.. py:currentmodule:: stocproc.method_kle
.. autofunction:: stocproc.method_kle.solve_hom_fredholm
.. autofunction:: stocproc.method_kle.get_mid_point_weights_times
.. autofunction:: stocproc.method_kle.get_trapezoidal_weights_times
.. autofunction:: stocproc.method_kle.get_simpson_weights_times
.. autofunction:: stocproc.method_kle.get_four_point_weights_times
.. autofunction:: stocproc.method_kle.get_gauss_legendre_weights_times
.. autofunction:: stocproc.method_kle.get_tanh_sinh_weights_times

View file

@ -56,6 +56,5 @@ import sys
if sys.version_info.major < 3:
raise SystemError("no support for Python 2")
from .stocproc import StocProc_FFT_tol
from .stocproc import StocProc_FFT
from .stocproc import StocProc_KLE
from .stocproc import StocProc_KLE_tol

View file

@ -10,13 +10,13 @@ from . import tools
import logging
log = logging.getLogger(__name__)
def solve_hom_fredholm(r, w, eig_val_min=None):
def solve_hom_fredholm(r, w):
r"""Solves the discrete homogeneous Fredholm equation of the second kind
.. math:: \int_0^{t_\mathrm{max}} \mathrm{d}s R(t-s) u(s) = \lambda u(t)
Quadrature approximation of the integral gives a discrete representation of the
basis functions and leads to a regular eigenvalue problem.
Quadrature approximation of the integral gives a discrete representation
which leads to a regular eigenvalue problem.
.. math:: \sum_i w_i R(t_j-s_i) u(s_i) = \lambda u(t_j) \equiv \mathrm{diag(w_i)} \cdot R \cdot u = \lambda u
@ -27,18 +27,31 @@ def solve_hom_fredholm(r, w, eig_val_min=None):
.. math:: D \cdot R \cdot D \cdot D \cdot u = \lambda D \cdot u \equiv \tilde R \tilde u = \lambda \tilde u
where :math:`\tilde R` is hermitian and :math:`u = D^{-1}\tilde u`
Setting :math:`t_i = s_i` and due to the definition of the correlation function the
matrix :math:`r_{ij} = R(t_i, s_j)` is hermitian.
where :math:`\tilde R` is hermitian and :math:`u = D^{-1}\tilde u`.
:param r: correlation matrix :math:`R(t_j-s_i)`
:param w: integrations weights :math:`w_i`
(they have to correspond to the discrete time :math:`t_i`)
:param eig_val_min: discards all eigenvalues and eigenvectos with
:math:`\lambda_i < \mathtt{eig\_val\_min} / \mathrm{max}(\lambda)`
:return: eigenvalues, eigenvectos (eigenvectos are stored in the normal numpy fashion, ordered in decreasing order)
.. seealso::
There are various convenient functions to calculate the integration weights and times
to approximate the integral over the interval [0, t_max] using ng points.
:py:func:`get_mid_point_weights_times`,
:py:func:`get_trapezoidal_weights_times`,
:py:func:`get_simpson_weights_times`,
:py:func:`get_four_point_weights_times`,
:py:func:`get_gauss_legendre_weights_times`,
:py:func:`get_tanh_sinh_weights_times`
.. note::
It has been noticed that the performance of the various weights depends on the auto correlation
function. As default one should use the simpson weights. 'four point', 'gauss legendre' and 'tanh sinh'
might perform better for auto correlation function that decay slowly. Their advantage becomes evident
for a large numbers of grid points only. So if one cares about relative differences below 1e-4
the more sophisticated weights are suitable.
"""
t0 = time.time()
# weighted matrix r due to quadrature weights
@ -47,16 +60,10 @@ def solve_hom_fredholm(r, w, eig_val_min=None):
r = w_sqrt.reshape(n,1) * r * w_sqrt.reshape(1,n)
eig_val, eig_vec = scipy_eigh(r, overwrite_a=True) # eig_vals in ascending
if eig_val_min is None:
min_idx = 0
else:
min_idx = sum(eig_val < eig_val_min)
eig_val = eig_val[min_idx:][::-1]
eig_vec = eig_vec[:, min_idx:][:, ::-1]
log.debug("use {} / {} eigenfunctions".format(len(eig_val), len(w)))
eig_val = eig_val[::-1]
eig_vec = eig_vec[:, ::-1]
eig_vec = np.reshape(1/w_sqrt, (n,1)) * eig_vec
log.debug("discrete fredholm equation of size {} solved [{:.2e}]".format(n, time.time() - t0))
log.debug("discrete fredholm equation of size {} solved [{:.2e}s]".format(n, time.time() - t0))
return eig_val, eig_vec
def align_eig_vec(eig_vec):
@ -89,72 +96,72 @@ def _calc_corr_matrix(s, bcf):
r[:, i] = bcf_n[idx:idx + n_]
return r
def opt_fredholm(kernel, lam, t, u, meth, ntimes):
def fopt(x, p, k):
n = len(x)//2 + 1
lam = x[0]
u = x[1:n] + 1j*x[n:]
return np.log10((np.sum(np.abs(k.dot(u) - lam * u) ** p)) ** (1 / p))
for i in range(ntimes):
print("iter {}/{} lam {}".format(i+1, ntimes, lam))
u_intp = tools.ComplexInterpolatedUnivariateSpline(t, u)
ng = 2*(len(t)-1)+1
t, w = meth(t[-1], ng)
u_new = u_intp(t)
k_new = kernel(t.reshape(-1,1)-t.reshape(1,-1))*w.reshape(-1,1)
p = 5
r = minimize(fopt, x0=np.hstack((lam, u_new.real, u_new.imag)), args=(p, k_new), method='CG')
x = r.x
n = len(x) // 2 + 1
lam = x[0]
u = x[1:n] + 1j * x[n:]
print("func val {} ng {}".format(r.fun, ng))
return lam, u, t
def get_mid_point_weights_times(t_max, num_grid_points):
r"""Returns the time gridpoints and wiehgts for numeric integration via **mid point rule**.
The idea is to use :math:`N_\mathrm{GP}` time grid points located in the middle
each of the :math:`N_\mathrm{GP}` equally distributed subintervals of :math:`[0, t_\mathrm{max}]`.
.. math:: t_i = \left(i + \frac{1}{2}\right)\frac{t_\mathrm{max}}{N_\mathrm{GP}} \qquad i = 0,1, ... N_\mathrm{GP} - 1
r"""Returns the weights and grid points for numeric integration via **mid point rule**.
The corresponding trivial weights for integration are
.. math:: w_i = \Delta t = \frac{t_\mathrm{max}}{N_\mathrm{GP}} \qquad i = 0,1, ... N_\mathrm{GP} - 1
:param t_max: end of the interval for the time grid :math:`[0,t_\mathrm{max}]`
(note: this would corespond to an integration from :math:`0-\Delta t / 2`
to :math:`t_\mathrm{max}+\Delta t /2`)
:param num_grid_points: number of
:param num_grid_points: number of grid points N
:return: location of the grid points, corresponding weights
Because this function is intended to provide the weights to be used in :py:func:`solve_hom_fredholm`
is stretches the homogeneous weights over the grid points starting from 0 up to t_max, so the
term min_point is somewhat miss leading. This is possible because we want to simulate
stationary stochastic processes which allows :math:`\alpha(t_i+\Delta - (s_j+\Delta)) = \alpha(t_i-s_j)`.
The N grid points are located at
.. math:: t_i = i \frac{t_\mathrm{max}}{N-1} \qquad i = 0,1, ... N - 1
and the corresponding weights are
.. math:: w_i = \Delta t = \frac{t_\mathrm{max}}{N-1} \qquad i = 0,1, ... N - 1
"""
# generate mid points
t, delta_t = np.linspace(0, t_max, num_grid_points, retstep = True)
# equal weights for grid points
w = np.ones(num_grid_points)*delta_t
return t, w
def get_trapezoidal_weights_times(t_max, num_grid_points):
# generate mid points
r"""Returns the weights and grid points for numeric integration via **trapezoidal rule**.
:param t_max: end of the interval for the time grid :math:`[0,t_\mathrm{max}]`
:param num_grid_points: number of grid points N
:return: location of the grid points, corresponding weights
The N grid points are located at
.. math:: t_i = i \frac{t_\mathrm{max}}{N-1} \qquad i = 0,1, ... N - 1
and the corresponding weights are
.. math:: w_0 = w_{N-1} = \Delta t /2 \qquad w_i = \Delta t \quad 0 < i < N - 1
\qquad \Delta t = \frac{t_\mathrm{max}}{N-1}
"""
t, delta_t = np.linspace(0, t_max, num_grid_points, retstep = True)
# equal weights for grid points
w = np.ones(num_grid_points)*delta_t
w[0] /= 2
w[-1] /= 2
return t, w
def get_simpson_weights_times(t_max, num_grid_points):
r"""Returns the weights and grid points for numeric integration via **simpson rule**.
:param t_max: end of the interval for the time grid :math:`[0,t_\mathrm{max}]`
:param num_grid_points: number of grid points N (needs to be odd)
:return: location of the grid points, corresponding weights
The N grid points are located at
.. math:: t_i = i \frac{t_\mathrm{max}}{N-1} \qquad i = 0,1, ... N - 1
and the corresponding weights are
.. math:: w_0 = w_{N-1} = 1/3 \Delta t \qquad w_{2i} = 2/3 \Delta t \quad 0 < i < (N - 1)/2
.. math:: \qquad w_{2i+1} = 4/3 \Delta t \quad 0 \leq i < (N - 1)/2 \qquad \Delta t = \frac{t_\mathrm{max}}{N-1}
"""
if num_grid_points % 2 != 1:
raise RuntimeError("simpson weights needs grid points ng such that ng = 2*k+1, but git ng={}".format(num_grid_points))
# generate mid points
t, delta_t = np.linspace(0, t_max, num_grid_points, retstep = True)
# equal weights for grid points
w = np.empty(num_grid_points, dtype=np.float64)
w[0::2] = 2/3*delta_t
w[1::2] = 4/3*delta_t
@ -163,30 +170,76 @@ def get_simpson_weights_times(t_max, num_grid_points):
return t, w
def get_four_point_weights_times(t_max, num_grid_points):
r"""Returns the weights and grid points for numeric integration via **four-point Newton-Cotes rule**.
:param t_max: end of the interval for the time grid :math:`[0,t_\mathrm{max}]`
:param num_grid_points: number of grid points N (needs to be (4k+1) where k is an integer greater 0)
:return: location of the grid points, corresponding weights
The N grid points are located at
.. math:: t_i = i \frac{t_\mathrm{max}}{N-1} \qquad i = 0,1, ... N - 1
and the corresponding weights are
.. math:: w_0 = w_{N-1} = 28/90 \Delta t
.. math:: w_{4i+1} = w_{4i+3} = 128/90 \Delta t \quad 0 \leq i < (N - 1)/4
.. math:: w_{4i+2} = 48/90 \Delta t \quad 0 \leq i < (N - 1)/4
.. math:: w_{4i} = 56/90 \Delta t \quad 0 < i < (N - 1)/4
.. math:: \Delta t = \frac{t_\mathrm{max}}{N-1}
"""
if num_grid_points % 4 != 1:
raise RuntimeError("four point weights needs grid points ng such that ng = 4*k+1, but git ng={}".format(num_grid_points))
# generate mid points
t, delta_t = np.linspace(0, t_max, num_grid_points, retstep = True)
# equal weights for grid points
w = np.empty(num_grid_points, dtype=np.float64)
w[0::4] = 2 * 7 * 4 / 90 * delta_t
w[1::4] = 1 * 32 * 4 / 90 * delta_t
w[2::4] = 1 * 12 * 4 / 90 * delta_t
w[3::4] = 1 * 32 * 4 / 90 * delta_t
w[0] = 1 * 7 * 4 / 90 * delta_t
w[-1] = 1 * 7 * 4 / 90 * delta_t
w[0::4] = 56 / 90 * delta_t
w[1::4] = 128 / 90 * delta_t
w[2::4] = 48 / 90 * delta_t
w[3::4] = 128 / 90 * delta_t
w[0] = 28 / 90 * delta_t
w[-1] = 28 / 90 * delta_t
return t, w
def get_gauss_legendre_weights_times(t_max, num_grid_points):
"""Returns the weights and grid points for numeric integration via **Gauss integration**
by expanding the function in terms of Legendre Polynomials.
:param t_max: end of the interval for the time grid :math:`[0,t_\mathrm{max}]`
:param num_grid_points: number of grid points N
:return: location of the grid points, corresponding weights
"""
return gquad.gauss_nodes_weights_legendre(n = num_grid_points, low=0, high=t_max)
def get_sinh_tanh_weights_times(t_max, num_grid_points):
"""
inspired by Tanh-Sinh High-Precision Quadrature - David H. Bailey
def get_tanh_sinh_weights_times(t_max, num_grid_points):
r"""Returns the weights and grid points for numeric integration via **Tanh-Sinh integration**. The idea is to
transform the integral over a finite interval :math:`x \in [-1, 1]` via the variable transformation
.. math :: x = \tanh(\pi/2 \sinh(t))
to a integral over the entire real axis :math:`t \in [-\infty,\infty]` but where the new
transformed integrand decay rapidly such that a simply midpoint rule performs very well.
inspired by 'Tanh-Sinh High-Precision Quadrature - David H. Bailey'
:param t_max: end of the interval for the time grid :math:`[0,t_\mathrm{max}]`
:param num_grid_points: number of grid points N (needs to be odd)
:return: location of the grid points, corresponding weights
For a fixed small parameter h the location of the grid points read
.. math :: x_i = \tanh(\pi/2 \sinh(ih)
with corresponding weights
.. math :: w_i = \frac{\pi/2 \cosh(ih)}{\cosh^2(\pi/2 \sinh(ih))}
where i can be any integer. For a given number of grid points N, h is chosen such that
:math:`w_{(N-1)/2} < 10^{-14}` which implies odd N. With that particular h :math:`x_i` and
:math:`w_i` are calculated for :math:`-(N-1)/2 \leq i \leq (N-1)/2`. Afterwards the :math:`x_i` are linearly
scaled such that :math:`x_{-(N-1)/2} = 0` and :math:`x_{(N-1)/2} = t_\mathrm{max}`.
"""
def get_h_of_N(N):
"""returns the stepsize h for sinh tanh quad for a given number of points N
r"""returns the stepsize h for sinh tanh quad for a given number of points N
such that the smallest weights are about 1e-14
"""
a = 16.12087683080651
@ -210,18 +263,6 @@ def get_sinh_tanh_weights_times(t_max, num_grid_points):
t = np.hstack((y_plus[-1:0:-1], (2-y_plus)))*t_max/2
return t, w
_WC_ = 2
_S_ = 0.6
_GAMMA_S_PLUS_1 = gamma(_S_ + 1)
def lac(t):
"""lorenzian bath correlation function"""
return np.exp(- np.abs(t) - 1j * _WC_ * t)
def oac(t):
"""ohmic bath correlation function"""
return (1 + 1j*(t))**(-(_S_+1)) * _GAMMA_S_PLUS_1 / np.pi
def get_rel_diff(corr, t_max, ng, weights_times, ng_fac):
t, w = weights_times(t_max, ng)
r = corr(t.reshape(-1, 1) - t.reshape(1, -1))
@ -252,14 +293,69 @@ def get_rel_diff(corr, t_max, ng, weights_times, ng_fac):
return tfine, rd
def auto_ng(corr, t_max, ngfac=2, meth=get_mid_point_weights_times, tol=1e-3, diff_method='full', dm_random_samples=10**4):
r"""increase the number of gridpoints until the desired accuracy is met
This function increases the number of grid points of the discrete Fredholm equation exponentially until
a given accuracy is met. The accuracy is determined from the deviation of the approximated
auto correlation of the Karhunen-Loève expansion from the given reference auto correlation.
.. math::
\Delta(n) = \max_{t,s \in [0,t_\mathrm{max}]}\left( \Big | \alpha(t-s) - \sum_{i=1}^n \lambda_i u_i(t) u_i^\ast(s) \Big | \right )
The procedure works as follows:
1) Solve the discrete Fredholm equation on a grid with ng points.
This gives ng eigenvalues/vectors where each ng-dimensional vector approximates the continuous eigenfunction.
(:math:`t, u_i(t) \leftrightarrow t_k, u_{ik}` where the :math:`t_k` depend on the integration weights
method)
2) Approximate the eigenfunction on a finer, equidistant grid
(:math:`ng_\mathrm{fine} = ng_\mathrm{fac}(ng-1)+1`) using
.. math::
u_i(t) = \frac{1}{\lambda_i} \int_0^{t_\mathrm{max}} \mathrm{d}s \; \alpha(t-s) u_i(s)
\approx \frac{1}{\lambda_i} \sum_k w_k \alpha(t-s_k) u_{ik}
According to the Numerical Recipes [1] this interpolation should perform better that simple
spline interpolation. However it turns that this is not the case in general (e.g. for exponential
auto correlation functions the spline interpolation performs better). For that reason it might be
usefull to set ngfac to 1 which will skip the integral interpolation
3) Use the eigenfunction on the fine grid to setup a cubic spline interpolation.
4) Use the spline interpolation to estimate the deviation :math:`\Delta(n)`. When using diff_method = 'full'
the maximization is performed over all :math:`t'_i, s'_j` where :math:`t'_i = (t_i + t_{i+1})/2` and
:math:`s'_i = (s_i + s_{i+1})/2` with :math:`i,j = 0, \, ...\, , ng_\mathrm{fine}-2`. It is expected that
the interpolation error is maximal when beeing in between the reference points.
5) Now calculate the deviation :math:`\Delta(n)` for sequential n starting at n=0. Stop if
:math:`\Delta(n) < tol`. If the deviation does not drop below tol for all :math:`0 \leq n < ng-1` increase
ng as follows :math:`ng = 2*ng-1 and start over at 1). (This update schema for ng asured that ng is odd
which is needed for the 'simpson' and 'fourpoint' integration weights)
:param corr: the auto correlation function
:param t_max: specifies the interval [0, t_max] for which the stochastic process can be evaluated
:param ngfac: specifies the fine grid to use for the spline interpolation, the intermediate points are
calculated using integral interpolation
:param meth: the method for calculation integration weights and times, a callable or one of the following strings
'midpoint' ('midp'), 'trapezoidal' ('trapz'), 'simpson' ('simp'), 'fourpoint' ('fp'),
'gauss_legendre' ('gl'), 'tanh_sinh' ('ts')
:param tol: defines the success criterion max(abs(corr_exact - corr_reconstr)) < tol
:param diff_method: either 'full' or 'random', determines the points where the above success criterion is evaluated,
'full': full grid in between the fine grid, such that the spline interpolation error is expected to be maximal
'random': pick a fixed number of random times t and s within the interval [0, t_max]
:param dm_random_samples: the number of random times used for diff_method 'random'
:return: an array containing the necessary eigenfunctions of the Karhunen-Loève expansion for sampling the
stochastic processes
[1] Press, W.H., Teukolsky, S.A., Vetterling, W.T., Flannery, B.P.,
2007. Numerical Recipes 3rd Edition: The Art of Scientific Computing,
Auflage: 3. ed. Cambridge University Press, Cambridge, UK ; New York. (pp. 990)
"""
time_start = time.time()
if diff_method == 'full':
pass
elif diff_method == 'random':
t_rand = np.random.rand(dm_random_samples) * t_max
s_rand = np.random.rand(dm_random_samples) * t_max
alpha_ref = corr(t_rand - s_rand)
diff = -alpha_ref
else:
raise ValueError("unknown diff_method '{}', use 'full' or 'random'".format(diff_method))
alpha_0 = np.abs(corr(0))
@ -271,77 +367,107 @@ def auto_ng(corr, t_max, ngfac=2, meth=get_mid_point_weights_times, tol=1e-3, di
time_spline = 0
time_calc_diff = 0
if isinstance(meth, str):
meth = str_meth_to_meth(meth)
k = 4
while True:
k += 1
ng = 2 ** k + 1
log.debug("check {} grid points".format(ng))
log.info("check {} grid points".format(ng))
t, w = meth(t_max, ng)
t0 = time.time()
r = _calc_corr_matrix(t, corr)
t0 = time.time() # efficient way to construct the
r = _calc_corr_matrix(t, corr) # auto correlation matrix r
time_calc_ac += (time.time() - t0)
t0 = time.time()
_eig_val, _eig_vec = solve_hom_fredholm(r, w)
t0 = time.time() # solve the dicrete fredholm equation
_eig_val, _eig_vec = solve_hom_fredholm(r, w) # using integration weights w
time_fredholm += (time.time() - t0)
tfine, dt = np.linspace(0, t_max, (ng - 1) * ngfac + 1, retstep=True)
tsfine = tfine[:-1] + dt/2
tfine, dt = np.linspace(0, t_max, (ng - 1) * ngfac + 1, retstep=True) # setup fine
tsfine = tfine[:-1] + dt/2 # and super fine time grid
t0 = time.time()
alpha_k = _calc_corr_min_t_plus_t(tfine, corr)
time_calc_ac += (time.time() - t0)
t0 = time.time() # efficient way to calculate the auto correlation
alpha_k = _calc_corr_min_t_plus_t(tfine, corr) # from -tmax untill tmax on the fine grid
time_calc_ac += (time.time() - t0) # needed for integral interpolation
if diff_method == 'full':
ng_sfine = len(tsfine)
alpha_ref = np.empty(shape=(ng_sfine, ng_sfine), dtype=np.complex128)
for i in range(ng_sfine):
idx = ng_sfine - 1 - i
idx = ng_sfine - i
alpha_ref[:, i] = alpha_k[idx:idx + ng_sfine] # note we can use alpha_k as
# alpha(ti+dt/2 - (tj+dt/2)) = alpha(ti - tj)
diff = -alpha_ref
old_md = np.inf
ui_fine_all = []
sqrt_lambda_ui_fine_all = []
for i in range(ng):
evec = _eig_vec[:, i]
sqrt_eval = np.sqrt(_eig_val[i])
if ngfac != 1:
t0 = time.time()
ui_fine = 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)
# when using sqrt_lambda instead of lambda we get sqrt_lamda time u
# which is the quantity needed for the stochastic process
# generation
sqrt_lambda_ui_fine = 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)
time_integr_intp += (time.time() - t0)
else:
ui_fine = evec
ui_fine_all.append(ui_fine)
sqrt_lambda_ui_fine = evec*sqrt_eval
sqrt_lambda_ui_fine_all.append(sqrt_lambda_ui_fine)
# setup cubic spline interpolator
t0 = time.time()
ui_spl = tools.ComplexInterpolatedUnivariateSpline(tfine, ui_fine)
sqrt_lambda_ui_spl = tools.ComplexInterpolatedUnivariateSpline(tfine, sqrt_lambda_ui_fine)
time_spline += (time.time() - t0)
# calculate the max deviation
t0 = time.time()
if diff_method == 'random':
ui_t = ui_spl(t_rand)
ui_s = ui_spl(s_rand)
ui_t = sqrt_lambda_ui_spl(t_rand)
ui_s = sqrt_lambda_ui_spl(s_rand)
diff += ui_t * np.conj(ui_s)
elif diff_method == 'full':
ui_super_fine = ui_spl(tsfine)
ui_super_fine = sqrt_lambda_ui_spl(tsfine)
diff += ui_super_fine.reshape(-1, 1) * np.conj(ui_super_fine.reshape(1, -1))
md = np.max(np.abs(diff)) / alpha_0
time_calc_diff += (time.time() - t0)
log.debug("num evec {} -> max diff {:.3e}".format(i+1, md))
if old_md < md:
log.debug("max diff increased -> break, use higher ng")
break
old_md = md
#if old_md < md:
# log.info("max diff increased -> break, use higher ng")
# break
#old_md = md
if md < tol:
time_total = time_calc_diff + time_spline + time_integr_intp + time_calc_ac + time_fredholm
log.debug("calc_ac {:.3%}, fredholm {:.3%}, integr_intp {:.3%}, spline {:.3%}, calc_diff {:.3%}".format(
time_calc_ac/time_total, time_fredholm/time_total, time_integr_intp/time_total,
time_spline/time_total, time_calc_diff/time_total))
log.debug("auto ng SUCCESSFUL max diff {:.3e} < tol {:.3e} ng {} num evec {}".format(md, tol, ng, i+1))
return np.asarray(ui_fine_all)
time_overall = time.time() - time_start
time_rest = time_overall - time_total
log.info("calc_ac {:.3%}, fredholm {:.3%}, integr_intp {:.3%}, spline {:.3%}, calc_diff {:.3%}, rest {:.3%}".format(
time_calc_ac/time_overall, time_fredholm/time_overall, time_integr_intp/time_overall,
time_spline/time_overall, time_calc_diff/time_overall, time_rest/time_overall))
log.info("auto ng SUCCESSFUL max diff {:.3e} < tol {:.3e} ng {} num evec {}".format(md, tol, ng, i+1))
return np.asarray(sqrt_lambda_ui_fine_all)
log.info("ng {} yields md {:.3e}".format(ng, md))
def str_meth_to_meth(meth):
if (meth == 'midpoint') or (meth == 'midp'):
return get_mid_point_weights_times
elif (meth == 'trapezoidal') or (meth == 'trapz'):
return get_trapezoidal_weights_times
elif (meth == 'simpson') or (meth == 'simp'):
return get_simpson_weights_times
elif (meth == 'fourpoint') or (meth == 'fp'):
return get_four_point_weights_times
elif (meth == 'gauss_legendre') or (meth == 'gl'):
return get_gauss_legendre_weights_times
elif (meth == 'tanh_sinh') or (meth == 'ts'):
return get_tanh_sinh_weights_times
else:
raise ValueError("unknown method to get integration weights '{}'".format(meth))

View file

@ -24,6 +24,7 @@ associated spectral density. The number scales linear with the time interval of
sufficient accuracy many of these values are required. As the generation of a new process is based on
a Fast-Fouried-Transform over these values, this part is comparably lengthy.
"""
import abc
import numpy as np
import time
@ -35,7 +36,7 @@ from .tools import ComplexInterpolatedUnivariateSpline
import logging
log = logging.getLogger(__name__)
class _absStocProc(object):
class _absStocProc(abc.ABC):
r"""
Abstract base class to stochastic process interface
@ -49,20 +50,18 @@ class _absStocProc(object):
"""
def __init__(self, t_max, num_grid_points, seed=None, k=3):
def __init__(self, t_max, num_grid_points, seed=None):
r"""
:param t_max: specify time axis as [0, t_max]
:param num_grid_points: number of equidistant times on that axis
:param seed: if not ``None`` set seed to ``seed``
:param verbose: 0: no output, 1: informational output, 2: (eventually some) debug info
:param k: polynomial degree used for spline interpolation
"""
self.t_max = t_max
self.num_grid_points = num_grid_points
self.t = np.linspace(0, t_max, num_grid_points)
self._z = None
self._interpolator = None
self._k = k
self._seed = seed
if seed is not None:
np.random.seed(seed)
@ -83,10 +82,11 @@ class _absStocProc(object):
else:
if self._interpolator is None:
t0 = time.time()
self._interpolator = ComplexInterpolatedUnivariateSpline(self.t, self._z, k=self._k)
self._interpolator = ComplexInterpolatedUnivariateSpline(self.t, self._z, k=3)
log.debug("created interpolator [{:.2e}s]".format(time.time() - t0))
return self._interpolator(t)
@abc.abstractmethod
def _calc_z(self, y):
r"""
maps the normal distributed complex valued random variables y to the stochastic process
@ -94,7 +94,8 @@ class _absStocProc(object):
:return: the stochastic process, array of complex numbers
"""
pass
@abc.abstractmethod
def get_num_y(self):
r"""
:return: number of complex random variables needed to calculate the stochastic process
@ -136,127 +137,8 @@ class _absStocProc(object):
self._z = self._calc_z(y)
log.debug("proc_cnt:{} new process generated [{:.2e}s]".format(self._proc_cnt, time.time() - t0))
METHOD = 'midp'
class StocProc_KLE(_absStocProc):
r"""
class to simulate stochastic processes using KLE method
- Solve fredholm equation on grid with ``ng_fredholm nodes`` (trapezoidal_weights).
If case ``ng_fredholm`` is ``None`` set ``ng_fredholm = num_grid_points``. In general it should
hold ``ng_fredholm < num_grid_points`` and ``num_grid_points = 10*ng_fredholm`` might be a good ratio.
- Calculate discrete stochastic process (using interpolation solution of fredholm equation) with num_grid_points nodes
- invoke spline interpolator when calling
"""
def __init__(self, r_tau, t_max, ng_fredholm, ng_fac=4, seed=None, sig_min=1e-5, k=3, align_eig_vec=False):
r"""
:param r_tau: auto correlation function of the stochastic process
:param t_max: specify time axis as [0, t_max]
:param seed: if not ``None`` set seed to ``seed``
:param sig_min: eigenvalue threshold (see KLE method to generate stochastic processes)
:param verbose: 0: no output, 1: informational output, 2: (eventually some) debug info
:param k: polynomial degree used for spline interpolation
"""
# this lengthy part will be skipped when init class from dump, as _A and alpha_k will be stored
t0 = time.time()
if METHOD == 'midp':
t, w = method_kle.get_mid_point_weights_times(t_max, ng_fredholm)
elif METHOD == 'simp':
t, w = method_kle.get_simpson_weights_times(t_max, ng_fredholm)
r = self._calc_corr_matrix(t, r_tau)
_eig_val, _eig_vec = method_kle.solve_hom_fredholm(r, w, sig_min ** 2)
if align_eig_vec:
for i in range(_eig_vec.shape[1]):
s = np.sum(_eig_vec[:, i])
phase = np.exp(1j * np.arctan2(np.real(s), np.imag(s)))
_eig_vec[:, i] /= phase
_sqrt_eig_val = np.sqrt(_eig_val)
_A = w.reshape(-1, 1) * _eig_vec / _sqrt_eig_val.reshape(1, -1)
ng_fine = ng_fac * (ng_fredholm - 1) + 1
alpha_k = self._calc_corr_min_t_plus_t(s=np.linspace(0, t_max, ng_fine), bcf=r_tau)
log.debug("new KLE StocProc class prepared [{:.2e}]".format(time.time() - t0))
data = (_A, alpha_k, seed, k, t_max, ng_fac)
self.__setstate__(data)
# needed for getkey / getstate
self.key = (r_tau, t_max, ng_fredholm, ng_fac, sig_min, align_eig_vec)
# save these guys as they are needed to estimate the autocorrelation
self._s = t
self._w = w
self._eig_val = _eig_val
self._eig_vec = _eig_vec
def _getkey(self):
return self.__class__.__name__, self.key
def __getstate__(self):
return self._A, self.alpha_k, self._seed, self._k, self.t_max, self.ng_fac
def __setstate__(self, state):
self._A, self.alpha_k, seed, k, t_max, self.ng_fac = state
if self.ng_fac == 1:
self.kle_interp = False
else:
self.kle_interp = True
self._one_over_sqrt_2 = 1 / np.sqrt(2)
num_gp, self.num_y = self._A.shape
ng_fine = self.ng_fac * (num_gp - 1) + 1
super().__init__(t_max=t_max, num_grid_points=ng_fine, seed=seed, k=k)
@staticmethod
def _calc_corr_min_t_plus_t(s, bcf):
bcf_n_plus = bcf(s-s[0])
# [bcf(-3) , bcf(-2) , bcf(-1) , bcf(0), bcf(1), bcf(2), bcf(3)]
# == [bcf(3)^\ast, bcf(2)^\ast, bcf(1)^\ast, bcf(0), bcf(1), bcf(2), bcf(3)]
return np.hstack((np.conj(bcf_n_plus[-1:0:-1]), bcf_n_plus))
@staticmethod
def _calc_corr_matrix(s, bcf):
"""calculates the matrix alpha_ij = bcf(t_i-s_j)
calls bcf only for s-s_0 and reconstructs the rest
"""
n_ = len(s)
bcf_n = StocProc_KLE._calc_corr_min_t_plus_t(s, bcf)
# we want
# r = bcf(0) bcf(-1), bcf(-2)
# bcf(1) bcf( 0), bcf(-1)
# bcf(2) bcf( 1), bcf( 0)
r = np.empty(shape=(n_,n_), dtype = np.complex128)
for i in range(n_):
idx = n_-1-i
r[:,i] = bcf_n[idx:idx+n_]
return r
def __calc_missing(self):
raise NotImplementedError
def _calc_z(self, y):
if self.kle_interp:
_a_tmp = np.tensordot(y, self._A, axes=([0], [1]))
_num_gp = self._A.shape[0]
return stocproc_c.z_t(delta_t_fac = self.ng_fac,
N1 = _num_gp,
alpha_k = self.alpha_k,
a_tmp = _a_tmp,
kahanSum = True)
else:
return np.tensordot(y*self._sqrt_eig_val, self._eig_vec, axes=([0], [1])).flatten()
def get_num_y(self):
return self.num_y
class StocProc_KLE_tol(StocProc_KLE):
r"""
A class to simulate stochastic processes using Karhunen-Loève expansion (KLE) method.
The idea is that any stochastic process can be expressed in terms of the KLE
@ -272,7 +154,8 @@ class StocProc_KLE_tol(StocProc_KLE):
for a given positive integral kernel :math:`R(\tau)`. It turns out that the auto correlation
:math:`\langle Z(t)Z^\ast(s) \rangle = R(t-s)` is given by that kernel.
For the numeric implementation the integral equation has to be discretized
For the numeric implementation the integral equation will be discretized
(see :py:func:`stocproc.method_kle.solve_hom_fredholm` for details).
- Solve fredholm equation on grid with ``ng_fredholm nodes`` (trapezoidal_weights).
@ -287,7 +170,8 @@ class StocProc_KLE_tol(StocProc_KLE):
"""
def __init__(self, r_tau, t_max, tol=1e-2, ng_fac=4, seed=None, k=3, align_eig_vec=False):
def __init__(self, r_tau, t_max, ng_fac=4, meth='fourpoint', tol=1e-2, diff_method='full', dm_random_samples=10**4,
seed=None, align_eig_vec=False):
"""this is init
:param r_tau:
@ -298,69 +182,48 @@ class StocProc_KLE_tol(StocProc_KLE):
:param k:
:param align_eig_vec:
"""
self.tol = tol
kwargs = {'r_tau': r_tau, 't_max': t_max, 'ng_fac': ng_fac, 'seed': seed,
'sig_min': tol**2, 'k': k, 'align_eig_vec': align_eig_vec}
self._auto_grid_points(**kwargs)
# overwrite ng_fac in key from StocProc_KLE with value of tol
# self.key = (r_tau, t_max, ng_fredholm, ng_fac, sig_min, align_eig_vec)
self.key = (self.key[0], self.key[1], tol, self.key[3],self.key[4], self.key[5])
def _init_StocProc_KLE_and_get_error(self, ng, **kwargs):
super().__init__(ng_fredholm=ng, **kwargs)
ng_fine = self.ng_fac*(ng-1)+1
u_i_all_t = stocproc_c.eig_func_all_interp(delta_t_fac = self.ng_fac,
time_axis = self._s,
alpha_k = self.alpha_k,
weights = self._w,
eigen_val = self._eig_val,
eigen_vec = self._eig_vec)
sqrt_lambda_ui_fine = method_kle.auto_ng(corr=r_tau,
t_max=t_max,
ngfac=ng_fac,
meth=meth,
tol=tol,
diff_method=diff_method,
dm_random_samples=dm_random_samples)
u_i_all_ast_s = np.conj(u_i_all_t) #(N_gp, N_ev)
num_ev = len(self._eig_val)
tmp = self._eig_val.reshape(1, num_ev) * u_i_all_t #(N_gp, N_ev)
recs_bcf = np.tensordot(tmp, u_i_all_ast_s, axes=([1],[1]))
refc_bcf = np.empty(shape=(ng_fine,ng_fine), dtype = np.complex128)
for i in range(ng_fine):
idx = ng_fine-1-i
refc_bcf[:,i] = self.alpha_k[idx:idx+ng_fine]
err = np.max(np.abs(recs_bcf-refc_bcf)/np.abs(refc_bcf))
return err
def _auto_grid_points(self, **kwargs):
err = np.inf
c = 2
#exponential increase to get below error threshold
while err > self.tol:
c *= 2
ng = 2*c + 1
err = self._init_StocProc_KLE_and_get_error(ng, **kwargs)
log.info("ng {} -> err {:.3e}".format(ng, err))
c_low = c // 2
c_high = c
while (c_high - c_low) > 1:
c = (c_low + c_high) // 2
ng = 2*c + 1
err = self._init_StocProc_KLE_and_get_error(ng, **kwargs)
log.info("ng {} -> err {:.3e}".format(ng, err))
if err > self.tol:
c_low = c
else:
c_high = c
# inplace alignment such that re(ui(0)) >= 0 and im(ui(0)) = 0
if align_eig_vec:
method_kle.align_eig_vec(sqrt_lambda_ui_fine)
state = sqrt_lambda_ui_fine, t_max, seed
self.__setstate__(state)
self.key = r_tau, t_max, tol
def __getstate__(self):
return self.sqrt_lambda_ui_fine, self.t_max, self._seed
def __setstate__(self, state):
sqrt_lambda_ui_fine, t_max, seed = state
num_ev, ng = sqrt_lambda_ui_fine.shape
super().__init__(t_max = t_max,
num_grid_points = ng,
seed = seed)
self.num_ev = num_ev
self.sqrt_lambda_ui_fine = sqrt_lambda_ui_fine
def _calc_z(self, y):
return np.tensordot(y, self.sqrt_lambda_ui_fine, axes=([0], [0])).flatten()
def get_num_y(self):
return self.num_ev
class StocProc_FFT_tol(_absStocProc):
class StocProc_FFT(_absStocProc):
r"""
Simulate Stochastic Process using FFT method
"""
def __init__(self, spectral_density, t_max, bcf_ref, intgr_tol=1e-2, intpl_tol=1e-2,
seed=None, k=3, negative_frequencies=False):
seed=None, negative_frequencies=False):
if not negative_frequencies:
log.info("non neg freq only")
# assume the spectral_density is 0 for w<0
@ -412,24 +275,22 @@ class StocProc_FFT_tol(_absStocProc):
super().__init__(t_max = t_max,
num_grid_points = num_grid_points,
seed = seed,
k = k)
seed = seed)
omega = dx*np.arange(N)
self.yl = spectral_density(omega + a + dx/2) * dx / np.pi
self.yl = np.sqrt(self.yl)
self.omega_min_correction = np.exp(-1j*(a+dx/2)*self.t) #self.t is from the parent class
self.key = bcf_ref, t_max, intgr_tol, intpl_tol
def __getstate__(self):
return self.yl, self.num_grid_points, self.omega_min_correction, self.t_max, self._seed, self._k
return self.yl, self.num_grid_points, self.omega_min_correction, self.t_max, self._seed
def __setstate__(self, state):
self.yl, num_grid_points, self.omega_min_correction, t_max, seed, k = state
self.yl, num_grid_points, self.omega_min_correction, t_max, seed = state
super().__init__(t_max = t_max,
num_grid_points = num_grid_points,
seed = seed,
k = k)
seed = seed)
def _calc_z(self, y):
z = np.fft.fft(self.yl * y)[0:self.num_grid_points] * self.omega_min_correction

View file

@ -482,13 +482,15 @@ def test_cython_interpolation():
def test_reconstr_ac():
t_max = 15
method_kle.auto_ng(corr=method_kle.oac,
t_max=t_max,
ngfac=2,
meth=method_kle.get_mid_point_weights_times,
tol=1e-3,
diff_method='random',
dm_random_samples=10**4)
res = method_kle.auto_ng(corr=method_kle.oac,
t_max=t_max,
ngfac=2,
meth=method_kle.get_mid_point_weights_times,
tol=1e-3,
diff_method='full',
dm_random_samples=10 ** 4)
print(type(res))
print(res.shape)

View file

@ -20,11 +20,13 @@ import sys
import os
import pathlib
p = pathlib.PosixPath(os.path.abspath(__file__))
sys.path.insert(0, str(p.parent.parent))
import stocproc as sp
import warnings
warnings.simplefilter('default')
_S_ = 0.6
@ -33,10 +35,20 @@ _GAMMA_S_PLUS_1 = gamma(_S_ + 1)
def corr(tau):
"""ohmic bath correlation function"""
return (1 + 1j*(tau))**(-(_S_+1)) * _GAMMA_S_PLUS_1 / np.pi
return (1 + 1j * (tau)) ** (-(_S_ + 1)) * _GAMMA_S_PLUS_1 / np.pi
def spectral_density(omega):
return omega**_S_ * np.exp(-omega)
return omega ** _S_ * np.exp(-omega)
_WC_ = 2
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 stocproc_metatest(stp, num_samples, tol, corr, plot):
print("generate samples")
@ -99,26 +111,6 @@ def stocproc_metatest(stp, num_samples, tol, corr, plot):
def test_stochastic_process_KLE_correlation_function(plot=False):
"""
generate samples using StocPrioc_KLE class
compare <X_t X_s> and <X_t X^ast_s> from samples with true ac functions
no interpolation at all
"""
t_max = 15
num_grid_points = 101
num_samples = 1000
tol = 3e-2
stp = sp.StocProc_KLE(r_tau = corr,
t_max = t_max,
ng_fredholm = num_grid_points,
ng_fac = 4,
seed = 0)
stocproc_metatest(stp, num_samples, tol, corr, plot)
def test_stochastic_process_KLE_tol_correlation_function(plot=False):
"""
generate samples using FFT method
@ -128,18 +120,13 @@ def test_stochastic_process_KLE_tol_correlation_function(plot=False):
"""
t_max = 15
num_samples = 1000
num_samples = 2000
tol = 3e-2
stp = sp.StocProc_KLE_tol(tol = 1e-2,
r_tau = corr,
t_max = t_max,
ng_fac = 4,
seed = 0)
stp = sp.StocProc_KLE(tol=1e-2, r_tau=corr, t_max=t_max, ng_fac=4, seed=0)
stocproc_metatest(stp, num_samples, tol, corr, plot)
def test_stochastic_process_FFT_correlation_function(plot = False):
def test_stochastic_process_FFT_correlation_function(plot=False):
"""
generate samples using FFT method
@ -149,26 +136,20 @@ def test_stochastic_process_FFT_correlation_function(plot = False):
"""
t_max = 15
num_samples = 1000
num_samples = 2000
tol = 3e-2
stp = sp.StocProc_FFT_tol(spectral_density = spectral_density,
t_max = t_max,
bcf_ref = corr,
intgr_tol = 1e-2,
intpl_tol = 1e-2,
seed = 0)
stp = sp.StocProc_FFT(spectral_density=spectral_density, t_max=t_max, bcf_ref=corr, intgr_tol=1e-2, intpl_tol=1e-2,
seed=0)
stocproc_metatest(stp, num_samples, tol, corr, plot)
def test_stocproc_dump_load():
t_max = 15
num_grid_points = 101
## STOCPROC KLE ##
####################
t0 = time.time()
stp = sp.StocProc_KLE(r_tau = corr,
t_max = t_max,
ng_fredholm = num_grid_points,
ng_fac = 4,
seed = 0)
stp = sp.StocProc_KLE(tol=1e-2, r_tau=corr, t_max=t_max, ng_fac=4, seed=0)
t1 = time.time()
dt1 = t1 - t0
stp.new_process()
@ -179,39 +160,18 @@ def test_stocproc_dump_load():
stp2 = pickle.loads(bin_data)
t1 = time.time()
dt2 = t1 - t0
assert dt2 / dt1 < 0.1 # loading should be way faster
assert dt2 / dt1 < 0.1 # loading should be way faster
stp2.new_process()
x2 = stp2()
assert np.all(x == x2)
## STOCPROC FFT ##
####################
t0 = time.time()
stp = sp.StocProc_KLE_tol(r_tau=corr,
t_max=t_max,
tol=1e-2,
ng_fac=4,
seed=0)
stp = sp.StocProc_FFT(spectral_density, t_max, corr, seed=0)
t1 = time.time()
dt1 = t1 - t0
stp.new_process()
x = stp()
bin_data = pickle.dumps(stp)
t0=time.time()
stp2 = pickle.loads(bin_data)
t1 = time.time()
dt2 = t1 - t0
assert dt2 / dt1 < 0.1 # loading should be way faster
stp2.new_process()
x2 = stp2()
assert np.all(x == x2)
t0 = time.time()
stp = sp.StocProc_FFT_tol(spectral_density, t_max, corr, seed=0)
t1 = time.time()
dt1 = t1-t0
stp.new_process()
x = stp()
@ -222,47 +182,68 @@ def test_stocproc_dump_load():
t1 = time.time()
dt2 = t1 - t0
assert dt2/dt1 < 0.1 # loading should be way faster
assert dt2 / dt1 < 0.1 # loading should be way faster
stp2.new_process()
x2 = stp2()
assert np.all(x == x2)
def test_lorentz_SD(plot=False):
_WC_ = 1
def lsp(w):
return 1/(1 + (w - _WC_)**2)# / np.pi
def lac(t):
return np.exp(- np.abs(t) - 1j*_WC_*t)
def test_many(plot=False):
t_max = 15
num_samples = 5000
tol = 5e-2
sd = spectral_density
ac = corr
stp = sp.StocProc_FFT(sd, t_max, ac, negative_frequencies=False, seed=0, intgr_tol=5e-3, intpl_tol=5e-3)
stocproc_metatest(stp, num_samples, tol, ac, plot)
stp = sp.StocProc_KLE(tol=5e-3, r_tau=ac, t_max=t_max, ng_fac=1, seed=0, diff_method='full', meth='simp')
stocproc_metatest(stp, num_samples, tol, ac, plot)
stp = sp.StocProc_KLE(tol=5e-3, r_tau=ac, t_max=t_max, ng_fac=1, seed=0, diff_method='random', meth='simp')
stocproc_metatest(stp, num_samples, tol, ac, plot)
stp = sp.StocProc_KLE(tol=5e-3, r_tau=ac, t_max=t_max, ng_fac=1, seed=0, diff_method='full', meth='fp')
stocproc_metatest(stp, num_samples, tol, ac, plot)
stp = sp.StocProc_KLE(tol=5e-3, r_tau=ac, t_max=t_max, ng_fac=1, seed=0, diff_method='random', meth='fp')
stocproc_metatest(stp, num_samples, tol, ac, plot)
t_max = 15
num_samples = 15000
tol = 3e-2
num_samples = 12000
tol = 5e-2
#stp = sp.StocProc_FFT_tol(lsp, t_max, lac, negative_frequencies=True, seed=0, intgr_tol=5e-3, intpl_tol=5e-3)
#stocproc_metatest(stp, num_samples, tol, lac, plot)
sd = lsd
ac = lac
stp = sp.StocProc_KLE_tol(tol=1e-2,
r_tau = lac,
t_max = t_max,
ng_fac = 2,
seed = 0)
stocproc_metatest(stp, num_samples, tol, lac, plot)
stp = sp.StocProc_FFT(sd, t_max, ac, negative_frequencies=True, seed=0, intgr_tol=5e-3, intpl_tol=5e-3)
stocproc_metatest(stp, num_samples, tol, ac, plot)
stp = sp.StocProc_KLE(tol=5e-3, r_tau=ac, t_max=t_max, ng_fac=1, seed=0, diff_method='full', meth='simp')
stocproc_metatest(stp, num_samples, tol, ac, plot)
stp = sp.StocProc_KLE(tol=5e-3, r_tau=ac, t_max=t_max, ng_fac=1, seed=0, diff_method='random', meth='simp')
stocproc_metatest(stp, num_samples, tol, ac, plot)
stp = sp.StocProc_KLE(tol=5e-3, r_tau=ac, t_max=t_max, ng_fac=1, seed=0, diff_method='full', meth='fp')
stocproc_metatest(stp, num_samples, tol, ac, plot)
stp = sp.StocProc_KLE(tol=5e-3, r_tau=ac, t_max=t_max, ng_fac=1, seed=0, diff_method='random', meth='fp')
stocproc_metatest(stp, num_samples, tol, ac, plot)
if __name__ == "__main__":
import logging
logging.basicConfig(level=logging.INFO)
#logging.basicConfig(level=logging.INFO)
# test_stochastic_process_KLE_correlation_function(plot=True)
# test_stochastic_process_FFT_correlation_function(plot=True)
# test_stochastic_process_KLE_tol_correlation_function(plot=True)
# test_stochastic_process_KLE_correlation_function(plot=False)
# test_stochastic_process_FFT_correlation_function(plot=False)
# test_stocproc_dump_load()
test_lorentz_SD(plot=True)
test_many(plot=False)
# test_subohmic_SD()
pass