mirror of
https://github.com/vale981/stocproc
synced 2025-03-04 17:21:42 -05:00
save some work on tests and doc
This commit is contained in:
parent
3e2307b016
commit
1fcb195aa7
14 changed files with 472 additions and 166 deletions
4
doc/source/StocProc_FFT.rst
Normal file
4
doc/source/StocProc_FFT.rst
Normal file
|
@ -0,0 +1,4 @@
|
|||
StocProc_FFT_tol
|
||||
----------------
|
||||
|
||||
.. autoclass:: stocproc.stocproc.StocProc_FFT_tol
|
9
doc/source/StocProc_KLE.rst
Normal file
9
doc/source/StocProc_KLE.rst
Normal file
|
@ -0,0 +1,9 @@
|
|||
StocProc_KLE_tol
|
||||
----------------
|
||||
|
||||
.. py:currentmodule:: stocproc
|
||||
|
||||
.. autoclass:: StocProc_KLE_tol
|
||||
:members:
|
||||
:inherited-members:
|
||||
:undoc-members:
|
|
@ -40,6 +40,8 @@ extensions = [
|
|||
'sphinx.ext.githubpages',
|
||||
]
|
||||
|
||||
autoclass_content = 'both'
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
|
|
11
doc/source/example.rst
Normal file
11
doc/source/example.rst
Normal file
|
@ -0,0 +1,11 @@
|
|||
Example
|
||||
=======
|
||||
|
||||
This example sets up a generator for stochastic processes with exponential
|
||||
auto correlation. A single process is shown as well as the reconstruction
|
||||
of the auto correlation using 5000 samples.
|
||||
|
||||
This example is used to generate the figures for the example
|
||||
section of the :doc:`StocProc Module </index>`.
|
||||
|
||||
.. literalinclude:: ../../examples/example.py
|
|
@ -1 +1,2 @@
|
|||
.. automodule:: stocproc
|
||||
.. automodule:: stocproc
|
||||
|
||||
|
|
1
doc/source/stocproc.rst
Normal file
1
doc/source/stocproc.rst
Normal file
|
@ -0,0 +1 @@
|
|||
.. automodule:: stocproc.stocproc
|
76
examples/example.py
Normal file
76
examples/example.py
Normal file
|
@ -0,0 +1,76 @@
|
|||
import sys
|
||||
import pathlib
|
||||
# add stocproc package location to path
|
||||
sys.path.insert(0, pathlib.Path(__file__).parent.parent)
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import stocproc as sp
|
||||
|
||||
_WC_ = 5
|
||||
def lsd(w):
|
||||
"""Lorenzian spectral density"""
|
||||
return 1/(1 + (w - _WC_)**2)
|
||||
|
||||
def lac(t):
|
||||
"""the corresponding Lorenzian correlation function
|
||||
|
||||
note there is a factor of one over pi in the deficition
|
||||
of the correlation function:
|
||||
lac(t) = 1/pi int_{-infty}^infty d w lsd(w) exp(-i w t)
|
||||
"""
|
||||
return np.exp(- np.abs(t) - 1j*_WC_*t)
|
||||
|
||||
t_max = 10
|
||||
print("setup process generator")
|
||||
stp = sp.StocProc_FFT_tol(lsd, t_max, lac,
|
||||
negative_frequencies=True, seed=0,
|
||||
intgr_tol=1e-2, intpl_tol=1e-2)
|
||||
|
||||
fig = plt.figure()
|
||||
print("generate single process")
|
||||
stp.new_process()
|
||||
zt = stp() # get discrete process
|
||||
t = stp.t # and the natural time axis for the discrete process
|
||||
plt.plot(stp.t, np.real(stp()), color='k',
|
||||
label="$\mathrm{real}(z(t))$")
|
||||
plt.plot(stp.t, np.imag(stp()), color='k', ls='--',
|
||||
label="$\mathrm{imag}(z(t))$")
|
||||
plt.xlim([0,10])
|
||||
plt.legend(ncol=2, loc='upper right')
|
||||
plt.title("stochastic process with exponential autocorrelaition")
|
||||
plt.xlabel("time")
|
||||
plt.ylabel("process $z(t)$")
|
||||
plt.grid()
|
||||
plt.savefig("proc.png")
|
||||
|
||||
ns = 5000
|
||||
print("generate {} samples".format(ns))
|
||||
# choose time axis 4 time finer than the natural discrete axis
|
||||
tfine = np.linspace(0, t_max, (stp.num_grid_points - 1) * 4 + 1)
|
||||
corr = np.zeros(shape=len(tfine), dtype=np.complex128)
|
||||
# tells that we want to calculate <z(t) z^\ast(tref)>
|
||||
tref = 2
|
||||
# calculates the auto correlation
|
||||
for i in range(ns):
|
||||
stp.new_process()
|
||||
zt = stp(tfine)
|
||||
corr += zt * np.conj(stp(tref))
|
||||
corr /= ns
|
||||
|
||||
fig = plt.figure()
|
||||
aclab = r"\langle z(t)z^\ast(t_\mathrm{ref})\rangle"
|
||||
plt.plot(tfine, np.real(lac(tfine-tref)), color='r',
|
||||
label=r"$\mathrm{{real}}\left({}\right)$".format(aclab))
|
||||
plt.plot(tfine, np.imag(lac(tfine-tref)), color='r', ls='--',
|
||||
label=r"$\mathrm{{imag}}\left({}\right)$".format(aclab))
|
||||
plt.plot(tfine, np.real(corr), color='k',
|
||||
label="exact auto correlation")
|
||||
plt.plot(tfine, np.imag(corr), color='k', ls='--')
|
||||
plt.legend(loc='upper right')
|
||||
plt.title("auto correlation using {} samples".format(ns))
|
||||
plt.xlabel("time")
|
||||
plt.ylabel(r"auto correlation ($t_\mathrm{{ref}}={}$)".format(tref))
|
||||
plt.grid()
|
||||
plt.savefig("ac.png")
|
||||
|
||||
plt.show()
|
|
@ -1,32 +1,61 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Stochastic Process Module
|
||||
=========================
|
||||
|
||||
This module contains two different implementation for generating stochastic processes for a
|
||||
given auto correlation function. Both methods are based on a time discrete process, however cubic
|
||||
given auto correlation function (:doc:`Karhunen-Loève expansion </StocProc_KLE>`
|
||||
and :doc:`Fast-Fourier method </StocProc_FFT>`).
|
||||
Both methods are based on a time discrete process, however cubic
|
||||
spline interpolation is assured to be valid within a given tolerance.
|
||||
|
||||
* simulate stochastic processes using Karhunen-Loève expansion :py:func:`stocproc.StocProc_KLE_tol`
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
Setting up the class involves solving an eigenvalue problem which grows with
|
||||
the time interval the process is simulated on. Further generating a new process
|
||||
involves a multiplication with that matrix, therefore it scales quadratically with the
|
||||
time interval. Nonetheless it turns out that this method requires less random numbers
|
||||
than the Fast-Fourier method.
|
||||
stocproc
|
||||
example
|
||||
|
||||
* simulate stochastic processes using Fast-Fourier method method :py:func:`stocproc.StocProc_FFT_tol`
|
||||
Example
|
||||
-------
|
||||
|
||||
Setting up this class is quite efficient as it only calculates values of the
|
||||
associated spectral density. The number scales linear with the time interval of interest. However to achieve
|
||||
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.
|
||||
The example will setup a process generator for an exponential auto correlation function
|
||||
and sample a single realization. ::
|
||||
|
||||
def lsd(w):
|
||||
# Lorenzian spectral density
|
||||
return 1/(1 + (w - _WC_)**2)
|
||||
|
||||
def lac(t):
|
||||
# the corresponding Lorenzian correlation function
|
||||
# note there is a factor of one over pi in the
|
||||
# deficition of the correlation function:
|
||||
# lac(t) = 1/pi int_{-infty}^infty d w lsd(w) exp(-i w t)
|
||||
return np.exp(- np.abs(t) - 1j*_WC_*t)
|
||||
|
||||
t_max = 10
|
||||
print("setup process generator")
|
||||
stp = sp.StocProc_FFT_tol(lsd, t_max, lac,
|
||||
negative_frequencies=True, seed=0,
|
||||
intgr_tol=1e-2, intpl_tol=1e-2)
|
||||
print("generate single process")
|
||||
stp.new_process()
|
||||
zt = stp() # get discrete process
|
||||
|
||||
The full example can be found :doc:`here </example>`.
|
||||
|
||||
.. image:: ../../examples/proc.*
|
||||
|
||||
Averaging over 5000 samples yields the auto correlation function which is in good agreement
|
||||
with the exact auto correlation.
|
||||
|
||||
.. image:: ../../examples/ac.*
|
||||
"""
|
||||
|
||||
version = '0.2.0'
|
||||
|
||||
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_KLE
|
||||
from .stocproc import StocProc_KLE_tol
|
|
@ -1,3 +1,9 @@
|
|||
"""
|
||||
The method_fft module provides convenient function to
|
||||
setup a stochastic process generator using fft method
|
||||
|
||||
|
||||
"""
|
||||
from __future__ import division, print_function
|
||||
|
||||
from .tools import ComplexInterpolatedUnivariateSpline
|
||||
|
@ -10,8 +16,7 @@ from scipy.optimize import brentq
|
|||
from scipy.optimize import basinhopping
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
warnings.simplefilter('error')
|
||||
#warnings.simplefilter('error')
|
||||
MAX_FLOAT = sys.float_info.max
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -221,7 +226,7 @@ def opt_integral_boundaries(integrand, a, b, t_max, ft_ref, opt_b_only, N):
|
|||
stepsize=0.1*(b-a))
|
||||
a, b = r.x[0], r.x[1]
|
||||
rd = 10 ** r.fun
|
||||
log.info("optimization yields max rd {:.3e} and new boundaries [{:.2e},{:.2e}]".format(rd, a, b))
|
||||
log.info("optimization with N {} yields max rd {:.3e} and new boundaries [{:.2e},{:.2e}]".format(N, rd, a, b))
|
||||
|
||||
return rd, a, b
|
||||
|
||||
|
@ -279,17 +284,19 @@ def calc_ab_N_dx_dt(integrand, intgr_tol, intpl_tol, t_max, a, b, ft_ref, opt_b_
|
|||
ft_ref = ft_ref,
|
||||
opt_b_only=opt_b_only,
|
||||
N_max = N_max)
|
||||
dt = get_dt_for_accurate_interpolation(t_max = t_max,
|
||||
tol = intpl_tol,
|
||||
ft_ref = ft_ref)
|
||||
dt_tol = get_dt_for_accurate_interpolation(t_max = t_max,
|
||||
tol = intpl_tol,
|
||||
ft_ref = ft_ref)
|
||||
|
||||
dx = (b-a)/N
|
||||
N_min = 2*np.pi/dx/dt
|
||||
if N_min <= N:
|
||||
dt = 2*np.pi/dx/N
|
||||
if dt <= dt_tol:
|
||||
log.info("dt criterion fulfilled")
|
||||
return a, b, N, dx, dt
|
||||
else:
|
||||
log.info("down scale dx and dt to match new power of 2 N")
|
||||
|
||||
N_min = 2*np.pi/dx/dt_tol
|
||||
N = 2**int(np.ceil(np.log2(N_min)))
|
||||
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ def solve_hom_fredholm(r, w, eig_val_min):
|
|||
|
||||
return eig_val, eig_vec
|
||||
|
||||
def get_mid_point_weights(t_max, num_grid_points):
|
||||
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
|
||||
|
|
|
@ -1,6 +1,29 @@
|
|||
# -*- coding: utf8 -*-
|
||||
from __future__ import print_function, division
|
||||
"""
|
||||
Stochastic Process Generators
|
||||
=============================
|
||||
|
||||
Karhunen-Loève expansion
|
||||
------------------------
|
||||
|
||||
This method samples stochastic processes using Karhunen-Loève expansion and
|
||||
is implemented in the class :doc:`StocProc_KLE_tol </StocProc_KLE>`.
|
||||
|
||||
Setting up the class involves solving an eigenvalue problem which grows with
|
||||
the time interval the process is simulated on. Further generating a new process
|
||||
involves a multiplication with that matrix, therefore it scales quadratically with the
|
||||
time interval. Nonetheless it turns out that this method requires less random numbers
|
||||
than the Fast-Fourier method.
|
||||
|
||||
|
||||
Fast-Fourier method
|
||||
-------------------
|
||||
simulate stochastic processes using Fast-Fourier method method :py:func:`stocproc.StocProc_FFT_tol`
|
||||
|
||||
Setting up this class is quite efficient as it only calculates values of the
|
||||
associated spectral density. The number scales linear with the time interval of interest. However to achieve
|
||||
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 numpy as np
|
||||
import time
|
||||
|
||||
|
@ -113,6 +136,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
|
||||
|
@ -134,7 +159,11 @@ class StocProc_KLE(_absStocProc):
|
|||
|
||||
# this lengthy part will be skipped when init class from dump, as _A and alpha_k will be stored
|
||||
t0 = time.time()
|
||||
t, w = method_kle.get_simpson_weights_times(t_max, ng_fredholm)
|
||||
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:
|
||||
|
@ -229,11 +258,49 @@ class StocProc_KLE(_absStocProc):
|
|||
|
||||
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
|
||||
|
||||
.. math:: Z(t) = \sum_i \sqrt{\lambda_i} Y_i u_i(t)
|
||||
|
||||
where :math:`Y_i` and independent complex valued Gaussian random variables with variance one
|
||||
(:math:`\langle Y_i Y_j \rangle = \delta_{ij}`) and :math:`\lambda_i`, :math:`u_i(t)` are
|
||||
eigenvalues / eigenfunctions of the following Fredholm equation
|
||||
|
||||
.. math:: \int_0^{t_\mathrm{max}} \mathrm{d}s R(t-s) u_i(s) = \lambda_i u_i(t)
|
||||
|
||||
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
|
||||
|
||||
|
||||
- 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
|
||||
|
||||
same as StocProc_KLE except that ng_fredholm is determined from given tolerance
|
||||
|
||||
bla bla
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, tol=1e-2, **kwargs):
|
||||
def __init__(self, r_tau, t_max, tol=1e-2, ng_fac=4, seed=None, k=3, align_eig_vec=False):
|
||||
"""this is init
|
||||
|
||||
:param r_tau:
|
||||
:param t_max:
|
||||
:param tol:
|
||||
:param ng_fac:
|
||||
:param seed:
|
||||
: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)
|
||||
|
@ -339,6 +406,7 @@ class StocProc_FFT_tol(_absStocProc):
|
|||
N_max = 2**24)
|
||||
log.info("required tol result in N {}".format(N))
|
||||
|
||||
assert abs(2*np.pi - N*dx*dt) < 1e-12
|
||||
num_grid_points = int(np.ceil(t_max/dt))+1
|
||||
t_max = (num_grid_points-1)*dt
|
||||
|
||||
|
|
|
@ -20,13 +20,22 @@ stocproc_key_type = namedtuple(typename = 'stocproc_key_type',
|
|||
|
||||
|
||||
class ComplexInterpolatedUnivariateSpline(object):
|
||||
def __init__(self, x, y, k=2):
|
||||
def __init__(self, x, y, k=3):
|
||||
self.re_spline = InterpolatedUnivariateSpline(x, np.real(y))
|
||||
self.im_spline = InterpolatedUnivariateSpline(x, np.imag(y))
|
||||
|
||||
def __call__(self, t):
|
||||
return self.re_spline(t) + 1j * self.im_spline(t)
|
||||
|
||||
|
||||
def complex_quad(func, a, b, **kw_args):
|
||||
func_re = lambda t: np.real(func(t))
|
||||
func_im = lambda t: np.imag(func(t))
|
||||
I_re = quad(func_re, a, b, **kw_args)[0]
|
||||
I_im = quad(func_im, a, b, **kw_args)[0]
|
||||
|
||||
return I_re + 1j * I_im
|
||||
|
||||
def auto_correlation_numpy(x, verbose=1):
|
||||
warn("use 'auto_correlation' instead", DeprecationWarning)
|
||||
|
||||
|
|
196
tests/test_method_kle.py
Normal file
196
tests/test_method_kle.py
Normal file
|
@ -0,0 +1,196 @@
|
|||
import sys
|
||||
import os
|
||||
|
||||
import numpy as np
|
||||
import math
|
||||
from scipy.special import gamma as gamma_func
|
||||
import scipy.integrate as sp_int
|
||||
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))
|
||||
|
||||
import stocproc as sp
|
||||
from stocproc import tools
|
||||
from stocproc import stocproc_c
|
||||
from scipy.integrate import quad
|
||||
import logging
|
||||
|
||||
def test_solve_fredholm():
|
||||
_WC_ = 2
|
||||
def lac(t):
|
||||
return np.exp(- np.abs(t) - 1j*_WC_*t)
|
||||
|
||||
t_max = 10
|
||||
|
||||
for ng in range(11, 450, 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_val_min=0)
|
||||
|
||||
ng_fac = 4
|
||||
ng_fine = ng_fac * (ng - 1) + 1
|
||||
tfine = np.linspace(0, t_max, ng_fine)
|
||||
bcf_n_plus = lac(tfine - tfine[0])
|
||||
alpha_k = np.hstack((np.conj(bcf_n_plus[-1:0:-1]), bcf_n_plus))
|
||||
|
||||
u_i_all_t = stocproc_c.eig_func_all_interp(delta_t_fac=ng_fac,
|
||||
time_axis=t,
|
||||
alpha_k=alpha_k,
|
||||
weights=w,
|
||||
eigen_val=_eig_val,
|
||||
eigen_vec=_eig_vec)
|
||||
|
||||
u_i_all_ast_s = np.conj(u_i_all_t) # (N_gp, N_ev)
|
||||
num_ev = len(_eig_val)
|
||||
tmp = _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] = alpha_k[idx:idx + ng_fine]
|
||||
|
||||
err = np.max(np.abs(recs_bcf - refc_bcf) / np.abs(refc_bcf))
|
||||
plt.plot(ng, err, marker='o', color='r')
|
||||
|
||||
ng += 2
|
||||
t, w = sp.method_kle.get_simpson_weights_times(t_max, ng)
|
||||
r = lac(t.reshape(-1, 1) - t.reshape(1, -1))
|
||||
_eig_val2, _eig_vec2 = sp.method_kle.solve_hom_fredholm(r, w, eig_val_min=0)
|
||||
#print(np.max(np.abs(_eig_val - _eig_val2)), np.max(np.abs(_eig_vec - _eig_vec2)))
|
||||
_eig_val, _eig_vec = _eig_val2, _eig_vec2
|
||||
|
||||
ng_fac = 4
|
||||
ng_fine = ng_fac * (ng - 1) + 1
|
||||
tfine = np.linspace(0, t_max, ng_fine)
|
||||
bcf_n_plus = lac(tfine - tfine[0])
|
||||
alpha_k = np.hstack((np.conj(bcf_n_plus[-1:0:-1]), bcf_n_plus))
|
||||
|
||||
u_i_all_t2 = stocproc_c.eig_func_all_interp(delta_t_fac=ng_fac,
|
||||
time_axis=t,
|
||||
alpha_k=alpha_k,
|
||||
weights=w,
|
||||
eigen_val=_eig_val,
|
||||
eigen_vec=_eig_vec)
|
||||
#print(np.max(np.abs(u_i_all_t - u_i_all_t2)))
|
||||
u_i_all_t = u_i_all_t2
|
||||
#print()
|
||||
|
||||
|
||||
u_i_all_ast_s = np.conj(u_i_all_t) # (N_gp, N_ev)
|
||||
num_ev = len(_eig_val)
|
||||
tmp = _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] = alpha_k[idx:idx + ng_fine]
|
||||
|
||||
err2 = np.max(np.abs(recs_bcf - refc_bcf) / np.abs(refc_bcf))
|
||||
plt.plot(ng, err2, marker='o', color='k')
|
||||
print(err, err2)
|
||||
|
||||
plt.yscale('log')
|
||||
plt.grid()
|
||||
plt.show()
|
||||
|
||||
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
|
||||
for ng in range(11,500,30):
|
||||
print(ng)
|
||||
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_val_min=0)
|
||||
_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 < 1e-10
|
||||
|
||||
|
||||
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_val_min=0)
|
||||
_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 < 1e-10
|
||||
|
||||
def test_solve_fredholm_interp_eigenfunc(plot=False):
|
||||
"""
|
||||
here we take the discrete eigenfunctions of the Fredholm problem
|
||||
and use qubic interpolation to check the integral equality.
|
||||
|
||||
the difference between the midpoint weights and simpson weights become
|
||||
visible. Although the simpson integration yields on average a better performance
|
||||
there are high fluctuation in the error.
|
||||
"""
|
||||
_WC_ = 2
|
||||
def lac(t):
|
||||
return np.exp(- np.abs(t) - 1j*_WC_*t)
|
||||
|
||||
t_max = 10
|
||||
ng = 81
|
||||
ngfac = 2
|
||||
tfine = np.linspace(0, t_max, (ng-1)*ngfac+1)
|
||||
|
||||
if plot:
|
||||
fig, ax = plt.subplots(nrows=2, ncols=2, sharey=True, sharex=True)
|
||||
ax = ax.flatten()
|
||||
|
||||
for idx in range(4):
|
||||
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_val_min=0)
|
||||
u0 = tools.ComplexInterpolatedUnivariateSpline(t, _eig_vec[:,idx])
|
||||
lam0 = _eig_val[idx]
|
||||
err_mp = []
|
||||
for ti in tfine:
|
||||
I = tools.complex_quad(lambda s: lac(ti-s)*u0(s), 0, t_max, limit=500)
|
||||
err_mp.append(np.abs(I - lam0*u0(ti)))
|
||||
if plot:
|
||||
axc = ax[idx]
|
||||
axc.plot(tfine, err_mp, color='r', label='midp')
|
||||
|
||||
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_val_min=0)
|
||||
u0 = tools.ComplexInterpolatedUnivariateSpline(t, _eig_vec[:, idx])
|
||||
lam0 = _eig_val[idx]
|
||||
err_sp = []
|
||||
for ti in tfine:
|
||||
I = tools.complex_quad(lambda s: lac(ti - s) * u0(s), 0, t_max, limit=500)
|
||||
err_sp.append(np.abs(I - lam0 * u0(ti)))
|
||||
if plot:
|
||||
axc.plot(tfine, err_sp, color='k', label='simp')
|
||||
axc.set_yscale('log')
|
||||
axc.plot(tfine[::ngfac], err_sp[::ngfac], ls='', marker='x', color='k')
|
||||
axc.set_title("eigen function # {}".format(idx))
|
||||
|
||||
assert max(err_mp) > max(err_sp)
|
||||
|
||||
if plot:
|
||||
fig.suptitle("np.abs(int R(t-s)u_i(s) - lam_i * u_i(t))")
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# test_solve_fredholm()
|
||||
# test_solve_fredholm_reconstr_ac()
|
||||
test_solve_fredholm_interp_eigenfunc(plot=True)
|
|
@ -40,15 +40,16 @@ def spectral_density(omega):
|
|||
|
||||
def stocproc_metatest(stp, num_samples, tol, corr, plot):
|
||||
print("generate samples")
|
||||
t = np.linspace(0, stp.t_max, 487)
|
||||
x_t_array_KLE = np.empty(shape=(num_samples, 487), dtype=np.complex128)
|
||||
N = 287
|
||||
t = np.linspace(0, stp.t_max, N)
|
||||
x_t_array_KLE = np.empty(shape=(num_samples, N), dtype=np.complex128)
|
||||
for i in range(num_samples):
|
||||
stp.new_process()
|
||||
x_t_array_KLE[i] = stp(t)
|
||||
|
||||
autoCorr_KLE_conj, autoCorr_KLE_not_conj = sp.tools.auto_correlation(x_t_array_KLE)
|
||||
|
||||
ac_true = corr(t.reshape(487, 1) - t.reshape(1, 487))
|
||||
ac_true = corr(t.reshape(N, 1) - t.reshape(1, N))
|
||||
|
||||
max_diff_conj = np.max(np.abs(ac_true - autoCorr_KLE_conj))
|
||||
print("max diff <x(t) x^ast(s)>: {:.2e}".format(max_diff_conj))
|
||||
|
@ -63,32 +64,32 @@ def stocproc_metatest(stp, num_samples, tol, corr, plot):
|
|||
v_min_imag = np.floor(np.min(np.imag(ac_true)))
|
||||
v_max_imag = np.ceil(np.max(np.imag(ac_true)))
|
||||
|
||||
fig, ax = plt.subplots(nrows=4, ncols=2, figsize=(10, 14))
|
||||
fig, ax = plt.subplots(nrows=2, ncols=4, figsize=(14, 10))
|
||||
ax[0, 0].set_title(r"exact $\mathrm{re}\left(\langle x(t) x^\ast(s) \rangle\right)$")
|
||||
ax[0, 0].imshow(np.real(ac_true), interpolation='none', vmin=v_min_real, vmax=v_max_real, cmap="seismic")
|
||||
ax[0, 1].set_title(r"exact $\mathrm{im}\left(\langle x(t) x^\ast(s) \rangle\right)$")
|
||||
ax[0, 1].imshow(np.imag(ac_true), interpolation='none', vmin=v_min_imag, vmax=v_max_imag, cmap="seismic")
|
||||
ax[1, 0].set_title(r"exact $\mathrm{im}\left(\langle x(t) x^\ast(s) \rangle\right)$")
|
||||
ax[1, 0].imshow(np.imag(ac_true), interpolation='none', vmin=v_min_imag, vmax=v_max_imag, cmap="seismic")
|
||||
|
||||
ax[1, 0].set_title(r"KLE $\mathrm{re}\left(\langle x(t) x^\ast(s) \rangle\right)$")
|
||||
ax[1, 0].imshow(np.real(autoCorr_KLE_conj), interpolation='none', vmin=v_min_real, vmax=v_max_real,
|
||||
ax[0, 1].set_title(r"$\mathrm{re}\left(\langle x(t) x^\ast(s) \rangle\right)$")
|
||||
ax[0, 1].imshow(np.real(autoCorr_KLE_conj), interpolation='none', vmin=v_min_real, vmax=v_max_real,
|
||||
cmap="seismic")
|
||||
ax[1, 1].set_title(r"KLE $\mathrm{im}\left(\langle x(t) x^\ast(s) \rangle\right)$")
|
||||
ax[1, 1].set_title(r"$\mathrm{im}\left(\langle x(t) x^\ast(s) \rangle\right)$")
|
||||
ax[1, 1].imshow(np.imag(autoCorr_KLE_conj), interpolation='none', vmin=v_min_imag, vmax=v_max_imag,
|
||||
cmap="seismic")
|
||||
|
||||
ax[2, 0].set_title(r"KLE $\mathrm{re}\left(\langle x(t) x(s) \rangle\right)$")
|
||||
ax[2, 0].imshow(np.real(autoCorr_KLE_not_conj), interpolation='none', vmin=v_min_real, vmax=v_max_real,
|
||||
ax[0, 2].set_title(r"$\mathrm{re}\left(\langle x(t) x(s) \rangle\right)$")
|
||||
ax[0, 2].imshow(np.real(autoCorr_KLE_not_conj), interpolation='none', vmin=v_min_real, vmax=v_max_real,
|
||||
cmap="seismic")
|
||||
ax[2, 1].set_title(r"KLE $\mathrm{im}\left(\langle x(t) x(s) \rangle\right)$")
|
||||
ax[2, 1].imshow(np.imag(autoCorr_KLE_not_conj), interpolation='none', vmin=v_min_imag, vmax=v_max_imag,
|
||||
ax[1, 2].set_title(r"$\mathrm{im}\left(\langle x(t) x(s) \rangle\right)$")
|
||||
ax[1, 2].imshow(np.imag(autoCorr_KLE_not_conj), interpolation='none', vmin=v_min_imag, vmax=v_max_imag,
|
||||
cmap="seismic")
|
||||
|
||||
ax[3, 0].set_title(r"abs diff $\langle x(t) x^\ast(s) \rangle$")
|
||||
cax = ax[3, 0].imshow(np.log10(np.abs(autoCorr_KLE_conj - ac_true)), interpolation='none', cmap="inferno")
|
||||
fig.colorbar(cax, ax=ax[3, 0])
|
||||
ax[3, 1].set_title(r"abs diff $\langle x(t) x(s) \rangle$")
|
||||
cax = ax[3, 1].imshow(np.log10(np.abs(autoCorr_KLE_not_conj)), interpolation='none', cmap="inferno")
|
||||
fig.colorbar(cax, ax=ax[3, 1])
|
||||
ax[0, 3].set_title(r"abs diff $\langle x(t) x^\ast(s) \rangle$")
|
||||
cax = ax[0, 3].imshow(np.log10(np.abs(autoCorr_KLE_conj - ac_true)), interpolation='none', cmap="inferno")
|
||||
fig.colorbar(cax, ax=ax[0, 3])
|
||||
ax[1, 3].set_title(r"abs diff $\langle x(t) x(s) \rangle$")
|
||||
cax = ax[1, 3].imshow(np.log10(np.abs(autoCorr_KLE_not_conj)), interpolation='none', cmap="inferno")
|
||||
fig.colorbar(cax, ax=ax[1, 3])
|
||||
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
|
@ -238,126 +239,18 @@ def test_lorentz_SD(plot=False):
|
|||
|
||||
|
||||
t_max = 15
|
||||
num_samples = 5000
|
||||
num_samples = 15000
|
||||
tol = 3e-2
|
||||
stp = sp.StocProc_KLE(r_tau=lac,
|
||||
t_max=t_max,
|
||||
ng_fredholm=1025,
|
||||
ng_fac=2,
|
||||
seed=0)
|
||||
t = stp.t
|
||||
stp.new_process()
|
||||
plt.plot(t, np.abs(stp()))
|
||||
|
||||
|
||||
stp = sp.StocProc_FFT_tol(lsp, t_max, lac, negative_frequencies=True, seed=0, intgr_tol=1e-2, intpl_tol=1e-9)
|
||||
t = stp.t
|
||||
stp.new_process()
|
||||
plt.plot(t, np.abs(stp()), ls='', marker='.')
|
||||
|
||||
stp = sp.StocProc_FFT_tol(lsp, t_max, lac, negative_frequencies=True, seed=0, intgr_tol=1e-2, intpl_tol=1e-11)
|
||||
t = stp.t
|
||||
stp.new_process()
|
||||
plt.plot(t, np.abs(stp()), ls='', marker='.')
|
||||
|
||||
|
||||
plt.show()
|
||||
return
|
||||
|
||||
print("generate samples")
|
||||
t = np.linspace(0, stp.t_max, 487)
|
||||
t_fine = np.linspace(0, stp.t_max, 4870)
|
||||
|
||||
t_ref_list = [0,1,7]
|
||||
|
||||
|
||||
|
||||
# for num_samples in [100, 1000]:
|
||||
# x_t0 = np.zeros(shape=(3), dtype=np.complex128)
|
||||
# for i in range(num_samples):
|
||||
# stp.new_process()
|
||||
# x_t = stp(t)
|
||||
# for j, ti in enumerate(t_ref_list):
|
||||
# x_t0[j] += np.conj(stp(ti)) * stp(ti)
|
||||
# x_t0 /= num_samples
|
||||
# print(np.abs(1-x_t0))
|
||||
|
||||
num_samples = 1000
|
||||
x_t_array = np.zeros(shape=(487, 3), dtype=np.complex128)
|
||||
for i in range(num_samples):
|
||||
stp.new_process()
|
||||
x_t = stp(t)
|
||||
for j, ti in enumerate(t_ref_list):
|
||||
x_t_array[:, j] += x_t * np.conj(stp(ti))
|
||||
|
||||
x_t_array /= num_samples
|
||||
for j, ti in enumerate(t_ref_list):
|
||||
p, = plt.plot(t, np.abs(x_t_array[:, j]))
|
||||
plt.plot(t_fine, np.abs(lac(t_fine-ti)), color=p.get_color())
|
||||
|
||||
plt.show()
|
||||
|
||||
|
||||
|
||||
|
||||
#num_samples = 1000
|
||||
#stp = sp.StocProc_FFT_tol(lsp, t_max, lac, negative_frequencies=True, seed=0, intgr_tol=1e-2, intpl_tol=1e-2)
|
||||
#stocproc_metatest(stp, num_samples, tol, lambda tau:lac(tau)/np.pi, plot)
|
||||
|
||||
|
||||
|
||||
def test_subohmic_SD(plot=False):
|
||||
|
||||
def lsp(omega):
|
||||
return omega ** _S_ * np.exp(-omega)
|
||||
|
||||
def lac(tau):
|
||||
return (1 + 1j*(tau))**(-(_S_+1)) * _GAMMA_S_PLUS_1 / np.pi
|
||||
|
||||
|
||||
t_max = 15
|
||||
stp = sp.StocProc_KLE(r_tau=lac,
|
||||
t_max=t_max,
|
||||
ng_fredholm=1025,
|
||||
ng_fac=2,
|
||||
seed=0)
|
||||
t = stp.t
|
||||
stp.new_process()
|
||||
plt.plot(t, np.abs(stp()))
|
||||
|
||||
|
||||
stp = sp.StocProc_FFT_tol(lsp, t_max, lac, negative_frequencies=False, seed=0, intgr_tol=1e-3, intpl_tol=1e-3)
|
||||
t = stp.t
|
||||
stp.new_process()
|
||||
plt.plot(t, np.abs(stp()))
|
||||
plt.show()
|
||||
return
|
||||
|
||||
|
||||
|
||||
print("generate samples")
|
||||
t = np.linspace(0, stp.t_max, 487)
|
||||
t_fine = np.linspace(0, stp.t_max, 4870)
|
||||
|
||||
t_ref_list = [0,1,7]
|
||||
|
||||
num_samples = 1000
|
||||
x_t_array = np.zeros(shape=(487, 3), dtype=np.complex128)
|
||||
for i in range(num_samples):
|
||||
stp.new_process()
|
||||
x_t = stp(t)
|
||||
for j, ti in enumerate(t_ref_list):
|
||||
x_t_array[:, j] += x_t * np.conj(stp(ti))
|
||||
|
||||
x_t_array /= num_samples
|
||||
for j, ti in enumerate(t_ref_list):
|
||||
p, = plt.plot(t, np.abs(x_t_array[:, j]))
|
||||
plt.plot(t_fine, np.abs(lac(t_fine-ti)), color=p.get_color())
|
||||
|
||||
plt.show()
|
||||
|
||||
|
||||
#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)
|
||||
|
||||
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)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
Loading…
Add table
Reference in a new issue