master-thesis/python/graveyard/richard_hops/energy_flow_thermal.org

20 KiB
Raw Blame History

Setup

Jupyter

  %load_ext autoreload
  %autoreload 2
  %load_ext jupyter_spaces
The autoreload extension is already loaded. To reload it, use:
  %reload_ext autoreload
The jupyter_spaces extension is already loaded. To reload it, use:
  %reload_ext jupyter_spaces

Matplotlib

  import matplotlib
  import matplotlib.pyplot as plt

  #matplotlib.use("TkCairo", force=True)
  %gui tk
  %matplotlib inline
  plt.style.use('ggplot')

Richard (old) HOPS

  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

Auxiliary Definitions

  σ1 = np.matrix([[0,1],[1,0]])
  σ2 = np.matrix([[0,-1j],[1j,0]])
  σ3 = np.matrix([[1,0],[0,-1]])

Model Setup

Basic parameters.

  class params:
      T = 2

      t_max = 2
      t_steps = int(t_max * 1/.001)
      k_max = 10
      N = 4000

      seed = 100
      dim = 2
      H_s = σ3 + np.eye(dim)
      L = σ2 #1 / 2 * (σ1 - 1j * σ2)
      ψ_0 = np.array([0, 1])

      s = 1
      num_exp_t = 4

      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)

BCF and Thermal BCF

  @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)

Fit

We now fit a sum of exponentials against the BCF.

  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()

Plot

Let's look a the result.

  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)

/hiro/master-thesis/media/commit/8c2f1ac3775148eeb7e9842c198ddb28e700725b/python/graveyard/richard_hops/.ob-jupyter/94716da4c1c533b5ae91de94ef8e00707e7da233.png

Seems ok for now.

Hops setup

  HierachyParam = hierarchyData.HiP(
      k_max=params.k_max,
      # g_scale=None,
      # sample_method='random',
      seed=params.seed,
      nonlinear=True,
      normalized=False,
      # terminator=False,
      result_type=hierarchyData.RESULT_TYPE_ALL,
      # accum_only=None,
      # rand_skip=None
  )

Integration.

  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
  )

And now the system.

  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),
  )

The quantum noise.

  Eta = StocProc_FFT(
      I,
      params.t_max,
      α,
      negative_frequencies=False,
      seed=params.seed,
      intgr_tol=1e-3,
      intpl_tol=1e-3,
      scale=params.bcf_scale,
  )
  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 1.25e-01 -> diff 4.49e-03
  stocproc.method_ft - INFO - acc interp N 65 dt 6.25e-02 -> diff 1.08e-03
  stocproc.method_ft - INFO - acc interp N 129 dt 3.12e-02 -> diff 2.69e-04
  stocproc.method_ft - INFO - requires dt < 3.125e-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 3.11e-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.62e-03
  stocproc.method_ft - INFO - J_w_min:1.00e-03 N 64 yields: interval [0.00e+00,9.12e+00] diff 7.23e-04
  stocproc.method_ft - INFO - return, cause tol of 0.001 was reached
  stocproc.method_ft - INFO - requires dx < 1.425e-01
  stocproc.stocproc - INFO - Fourier Integral Boundaries: [0.000e+00, 2.422e+02]
  stocproc.stocproc - INFO - Number of Nodes            : 2048
  stocproc.stocproc - INFO - yields dx                  : 1.183e-01
  stocproc.stocproc - INFO - yields dt                  : 2.594e-02
  stocproc.stocproc - INFO - yields t_max               : 5.310e+01

The sample trajectories are smooth.

  %%space plot
  ts = np.linspace(0, params.t_max, 1000)
  Eta.new_process()
  plt.plot(ts, Eta(ts).real)
<matplotlib.lines.Line2D at 0x7f6809bb80a0>

/hiro/master-thesis/media/commit/8c2f1ac3775148eeb7e9842c198ddb28e700725b/python/graveyard/richard_hops/.ob-jupyter/4e525ff2fa6e494fb3abab758809f3f335b7cf0e.png

And now the thermal noise.

  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,
  )
  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 1.25e-01 -> diff 8.75e-04
  stocproc.method_ft - INFO - requires dt < 1.250e-01
  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.10e+00] diff 9.15e-03
  stocproc.method_ft - INFO - J_w_min:1.00e-03 N 32 yields: interval [0.00e+00,5.82e+00] diff 4.69e-03
  stocproc.method_ft - INFO - J_w_min:1.00e-02 N 64 yields: interval [0.00e+00,4.10e+00] diff 7.88e-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.50e+00] diff 9.58e-03
  stocproc.method_ft - INFO - J_w_min:1.00e-03 N 64 yields: interval [0.00e+00,5.82e+00] diff 1.59e-03
  stocproc.method_ft - INFO - J_w_min:1.00e-02 N 128 yields: interval [0.00e+00,4.10e+00] diff 7.56e-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.16e+00] diff 1.27e-02
  stocproc.method_ft - INFO - J_w_min:1.00e-04 N 64 yields: interval [0.00e+00,7.50e+00] diff 2.38e-03
  stocproc.method_ft - INFO - J_w_min:1.00e-03 N 128 yields: interval [0.00e+00,5.82e+00] diff 9.47e-04
  stocproc.method_ft - INFO - return, cause tol of 0.001 was reached
  stocproc.method_ft - INFO - requires dx < 4.544e-02
  stocproc.stocproc - INFO - Fourier Integral Boundaries: [0.000e+00, 6.839e+01]
  stocproc.stocproc - INFO - Number of Nodes            : 2048
  stocproc.stocproc - INFO - yields dx                  : 3.340e-02
  stocproc.stocproc - INFO - yields dt                  : 9.187e-02
  stocproc.stocproc - INFO - yields t_max               : 1.881e+02

The sample trajectories are smooth too.

  %%space plot
  ts = np.linspace(0, params.t_max, 1000)
  EtaTherm.new_process()
  plt.plot(ts, EtaTherm(ts).real)
<matplotlib.lines.Line2D at 0x7f68499d1cd0>

/hiro/master-thesis/media/commit/8c2f1ac3775148eeb7e9842c198ddb28e700725b/python/graveyard/richard_hops/.ob-jupyter/7c2fb11537e9382b65fdbc4225025dce060892b9.png

Actual Hops

Generate the key for binary caching.

  hi_key = hierarchyData.HIMetaKey_type(
      HiP=HierachyParam,
      IntP=IntegrationParam,
      SysP=SystemParam,
      Eta=Eta,
      EtaTherm=EtaTherm,
  )

Initialize Hierarchy.

  myHierarchy = hierarchyLib.HI(hi_key, number_of_samples=params.N, desc="calculate the heat flow")
/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(
init Hi class, use 2002 equation

Run the integration.

  myHierarchy.integrate_simple(data_path="data", data_name="energy_flow_therm_new_again_less.data")
  samples     :[TET 5.52ms     [0.0c/s] TTG --         0.0%         ETA -- ORT --]
  integration :[TET 5.32ms     [0.0c/s] TTG --         0.0%         ETA -- ORT --]
  samples     :[E-2.01s---[428.3c/s] G 8.00s 21.5% A 20211104_10:14:07 O 00:00:10]
  integration :[TET 7.05ms     [0.0c/s] TTG --         0.0%         ETA -- ORT --]
  samples     :[E-4.01s---[451.3c/s]-G-5.00s->45.2%   A 20211104_10:14:06 O 9.01s]
  integration :[TET 19.33ms     [0.0c/s] TTG --        0.0%         ETA -- ORT --]
  samples     :[E-6.01s---[455.7c/s]-G-3.00s--68.5%---A-20211104_10:14:06 O 9.01s]
  integration :[TET 27.20ms     [0.0c/s] TTG --        0.0%         ETA -- ORT --]
  samples     :[E-8.02s---[456.6c/s]-G-1.00s--91.5%---A-20211104_10:14:06-O>9.02s]
  integration :[TET 19.95ms     [0.0c/s] TTG --        0.0%         ETA -- ORT --]
  samples     :[E-8.75s---[457.4c/s]-G-0.00ms--100%---A-20211104_10:14:06-O-8.75s]
  integration :[TET 4.00ms     [0.0c/s] TTG --         0.0%         ETA -- ORT --]
  

Get the samples.

  # 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_again_less.data", hid_path="data"
      ) 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)
              temp_y = np.array(data.temp_y)
4000 samples found in database

Calculate energy.

  %matplotlib inline
  energy = np.einsum("ijk,kj", int_result.rho_τ,params.H_s).real
  plt.plot(int_result.τ, energy)
<matplotlib.lines.Line2D at 0x7f68497db4f0>

/hiro/master-thesis/media/commit/8c2f1ac3775148eeb7e9842c198ddb28e700725b/python/graveyard/richard_hops/.ob-jupyter/b02f05ff976469eb5f86581f73e361ba4169d4ee.png

Energy Flow

  int_result.ψ_1.shape
5120 2000 8

Let's look at the norm.

  plt.plot(int_result.τ, (int_result.ψ_0[0].conj() * int_result.ψ_0[0]).sum(axis=1).real)
<matplotlib.lines.Line2D at 0x7f68497580d0>

/hiro/master-thesis/media/commit/8c2f1ac3775148eeb7e9842c198ddb28e700725b/python/graveyard/richard_hops/.ob-jupyter/89c2992c07948ad101e60c83c395c1767e351af7.png

And try to calculate the energy flow.

  def flow_for_traj(ψ_0, ψ_1, temp_y):
      a = np.array((params.L @ ψ_0.T).T)
      b = np.array(((params.L @ params.H_s - params.H_s @ params.L) @ ψ_0.T).T)
      EtaTherm.new_process(temp_y)
      η_dot = scipy.misc.derivative(EtaTherm, int_result.τ, dx=1e-3, order=3)
      ψ_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
      j_0 = np.array(
          2
          ,* (
              1j
              ,* (np.sum(a.conj()[:, None, :] * ψ_1, axis=(1, 2)))
              / np.sum(ψ_0.conj() * ψ_0, axis=1)
          ).real
      ).flatten()

      j_therm = -np.array(
          2
          ,* (
              (np.sum(a.conj() * ψ_0, axis=1)) * η_dot / np.sum(ψ_0.conj() * ψ_0, axis=1)
          ).real
      ).flatten()

      shift_energy = (
          2
          ,* (
              EtaTherm(int_result.τ)
              ,* np.sum(a.conj() * ψ_0, axis=1)
              / np.sum(ψ_0.conj() * ψ_0, axis=1)
          ).real
      ).flatten()

      shift_energy_normal = (
          2
          ,* (1j *
             EtaTherm(int_result.τ) *
              (np.sum(b.conj() * ψ_0, axis=1))
              / np.sum(ψ_0.conj() * ψ_0, axis=1)
          ).real
      ).flatten()

      j_therm_alt = np.gradient(shift_energy, int_result.τ, edge_order=2)
      return j_0, j_therm, j_therm_alt + shift_energy_normal

Now we calculate the average over all trajectories.

  class Flow:
      j_0 = np.zeros_like(int_result.τ)
      j_therm = np.zeros_like(int_result.τ)
      j_therm_alt = np.zeros_like(int_result.τ)
      for i in range(0, params.N):
          dj, dj_therm, dj_therm_alt = flow_for_traj(
              int_result.ψ_0[i], int_result.ψ_1[i], int_result.temp_y[i]
          )

          j_0 += dj
          j_therm += dj_therm
          j_therm_alt += dj_therm_alt
      j_0 /= params.N
      j_therm /= params.N
      j_therm_alt /= params.N
      j = j_0 + j_therm

And plot it :).

  %matplotlib inline
  plt.plot(int_result.τ, Flow.j_0, label=r"$j_0$")
  plt.plot(int_result.τ, Flow.j_therm, label=r"$j_\mathrm{therm}$")
  plt.plot(int_result.τ, Flow.j_therm_alt, label=r"$j_\mathrm{therm}^\mathrm{alt}$")
  plt.plot(int_result.τ, Flow.j, label=r"$j$")
  plt.legend()
<matplotlib.legend.Legend at 0x7f68496cda30>

/hiro/master-thesis/media/commit/8c2f1ac3775148eeb7e9842c198ddb28e700725b/python/graveyard/richard_hops/.ob-jupyter/a11b670c1a122ed76028d9bd56c9ff33d49f4521.png

Let's calculate the integrated energy.

  E_t = np.array(
      [0]
      + [
          scipy.integrate.simpson(Flow.j[0:n], int_result.τ[0:n])
          for n in range(1, len(int_result.τ))
      ]
  )
  E_t[-1]
0.1557882146641204

With this we can retrieve the energy of the interaction Hamiltonian.

  E_I = - energy - E_t
  %%space plot
  #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()
<matplotlib.lines.Line2D at 0x7f68495ca970>
<matplotlib.lines.Line2D at 0x7f68495cad60>
<matplotlib.lines.Line2D at 0x7f6849572190>
Text(0.5, 0, 'τ')
<matplotlib.legend.Legend at 0x7f68495cabb0>

/hiro/master-thesis/media/commit/8c2f1ac3775148eeb7e9842c198ddb28e700725b/python/graveyard/richard_hops/.ob-jupyter/4019e2cde4e898f0a3174476803a78debd331d90.png

System + Interaction Energy

  def h_si_for_traj(ψ_0, ψ_1, temp_y):
      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
      )
      EtaTherm.new_process(temp_y)

      E_i = np.array(
          2
          ,* (
              -1j
              ,* np.sum(
                  a.conj()[:, None, :]
                  ,* ψ_1,
                  axis=(1, 2),
              )
          ).real
      ).flatten()

      E_i += np.array(
          2
          ,* (
              EtaTherm(int_result.τ)
              ,* np.sum(
                  a.conj()
                  ,* ψ_0,
                  axis=1,
              )
          ).real
      ).flatten()

      E_s = np.array(np.sum(b.conj() * ψ_0, axis=1)).flatten().real

      return (E_i + E_s * 0) / np.sum(ψ_0.conj() * ψ_0, axis=1).real
  e_si = 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], int_result.temp_y[i])
  e_si /= params.N

Doesn't work out.

  plt.plot(int_result.τ, e_si, label=r"direct")
  plt.plot(int_result.τ, E_I)
  plt.legend()
<matplotlib.legend.Legend at 0x7f68494a4e80>

/hiro/master-thesis/media/commit/8c2f1ac3775148eeb7e9842c198ddb28e700725b/python/graveyard/richard_hops/.ob-jupyter/7b84ba5527e25086a3b332b30c87a195c3e767c0.png