2022-02-04 15:33:55 +01:00
|
|
|
|
from types import ModuleType
|
|
|
|
|
from typing import Callable, Tuple, Union, Iterator
|
|
|
|
|
from lmfit import minimize, Parameters
|
|
|
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
import matplotlib
|
|
|
|
|
import numpy as np
|
|
|
|
|
from numpy.polynomial import Polynomial
|
|
|
|
|
from contextlib import contextmanager
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
import h5py
|
|
|
|
|
from hopsflow import hopsflow
|
2022-02-09 16:19:19 +01:00
|
|
|
|
import hopsflow.gaussflow_two as gf
|
2022-02-04 15:33:55 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def peruse_hierarchy_files(base: str) -> Iterator[h5py.File]:
|
|
|
|
|
p = Path(base)
|
|
|
|
|
for i in p.glob("*/*.h5"):
|
|
|
|
|
f = h5py.File(i, "r")
|
|
|
|
|
yield f
|
|
|
|
|
f.close()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def α_apprx(τ, g, w):
|
|
|
|
|
return np.sum(
|
|
|
|
|
g[np.newaxis, :] * np.exp(-w[np.newaxis, :] * (τ[:, np.newaxis])), axis=1
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def fit_α(
|
|
|
|
|
α: Callable[[np.ndarray], np.ndarray],
|
|
|
|
|
n: int,
|
|
|
|
|
t_max: float,
|
|
|
|
|
support_points: Union[int, np.ndarray] = 1000,
|
|
|
|
|
) -> Tuple[np.ndarray, np.ndarray]:
|
|
|
|
|
"""
|
|
|
|
|
Fit the BCF ``α`` to a sum of ``n`` exponentials up to
|
|
|
|
|
``t_max`` using a number of ``support_points``.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def residual(fit_params, x, data):
|
|
|
|
|
resid = 0
|
|
|
|
|
w = np.array([fit_params[f"w{i}"] for i in range(n)]) + 1j * np.array(
|
|
|
|
|
[fit_params[f"wi{i}"] for i in range(n)]
|
|
|
|
|
)
|
|
|
|
|
g = np.array([fit_params[f"g{i}"] for i in range(n)]) + 1j * np.array(
|
|
|
|
|
[fit_params[f"gi{i}"] for i in range(n)]
|
|
|
|
|
)
|
|
|
|
|
resid = data - α_apprx(x, g, w)
|
|
|
|
|
|
|
|
|
|
return resid.view(float)
|
|
|
|
|
|
|
|
|
|
fit_params = Parameters()
|
|
|
|
|
for i in range(n):
|
|
|
|
|
fit_params.add(f"g{i}", value=0.1)
|
|
|
|
|
fit_params.add(f"gi{i}", value=0.1)
|
|
|
|
|
fit_params.add(f"w{i}", value=0.1)
|
|
|
|
|
fit_params.add(f"wi{i}", value=0.1)
|
|
|
|
|
|
|
|
|
|
ts = np.asarray(support_points)
|
|
|
|
|
if ts.size < 2:
|
|
|
|
|
ts = np.linspace(0, t_max, support_points)
|
|
|
|
|
|
|
|
|
|
out = minimize(residual, fit_params, args=(ts, α(ts)))
|
|
|
|
|
|
|
|
|
|
w = np.array([out.params[f"w{i}"] for i in range(n)]) + 1j * np.array(
|
|
|
|
|
[out.params[f"wi{i}"] for i in range(n)]
|
|
|
|
|
)
|
|
|
|
|
g = np.array([out.params[f"g{i}"] for i in range(n)]) + 1j * np.array(
|
|
|
|
|
[out.params[f"gi{i}"] for i in range(n)]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return w, g
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
# Plot Porn #
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def wrap_plot(f):
|
|
|
|
|
def wrapped(*args, ax=None, setup_function=plt.subplots, **kwargs):
|
|
|
|
|
fig = None
|
|
|
|
|
if not ax:
|
|
|
|
|
fig, ax = setup_function()
|
|
|
|
|
|
|
|
|
|
ret_val = f(*args, ax=ax, **kwargs)
|
|
|
|
|
return (fig, ax, ret_val) if ret_val else (fig, ax)
|
|
|
|
|
|
|
|
|
|
return wrapped
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@contextmanager
|
|
|
|
|
def hiro_style():
|
|
|
|
|
with plt.style.context("ggplot"):
|
|
|
|
|
with matplotlib.rc_context(
|
|
|
|
|
{
|
|
|
|
|
# "font.family": "serif",
|
|
|
|
|
"text.usetex": False,
|
|
|
|
|
"pgf.rcfonts": False,
|
|
|
|
|
"lines.linewidth": 1,
|
|
|
|
|
}
|
|
|
|
|
):
|
|
|
|
|
yield True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@wrap_plot
|
|
|
|
|
def plot_complex(x, y, *args, ax=None, label="", **kwargs):
|
|
|
|
|
label = label + ", " if (len(label) > 0) else ""
|
|
|
|
|
ax.plot(x, y.real, *args, label=f"{label}real part", **kwargs)
|
|
|
|
|
ax.plot(x, y.imag, *args, label=f"{label}imag part", **kwargs)
|
|
|
|
|
ax.legend()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@wrap_plot
|
2022-02-09 16:19:19 +01:00
|
|
|
|
def plot_convergence(
|
2022-03-04 16:28:11 +01:00
|
|
|
|
x,
|
|
|
|
|
y,
|
|
|
|
|
ax=None,
|
|
|
|
|
label="",
|
|
|
|
|
transform=lambda y: y,
|
|
|
|
|
slice=None,
|
|
|
|
|
linestyle="-",
|
2022-03-15 11:44:23 +01:00
|
|
|
|
bath=None,
|
2022-02-09 16:19:19 +01:00
|
|
|
|
):
|
2022-02-04 15:33:55 +01:00
|
|
|
|
label = label + ", " if (len(label) > 0) else ""
|
|
|
|
|
slice = (0, -1) if not slice else slice
|
|
|
|
|
for n, val, _ in y[slice[0] : slice[1]]:
|
|
|
|
|
plt.plot(
|
2022-03-04 16:28:11 +01:00
|
|
|
|
x,
|
2022-03-15 11:44:23 +01:00
|
|
|
|
transform(val[bath] if bath is not None else val),
|
2022-03-04 16:28:11 +01:00
|
|
|
|
label=f"{label}n={n}",
|
|
|
|
|
alpha=n / y[-1][0],
|
|
|
|
|
linestyle="--",
|
2022-02-04 15:33:55 +01:00
|
|
|
|
)
|
2022-03-04 16:28:11 +01:00
|
|
|
|
|
2022-02-04 15:33:55 +01:00
|
|
|
|
ax.errorbar(
|
|
|
|
|
x,
|
2022-03-15 11:44:23 +01:00
|
|
|
|
transform(y[-1][1][bath] if bath is not None else y[-1][1]),
|
|
|
|
|
yerr=y[-1][2][bath] if bath is not None else y[-1][2],
|
2022-02-04 15:33:55 +01:00
|
|
|
|
ecolor="yellow",
|
|
|
|
|
label=f"{label}n={y[-1][0]}",
|
|
|
|
|
color="red",
|
2022-02-09 16:19:19 +01:00
|
|
|
|
linestyle=linestyle,
|
2022-02-04 15:33:55 +01:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@wrap_plot
|
|
|
|
|
def plot_diff_vs_sigma(
|
|
|
|
|
x,
|
|
|
|
|
y,
|
|
|
|
|
reference,
|
|
|
|
|
ax=None,
|
|
|
|
|
label="",
|
|
|
|
|
transform=lambda y: y,
|
|
|
|
|
ecolor="yellow",
|
|
|
|
|
):
|
|
|
|
|
label = label + ", " if (len(label) > 0) else ""
|
|
|
|
|
ax.fill_between(
|
|
|
|
|
x,
|
|
|
|
|
0,
|
2022-03-15 11:44:23 +01:00
|
|
|
|
y[-1][2] / np.mean(np.abs(reference)),
|
2022-02-04 15:33:55 +01:00
|
|
|
|
color=ecolor,
|
|
|
|
|
label=fr"{label}$\sigma$",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
for n, val, _ in y:
|
|
|
|
|
diff = np.abs(transform(val) - reference)
|
|
|
|
|
within = (diff < y[-1][2]).sum() / y[-1][2].size
|
|
|
|
|
ax.plot(
|
|
|
|
|
x,
|
2022-03-15 11:44:23 +01:00
|
|
|
|
diff / np.mean(np.abs(reference)),
|
2022-02-04 15:33:55 +01:00
|
|
|
|
label=fr"{label}n={n} $\Delta<\sigma = {within * 100}\%$",
|
|
|
|
|
alpha=n / y[-1][0],
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
# Numpy Hacks #
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def e_i(i: int, size: int) -> np.ndarray:
|
|
|
|
|
r"""Cartesian base vector :math:`e_i`."""
|
|
|
|
|
|
|
|
|
|
vec = np.zeros(size)
|
|
|
|
|
vec[i] = 1
|
|
|
|
|
return vec
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def except_element(array: np.ndarray, index: int) -> np.ndarray:
|
|
|
|
|
mask = [i != index for i in range(array.size)]
|
|
|
|
|
return array[mask]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def poly_real(p: Polynomial) -> Polynomial:
|
|
|
|
|
"""Return the real part of ``p``."""
|
|
|
|
|
new = p.copy()
|
|
|
|
|
new.coef = p.coef.real
|
|
|
|
|
return new
|