#+PROPERTY: header-args :session thermal_lin :kernel python :pandoc t :async yes * Setup ** Jupyter #+begin_src jupyter-python %load_ext autoreload %autoreload 2 %load_ext jupyter_spaces #+end_src #+RESULTS: ** Matplotlib #+begin_src jupyter-python import matplotlib import matplotlib.pyplot as plt #matplotlib.use("TkCairo", force=True) %gui tk %matplotlib inline plt.style.use('ggplot') #+end_src #+RESULTS: ** Richard (old) HOPS #+begin_src jupyter-python import hierarchyLib import hierarchyData import numpy as np from stocproc.stocproc import StocProc_FFT import bcf from dataclasses import dataclass, field import scipy import scipy.misc import scipy.signal import pickle from scipy.special import gamma as gamma_func from scipy.optimize import curve_fit #+end_src #+RESULTS: ** Auxiliary Definitions #+begin_src jupyter-python σ1 = np.matrix([[0,1],[1,0]]) σ2 = np.matrix([[0,-1j],[1j,0]]) σ3 = np.matrix([[1,0],[0,-1]]) #+end_src #+RESULTS: * Model Setup Basic parameters. #+begin_src jupyter-python class params: T = 2.09 t_max = 1 t_steps = int(t_max * 1/.01) k_max = 3 N = 17 seed = 100 dim = 2 H_s = σ3 + np.eye(dim) L = 1 / 2 * (σ1 - 1j * σ2) ψ_0 = np.array([1, 0]) s = 1 num_exp_t = 5 wc = 1 with open("good_fit_data_abs_brute_force", "rb") as f: good_fit_data_abs = pickle.load(f) alpha = 0.8 # _, g_tilde, w_tilde = good_fit_data_abs[(numExpFit, s)] # g_tilde = np.array(g_tilde) # w_tilde = np.array(w_tilde) # g = 1 / np.pi * gamma_func(s + 1) * wc ** (s + 1) * np.asarray(g_tilde) # w = wc * np.asarray(w_tilde) bcf_scale = np.pi / 2 * alpha * wc ** (1 - s) #+end_src #+RESULTS: ** BCF and Thermal BCF #+begin_src jupyter-python @dataclass class CauchyBCF: δ: float wc: float def I(self, ω): return np.sqrt(self.δ) / (self.δ + (ω - self.wc) ** 2 / self.δ) def __call__(self, τ): return np.sqrt(self.δ) * np.exp(-1j * self.wc * τ - np.abs(τ) * self.δ) def __bfkey__(self): return self.δ, self.wc α = bcf.OBCF(s=params.s, eta=1, gamma=params.wc) I = bcf.OSD(s=params.s, eta=1, gamma=params.wc) #+end_src #+RESULTS: *** Fit We now fit a sum of exponentials against the BCF. #+begin_src jupyter-python from lmfit import minimize, Parameters def α_apprx(τ, g, w): return np.sum( g[np.newaxis, :] * np.exp(-w[np.newaxis, :] * (τ[:, np.newaxis])), axis=1 ) def _fit(): def residual(fit_params, x, data): resid = 0 w = np.array([fit_params[f"w{i}"] for i in range(params.num_exp_t)]) + 1j * np.array( [fit_params[f"wi{i}"] for i in range(params.num_exp_t)] ) g = np.array([fit_params[f"g{i}"] for i in range(params.num_exp_t)]) + 1j * np.array( [fit_params[f"gi{i}"] for i in range(params.num_exp_t)] ) resid = data - α_apprx(x, g, w) return resid.view(float) fit_params = Parameters() for i in range(params.num_exp_t): fit_params.add(f"g{i}", value=.1) fit_params.add(f"gi{i}", value=.1) fit_params.add(f"w{i}", value=.1) fit_params.add(f"wi{i}", value=.1) ts = np.linspace(0, params.t_max, 1000) out = minimize(residual, fit_params, args=(ts, α(ts))) w = np.array([out.params[f"w{i}"] for i in range(params.num_exp_t)]) + 1j * np.array( [out.params[f"wi{i}"] for i in range(params.num_exp_t)] ) g = np.array([out.params[f"g{i}"] for i in range(params.num_exp_t)]) + 1j * np.array( [out.params[f"gi{i}"] for i in range(params.num_exp_t)] ) return w, g w, g = _fit() #+end_src #+RESULTS: *** Plot Let's look a the result. #+begin_src jupyter-python class bcfplt: t = np.linspace(0, params.t_max, 1000) ω = np.linspace(params.wc - 10, params.wc + 10, 1000) fig, axs = plt.subplots(2) axs[0].plot(t, np.real(α(t))) axs[0].plot(t, np.imag(α(t))) axs[0].plot(t, np.real(α_apprx(t, g, w))) axs[0].plot(t, np.imag(α_apprx(t, g, w))) axs[1].plot(ω, I(ω).real) axs[1].plot(ω, I(ω).imag) #+end_src #+RESULTS: [[file:./.ob-jupyter/8aef9360013cb6fc910354f4a0876034bbc0f184.png]] Seems ok for now. ** Hops setup #+begin_src jupyter-python HierachyParam = hierarchyData.HiP( k_max=params.k_max, # g_scale=None, # sample_method='random', seed=params.seed, nonlinear=False, normalized=False, # terminator=False, result_type=hierarchyData.RESULT_TYPE_ALL, # accum_only=None, # rand_skip=None ) #+end_src #+RESULTS: Integration. #+begin_src jupyter-python IntegrationParam = hierarchyData.IntP( t_max=params.t_max, t_steps=params.t_steps, # integrator_name='zvode', # atol=1e-8, # rtol=1e-8, # order=5, # nsteps=5000, # method='bdf', # t_steps_skip=1 ) #+end_src #+RESULTS: And now the system. #+begin_src jupyter-python SystemParam = hierarchyData.SysP( H_sys=params.H_s, L=params.L, psi0=params.ψ_0, # excited qubit g=np.array(g), w=np.array(w), H_dynamic=[], bcf_scale=params.bcf_scale, # some coupling strength (scaling of the fit parameters 'g_i') gw_hash=None, # this is used to load g,w from some database len_gw=len(g), ) #+end_src #+RESULTS: The quantum noise. #+begin_src jupyter-python Eta = StocProc_FFT( I, params.t_max, α, negative_frequencies=False, seed=params.seed, intgr_tol=1e-4, intpl_tol=1e-4, scale=params.bcf_scale, ) #+end_src #+RESULTS: #+begin_example stocproc.stocproc - INFO - non neg freq only stocproc.method_ft - INFO - get_dt_for_accurate_interpolation, please wait ... stocproc.method_ft - INFO - acc interp N 33 dt 6.25e-02 -> diff 1.08e-03 stocproc.method_ft - INFO - acc interp N 65 dt 3.12e-02 -> diff 2.69e-04 stocproc.method_ft - INFO - acc interp N 129 dt 1.56e-02 -> diff 6.71e-05 stocproc.method_ft - INFO - requires dt < 1.562e-02 stocproc.method_ft - INFO - get_N_a_b_for_accurate_fourier_integral, please wait ... stocproc.method_ft - INFO - J_w_min:1.00e-02 N 32 yields: interval [0.00e+00,6.47e+00] diff 9.83e-03 stocproc.method_ft - INFO - J_w_min:1.00e-03 N 32 yields: interval [0.00e+00,9.12e+00] diff 2.72e-03 stocproc.method_ft - INFO - J_w_min:1.00e-02 N 64 yields: interval [0.00e+00,6.47e+00] diff 1.11e-02 stocproc.method_ft - INFO - increasing N while shrinking the interval does lower the error -> try next level stocproc.method_ft - INFO - J_w_min:1.00e-04 N 32 yields: interval [0.00e+00,1.17e+01] diff 5.41e-03 stocproc.method_ft - INFO - J_w_min:1.00e-03 N 64 yields: interval [0.00e+00,9.12e+00] diff 5.54e-04 stocproc.method_ft - INFO - J_w_min:1.00e-02 N 128 yields: interval [0.00e+00,6.47e+00] diff 1.14e-02 stocproc.method_ft - INFO - increasing N while shrinking the interval does lower the error -> try next level stocproc.method_ft - INFO - J_w_min:1.00e-05 N 32 yields: interval [0.00e+00,1.42e+01] diff 8.13e-03 stocproc.method_ft - INFO - J_w_min:1.00e-04 N 64 yields: interval [0.00e+00,1.17e+01] diff 1.30e-03 stocproc.method_ft - INFO - J_w_min:1.00e-03 N 128 yields: interval [0.00e+00,9.12e+00] diff 8.98e-04 stocproc.method_ft - INFO - J_w_min:1.00e-02 N 256 yields: interval [0.00e+00,6.47e+00] diff 1.15e-02 stocproc.method_ft - INFO - increasing N while shrinking the interval does lower the error -> try next level stocproc.method_ft - INFO - J_w_min:1.00e-06 N 32 yields: interval [0.00e+00,1.66e+01] diff 1.11e-02 stocproc.method_ft - INFO - J_w_min:1.00e-05 N 64 yields: interval [0.00e+00,1.42e+01] diff 2.03e-03 stocproc.method_ft - INFO - J_w_min:1.00e-04 N 128 yields: interval [0.00e+00,1.17e+01] diff 2.69e-04 stocproc.method_ft - INFO - J_w_min:1.00e-03 N 256 yields: interval [0.00e+00,9.12e+00] diff 1.06e-03 stocproc.method_ft - INFO - increasing N while shrinking the interval does lower the error -> try next level stocproc.method_ft - INFO - J_w_min:1.00e-07 N 32 yields: interval [0.00e+00,1.91e+01] diff 1.48e-02 stocproc.method_ft - INFO - J_w_min:1.00e-06 N 64 yields: interval [0.00e+00,1.66e+01] diff 2.80e-03 stocproc.method_ft - INFO - J_w_min:1.00e-05 N 128 yields: interval [0.00e+00,1.42e+01] diff 5.04e-04 stocproc.method_ft - INFO - J_w_min:1.00e-04 N 256 yields: interval [0.00e+00,1.17e+01] diff 4.76e-05 stocproc.method_ft - INFO - return, cause tol of 0.0001 was reached stocproc.method_ft - INFO - requires dx < 4.557e-02 stocproc.stocproc - INFO - Fourier Integral Boundaries: [0.000e+00, 5.480e+02] stocproc.stocproc - INFO - Number of Nodes : 16384 stocproc.stocproc - INFO - yields dx : 3.345e-02 stocproc.stocproc - INFO - yields dt : 1.147e-02 stocproc.stocproc - INFO - yields t_max : 1.879e+02 #+end_example The sample trajectories are smooth. #+begin_src jupyter-python %%space plot ts = np.linspace(0, params.t_max, 1000) Eta.new_process() plt.plot(ts, Eta(ts).real) #+end_src #+RESULTS: :RESULTS: | | [[file:./.ob-jupyter/e263d6d8b8147ea9a2e498b427f567ba34a2b6a7.png]] :END: And now the thermal noise. #+begin_src jupyter-python EtaTherm = StocProc_FFT( spectral_density=bcf.OFTDens(s=params.s, eta=1, gamma=params.wc, beta=1 / params.T), t_max=params.t_max, alpha=bcf.OFTCorr(s=params.s, eta=1, gamma=params.wc, beta=1 / params.T), intgr_tol=1e-3, intpl_tol=1e-3, seed=params.seed, negative_frequencies=False, scale=params.bcf_scale, ) #+end_src #+RESULTS: #+begin_example stocproc.stocproc - INFO - non neg freq only stocproc.method_ft - INFO - get_dt_for_accurate_interpolation, please wait ... stocproc.method_ft - INFO - acc interp N 33 dt 6.25e-02 -> diff 2.21e-04 stocproc.method_ft - INFO - requires dt < 6.250e-02 stocproc.method_ft - INFO - get_N_a_b_for_accurate_fourier_integral, please wait ... stocproc.method_ft - INFO - J_w_min:1.00e-02 N 32 yields: interval [0.00e+00,4.18e+00] diff 9.38e-03 stocproc.method_ft - INFO - J_w_min:1.00e-03 N 32 yields: interval [0.00e+00,5.92e+00] diff 4.42e-03 stocproc.method_ft - INFO - J_w_min:1.00e-02 N 64 yields: interval [0.00e+00,4.18e+00] diff 8.00e-03 stocproc.method_ft - INFO - increasing N while shrinking the interval does lower the error -> try next level stocproc.method_ft - INFO - J_w_min:1.00e-04 N 32 yields: interval [0.00e+00,7.62e+00] diff 7.37e-03 stocproc.method_ft - INFO - J_w_min:1.00e-03 N 64 yields: interval [0.00e+00,5.92e+00] diff 1.66e-03 stocproc.method_ft - INFO - J_w_min:1.00e-02 N 128 yields: interval [0.00e+00,4.18e+00] diff 7.66e-03 stocproc.method_ft - INFO - increasing N while shrinking the interval does lower the error -> try next level stocproc.method_ft - INFO - J_w_min:1.00e-05 N 32 yields: interval [0.00e+00,9.30e+00] diff 1.04e-02 stocproc.method_ft - INFO - J_w_min:1.00e-04 N 64 yields: interval [0.00e+00,7.62e+00] diff 1.87e-03 stocproc.method_ft - INFO - J_w_min:1.00e-03 N 128 yields: interval [0.00e+00,5.92e+00] diff 9.72e-04 stocproc.method_ft - INFO - return, cause tol of 0.001 was reached stocproc.method_ft - INFO - requires dx < 4.622e-02 stocproc.stocproc - INFO - Fourier Integral Boundaries: [0.000e+00, 1.380e+02] stocproc.stocproc - INFO - Number of Nodes : 4096 stocproc.stocproc - INFO - yields dx : 3.368e-02 stocproc.stocproc - INFO - yields dt : 4.555e-02 stocproc.stocproc - INFO - yields t_max : 1.865e+02 #+end_example The sample trajectories are smooth too. #+begin_src jupyter-python %%space plot ts = np.linspace(0, params.t_max, 1000) EtaTherm.new_process() plt.plot(ts, EtaTherm(ts).real) #+end_src #+RESULTS: :RESULTS: | | [[file:./.ob-jupyter/fa5c945d8f37080bcad16c6fda2ebe4221da87ae.png]] :END: * Actual Hops Generate the key for binary caching. #+begin_src jupyter-python hi_key = hierarchyData.HIMetaKey_type( HiP=HierachyParam, IntP=IntegrationParam, SysP=SystemParam, Eta=Eta, EtaTherm=None, ) #+end_src #+RESULTS: Initialize Hierarchy. #+begin_src jupyter-python myHierarchy = hierarchyLib.HI(hi_key, number_of_samples=params.N, desc="calculate the heat flow") #+end_src #+RESULTS: : init Hi class, use 112 equation : /home/hiro/Documents/Projects/UNI/master/masterarb/python/richard_hops/hierarchyLib.py:1058: UserWarning: sum_k_max is not implemented! DO SO BEFORE NEXT USAGE (use simplex).HierarchyParametersType does not yet know about sum_k_max : warnings.warn( Run the integration. #+begin_src jupyter-python myHierarchy.integrate_simple(data_name="energy_flow_therm_new_lin.data") #+end_src #+RESULTS: : (10, 100, 56) : samples :0.0% : integration :0.0% : samples : 100% : integration :0.0% :  Get the samples. #+BEGIN_SRC jupyter-python # to access the data the 'hi_key' is used to find the data in the hdf5 file class int_result: with hierarchyData.HIMetaData( hid_name="energy_flow_therm_new_lin.data", hid_path="." ) as metaData: with metaData.get_HIData(hi_key, read_only=True) as data: smp = data.get_samples() print("{} samples found in database".format(smp)) τ = data.get_time() rho_τ = data.get_rho_t() s_proc = np.array(data.stoc_proc) states = np.array(data.aux_states).copy() ψ_1 = np.array(data.aux_states)[:, :, 0 : params.num_exp_t * params.dim] ψ_0 = np.array(data.stoc_traj) y = np.array(data.y) η = np.array(data.stoc_proc) #+end_src #+RESULTS: : 17 samples found in database Calculate energy. #+begin_src jupyter-python %matplotlib inline energy = np.array([np.trace(ρ @ params.H_s).real for ρ in int_result.rho_τ]) plt.plot(int_result.τ, energy) #+end_src #+RESULTS: :RESULTS: | | [[file:./.ob-jupyter/f17cfebfc5e7c505b28a2ffe32c89e50dd078f1e.png]] :END: * Energy Flow :PROPERTIES: :ID: 2872b2db-5d3d-470d-8c35-94aca6925f14 :END: #+begin_src jupyter-python int_result.ψ_1.shape #+end_src #+RESULTS: | 5120 | 400 | 10 | Let's look at the norm. #+begin_src jupyter-python plt.plot(int_result.τ, (int_result.ψ_0[0].conj() * int_result.ψ_0[0]).sum(axis=1).real) #+end_src #+RESULTS: :RESULTS: | | [[file:./.ob-jupyter/a304334c140a84b7983154f8ff9237ff343cf7bf.png]] :END: And try to calculate the energy flow. #+begin_src jupyter-python def flow_for_traj(ψ_0, ψ_1): a = np.array((params.L @ ψ_0.T).T) ψ_1 = (-w * g * params.bcf_scale)[None, :, None] * ψ_1.reshape( params.t_steps, params.num_exp_t, params.dim ) # return np.array(np.sum(ψ_0.conj() * ψ_0, axis=1)).flatten().real return np.array( 2 ,* ( 1j ,* np.sum(a.conj()[:, None, :] * ψ_1, axis=(1, 2)) ).real ).flatten() def flow_for_traj_alt(ψ_0, y): Eta.new_process(y) eta_dot = scipy.misc.derivative(Eta, int_result.τ, dx=1e-5, order=5) a = np.array((params.L @ ψ_0.T).T) return np.array( 2 ,* ( -1j * eta_dot.conj() ,* np.sum(ψ_0.conj() * a, axis=1) ).real ).flatten() #+end_src #+RESULTS: Now we calculate the average over all trajectories. #+begin_src jupyter-python class Flow: j = np.zeros_like(int_result.τ) for i in range(0, params.N): j += flow_for_traj(int_result.ψ_0[i], int_result.ψ_1[i]) j /= params.N #+end_src #+RESULTS: And do the same with the alternative implementation. #+begin_src jupyter-python class Flow_Alt: j = np.zeros_like(int_result.τ) for i in range(0, params.N): j += flow_for_traj_alt(int_result.ψ_0[i], int_result.y[i]) j /= params.N #+end_src #+RESULTS: And plot it :). We see: it also works with the derivative. #+begin_src jupyter-python %matplotlib inline plt.plot(int_result.τ, Flow.j) plt.plot(int_result.τ, Flow_Alt.j) plt.show() #+end_src #+RESULTS: [[file:./.ob-jupyter/e643a7b7a9b7b83eef79e50c8a9ba408cce1a7fb.png]] Let's calculate the integrated energy. #+begin_src jupyter-python E_t = np.array( [0] + [ scipy.integrate.simpson(Flow.j[0:n], int_result.τ[0:n]) for n in range(1, len(int_result.τ)) ] ) print(E_t[-1]) E_t = E_t / E_t[-1] * 2 #+end_src #+RESULTS: : 1.8046657496034806 With this we can retrieve the energy of the interaction Hamiltonian. #+begin_src jupyter-python E_I = 2 - energy - E_t #+end_src #+RESULTS: #+begin_src jupyter-python %%space plot plt.rcParams['figure.figsize'] = [15, 10] #plt.plot(τ, j, label="$J$", linestyle='--') plt.plot(int_result.τ, E_t, label=r"$\langle H_{\mathrm{B}}\rangle$") plt.plot(int_result.τ, E_I, label=r"$\langle H_{\mathrm{I}}\rangle$") plt.plot(int_result.τ, energy, label=r"$\langle H_{\mathrm{S}}\rangle$") plt.xlabel("τ") plt.legend() plt.show() #+end_src #+RESULTS: :RESULTS: | | | | | | : Text(0.5, 0, 'τ') : [[file:./.ob-jupyter/6de8a07c7bb8568fb4dd92a33321f5d670f90378.png]] :END: * System + Interaction Energy #+begin_src jupyter-python def h_si_for_traj(ψ_0, ψ_1): a = np.array((params.L @ ψ_0.T).T) b = np.array((params.H_s @ ψ_0.T).T) ψ_1 = (g*params.bcf_scale)[None, :, None] * ψ_1.reshape( params.t_steps, params.num_exp_t, params.dim ) E_i = np.array( 2 ,* ( -1j ,* np.sum( a.conj()[:, None, :] ,* ψ_1, axis=(1, 2), ) ).real ).flatten() E_s = np.array(np.sum(b.conj() * ψ_0, axis=1)).flatten().real return (E_i + E_s) def h_si_for_traj_alt(ψ_0, y): Eta.new_process(y) a = np.array((params.L @ ψ_0.T).T) b = np.array((params.H_s @ ψ_0.T).T) E_i = np.array( 2 ,* ( -1j * Eta(int_result.τ).conj() ,* np.sum( a ,* ψ_0.conj(), axis=1, ) ).real ).flatten() E_s = np.array(np.sum(b.conj() * ψ_0, axis=1)).flatten().real return (E_i + E_s) #+end_src #+RESULTS: #+begin_src jupyter-python e_si = np.zeros_like(int_result.τ) e_si_alt = np.zeros_like(int_result.τ) for i in range(0, params.N): e_si += h_si_for_traj(int_result.ψ_0[i], int_result.ψ_1[i]) e_si_alt += h_si_for_traj_alt(int_result.ψ_0[i], int_result.y[i]) e_si /= params.N e_si_alt /= params.N #+end_src #+RESULTS: Not too bad... #+begin_src jupyter-python plt.plot(int_result.τ, e_si, label=r"with $\psi^{1}$") plt.plot(int_result.τ, e_si_alt, label=r"with $\dot{\eta}$") plt.plot(int_result.τ, E_I + energy, label=r"from $J$") plt.legend() #+end_src #+RESULTS: :RESULTS: : [[file:./.ob-jupyter/14aebc12e53e92f378f287b4e7ca08af78cf7dd4.png]] :END: