2021-10-15 16:18:03 +02:00
|
|
|
import combLib
|
|
|
|
from functools import namedtuple
|
|
|
|
import h5py
|
|
|
|
import hashlib
|
|
|
|
import logging
|
|
|
|
import numpy as np
|
|
|
|
import os
|
|
|
|
import random
|
|
|
|
import signalDelay
|
|
|
|
import signal
|
|
|
|
import subprocess
|
|
|
|
import sqlitedict as sqd
|
|
|
|
import warnings
|
|
|
|
import shutil
|
|
|
|
|
|
|
|
import binfootprint as bf
|
|
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
2021-10-18 18:40:50 +02:00
|
|
|
HIMetaKey_type = namedtuple(
|
|
|
|
"HIMetaKey_type", ["HiP", "IntP", "SysP", "Eta", "EtaTherm"]
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
|
2021-10-18 18:40:50 +02:00
|
|
|
RESULT_TYPE_ZEROTH_ORDER_ONLY = "ZEROTH_ORDER_ONLY"
|
|
|
|
RESULT_TYPE_ZEROTH_ORDER_AND_ETA_LAMBDA = "ZEROTH_ORDER_AND_ETA_LAMBDA"
|
|
|
|
RESULT_TYPE_ALL = "ALL"
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
CHAR_SET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
|
|
|
|
|
|
|
|
def projector_psi_t(psi_t, normed=False):
|
|
|
|
"""
|
2021-10-18 18:40:50 +02:00
|
|
|
assume shape (len(t), dim_H_sys)
|
2021-10-15 16:18:03 +02:00
|
|
|
"""
|
|
|
|
psi_t_col = np.expand_dims(psi_t, axis=2)
|
|
|
|
psi_t_row = np.expand_dims(psi_t, axis=1)
|
|
|
|
|
|
|
|
if normed:
|
|
|
|
N = np.sum(np.conj(psi_t) * psi_t, axis=1).reshape(psi_t.shape[0], 1, 1)
|
|
|
|
return (psi_t_col * np.conj(psi_t_row)) / N
|
|
|
|
else:
|
2021-10-18 18:40:50 +02:00
|
|
|
return psi_t_col * np.conj(psi_t_row)
|
|
|
|
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
class HiP(object):
|
|
|
|
"""
|
2021-10-18 18:40:50 +02:00
|
|
|
a purely readable (non binary) data object
|
2021-10-15 16:18:03 +02:00
|
|
|
"""
|
2021-10-18 18:40:50 +02:00
|
|
|
|
|
|
|
__slots__ = [
|
|
|
|
"k_max",
|
|
|
|
"g_scale",
|
|
|
|
"sample_method",
|
|
|
|
"seed",
|
|
|
|
"nonlinear",
|
|
|
|
"normalized",
|
|
|
|
"terminator",
|
|
|
|
"result_type",
|
|
|
|
"accum_only",
|
|
|
|
"rand_skip",
|
|
|
|
]
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
k_max,
|
|
|
|
g_scale=None,
|
|
|
|
sample_method="random",
|
|
|
|
seed=0,
|
|
|
|
nonlinear=True,
|
|
|
|
normalized=False,
|
|
|
|
terminator=False,
|
|
|
|
result_type=RESULT_TYPE_ZEROTH_ORDER_ONLY,
|
|
|
|
accum_only=None,
|
|
|
|
rand_skip=None,
|
|
|
|
):
|
2021-10-15 16:18:03 +02:00
|
|
|
self.k_max = k_max
|
|
|
|
self.g_scale = g_scale
|
|
|
|
self.sample_method = sample_method
|
|
|
|
self.seed = seed
|
|
|
|
self.nonlinear = nonlinear
|
|
|
|
self.normalized = normalized
|
|
|
|
self.terminator = terminator
|
|
|
|
self.result_type = result_type
|
|
|
|
self.accum_only = accum_only
|
|
|
|
self.rand_skip = rand_skip
|
|
|
|
if accum_only is None:
|
|
|
|
if self.rand_skip is not None:
|
2021-10-18 18:40:50 +02:00
|
|
|
raise ValueError(
|
|
|
|
"if accum_only is 'None' (not set) rand_skip must also be 'None'"
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
def __bfkey__(self):
|
|
|
|
if self.accum_only is None:
|
|
|
|
if self.rand_skip is not None:
|
2021-10-18 18:40:50 +02:00
|
|
|
raise ValueError(
|
|
|
|
"if accum_only is 'None' (not set) rand_skip must also be 'None'"
|
|
|
|
)
|
|
|
|
return [
|
|
|
|
self.k_max,
|
|
|
|
self.g_scale,
|
|
|
|
self.sample_method,
|
|
|
|
self.seed,
|
|
|
|
self.nonlinear,
|
|
|
|
self.normalized,
|
|
|
|
self.terminator,
|
|
|
|
self.result_type,
|
|
|
|
]
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
if self.rand_skip is None:
|
2021-10-18 18:40:50 +02:00
|
|
|
return [
|
|
|
|
self.k_max,
|
|
|
|
self.g_scale,
|
|
|
|
self.sample_method,
|
|
|
|
self.seed,
|
|
|
|
self.nonlinear,
|
|
|
|
self.normalized,
|
|
|
|
self.terminator,
|
|
|
|
self.result_type,
|
|
|
|
self.accum_only,
|
|
|
|
]
|
|
|
|
|
|
|
|
return [
|
|
|
|
self.k_max,
|
|
|
|
self.g_scale,
|
|
|
|
self.sample_method,
|
|
|
|
self.seed,
|
|
|
|
self.nonlinear,
|
|
|
|
self.normalized,
|
|
|
|
self.terminator,
|
|
|
|
self.result_type,
|
|
|
|
self.accum_only,
|
|
|
|
self.rand_skip,
|
|
|
|
]
|
2021-10-15 16:18:03 +02:00
|
|
|
|
2021-10-18 18:40:50 +02:00
|
|
|
def __repr__(self):
|
|
|
|
return (
|
|
|
|
"k_max : {}\n".format(self.k_max)
|
|
|
|
+ "g_scale : {}\n".format(self.g_scale)
|
|
|
|
+ "sample_method: {}\n".format(self.sample_method)
|
|
|
|
+ "seed : {}\n".format(self.seed)
|
|
|
|
+ "nonlinear : {}\n".format(self.nonlinear)
|
|
|
|
+ "normalized : {}\n".format(self.normalized)
|
|
|
|
+ "terminator : {}\n".format(self.terminator)
|
|
|
|
+ "result_type : {}\n".format(self.result_type)
|
|
|
|
+ "accum_only : {}\n".format(self.accum_only)
|
|
|
|
+ "rand_skip : {}\n".format(self.rand_skip)
|
|
|
|
+ ""
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
|
|
|
|
class IntP(object):
|
|
|
|
"""
|
2021-10-18 18:40:50 +02:00
|
|
|
a purely readable (non binary) data object
|
2021-10-15 16:18:03 +02:00
|
|
|
"""
|
2021-10-18 18:40:50 +02:00
|
|
|
|
|
|
|
__slots__ = [
|
|
|
|
"t_max",
|
|
|
|
"t_steps",
|
|
|
|
"integrator_name",
|
|
|
|
"atol",
|
|
|
|
"rtol",
|
|
|
|
"order",
|
|
|
|
"nsteps",
|
|
|
|
"method",
|
|
|
|
"t_steps_skip",
|
|
|
|
]
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
t_max,
|
|
|
|
t_steps,
|
|
|
|
integrator_name="zvode",
|
|
|
|
atol=1e-8,
|
|
|
|
rtol=1e-8,
|
|
|
|
order=5,
|
|
|
|
nsteps=5000,
|
|
|
|
method="bdf",
|
|
|
|
t_steps_skip=1,
|
|
|
|
):
|
2021-10-15 16:18:03 +02:00
|
|
|
self.t_max = t_max
|
|
|
|
self.t_steps = t_steps
|
|
|
|
self.integrator_name = integrator_name
|
|
|
|
self.atol = atol
|
|
|
|
self.rtol = rtol
|
|
|
|
self.order = order
|
|
|
|
self.nsteps = nsteps
|
|
|
|
self.method = method
|
|
|
|
self.t_steps_skip = t_steps_skip
|
|
|
|
|
|
|
|
def __bfkey__(self):
|
|
|
|
if self.t_steps_skip == 1:
|
2021-10-18 18:40:50 +02:00
|
|
|
return [
|
|
|
|
self.t_max,
|
|
|
|
self.t_steps,
|
|
|
|
self.integrator_name,
|
|
|
|
self.atol,
|
|
|
|
self.rtol,
|
|
|
|
self.order,
|
|
|
|
self.nsteps,
|
|
|
|
self.method,
|
|
|
|
]
|
2021-10-15 16:18:03 +02:00
|
|
|
else:
|
2021-10-18 18:40:50 +02:00
|
|
|
return [
|
|
|
|
self.t_max,
|
|
|
|
self.t_steps,
|
|
|
|
self.integrator_name,
|
|
|
|
self.atol,
|
|
|
|
self.rtol,
|
|
|
|
self.order,
|
|
|
|
self.nsteps,
|
|
|
|
self.method,
|
|
|
|
self.t_steps_skip,
|
|
|
|
]
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
def __repr__(self):
|
2021-10-18 18:40:50 +02:00
|
|
|
return (
|
|
|
|
"t_max : {}\n".format(self.t_max)
|
|
|
|
+ "t_steps : {}\n".format(self.t_steps)
|
|
|
|
+ "integrator_name: {}\n".format(self.integrator_name)
|
|
|
|
+ "atol : {}\n".format(self.atol)
|
|
|
|
+ "rtol : {}\n".format(self.rtol)
|
|
|
|
+ "order : {}\n".format(self.order)
|
|
|
|
+ "nsteps : {}\n".format(self.nsteps)
|
|
|
|
+ "method : {}\n".format(self.method)
|
|
|
|
+ "t_steps_skip : {}\n".format(self.t_steps_skip)
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
|
2021-10-18 18:40:50 +02:00
|
|
|
class SysP(object):
|
|
|
|
__slots__ = [
|
|
|
|
"H_sys",
|
|
|
|
"L",
|
|
|
|
"psi0",
|
|
|
|
"g",
|
|
|
|
"w",
|
|
|
|
"H_dynamic",
|
|
|
|
"bcf_scale",
|
|
|
|
"gw_hash",
|
|
|
|
"len_gw",
|
|
|
|
"gw_info",
|
|
|
|
"T",
|
|
|
|
"T_method",
|
|
|
|
]
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
H_sys,
|
|
|
|
L,
|
|
|
|
psi0,
|
|
|
|
g,
|
|
|
|
w,
|
|
|
|
H_dynamic,
|
|
|
|
bcf_scale,
|
|
|
|
gw_hash,
|
|
|
|
len_gw,
|
|
|
|
gw_info=None, # these are only info fields
|
|
|
|
T=None, # which do not enter the key
|
|
|
|
T_method=None,
|
|
|
|
): # as T is included either in g/w or in EtaTherm
|
2021-10-15 16:18:03 +02:00
|
|
|
self.H_sys = H_sys
|
|
|
|
self.L = L
|
|
|
|
self.psi0 = psi0
|
|
|
|
self.g = g
|
|
|
|
self.w = w
|
|
|
|
self.H_dynamic = H_dynamic
|
|
|
|
self.bcf_scale = bcf_scale
|
|
|
|
self.gw_hash = gw_hash
|
|
|
|
self.len_gw = len_gw
|
|
|
|
self.gw_info = gw_info
|
|
|
|
self.T = T
|
|
|
|
self.T_method = T_method
|
|
|
|
|
2021-10-18 18:40:50 +02:00
|
|
|
if (self.gw_hash is None) and ((self.g is None) or (self.w is None)):
|
2021-10-15 16:18:03 +02:00
|
|
|
raise ValueError("specify either g/w or gw_hash")
|
|
|
|
|
|
|
|
def __bfkey__(self):
|
2021-10-18 18:40:50 +02:00
|
|
|
return [
|
|
|
|
self.H_sys,
|
|
|
|
self.L,
|
|
|
|
self.psi0,
|
|
|
|
self.g,
|
|
|
|
self.w,
|
|
|
|
self.H_dynamic,
|
|
|
|
self.bcf_scale,
|
|
|
|
self.gw_hash,
|
|
|
|
]
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
def __repr__(self):
|
2021-10-18 18:40:50 +02:00
|
|
|
return (
|
|
|
|
"H_sys : {}\n".format(self.H_sys)
|
|
|
|
+ "L : {}\n".format(self.L)
|
|
|
|
+ "psi0 : {}\n".format(self.psi0)
|
|
|
|
+ "g : {}\n".format(self.g)
|
|
|
|
+ "w : {}\n".format(self.w)
|
|
|
|
+ "H_dynamic: {}\n".format(self.H_dynamic)
|
|
|
|
+ "bcf_scale: {}\n".format(self.bcf_scale)
|
|
|
|
+ "gw_hash : {}\n".format(self.gw_hash)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
RAND_STR_ASCII_IDX_LIST = (
|
|
|
|
list(range(48, 58)) + list(range(65, 91)) + list(range(97, 123))
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def rand_str(l=8):
|
|
|
|
s = ""
|
2021-10-15 16:18:03 +02:00
|
|
|
for i in range(l):
|
|
|
|
s += chr(random.choice(RAND_STR_ASCII_IDX_LIST))
|
|
|
|
return s
|
|
|
|
|
2021-10-18 18:40:50 +02:00
|
|
|
|
2021-10-15 16:18:03 +02:00
|
|
|
HIData_default_size_stoc_traj = 10
|
|
|
|
HIData_default_size_rho_t_accum_part = 10
|
|
|
|
|
2021-10-18 18:40:50 +02:00
|
|
|
|
2021-10-15 16:18:03 +02:00
|
|
|
def is_int_power(x, b=2):
|
2021-10-18 18:40:50 +02:00
|
|
|
n_float = np.log(x) / np.log(b)
|
2021-10-15 16:18:03 +02:00
|
|
|
n = int(n_float)
|
2021-10-18 18:40:50 +02:00
|
|
|
if b ** n == x:
|
2021-10-15 16:18:03 +02:00
|
|
|
return n
|
|
|
|
else:
|
|
|
|
return None
|
|
|
|
|
2021-10-18 18:40:50 +02:00
|
|
|
|
2021-10-15 16:18:03 +02:00
|
|
|
def file_does_not_exists_or_is_empty(fname):
|
|
|
|
if not os.path.exists(fname):
|
|
|
|
return True
|
|
|
|
else:
|
2021-10-18 18:40:50 +02:00
|
|
|
return os.path.getsize(fname) == 0
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
|
|
|
|
class HIData(object):
|
2021-10-18 18:40:50 +02:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
hdf5_name,
|
|
|
|
size_sys,
|
|
|
|
size_t,
|
|
|
|
size_y,
|
|
|
|
size_aux_state=0,
|
|
|
|
num_bcf_terms=0,
|
|
|
|
accum_only=False,
|
|
|
|
read_only=False,
|
|
|
|
):
|
2021-10-15 16:18:03 +02:00
|
|
|
self.hdf5_name = hdf5_name
|
|
|
|
|
|
|
|
self.accum_only = accum_only
|
|
|
|
|
|
|
|
if file_does_not_exists_or_is_empty(hdf5_name):
|
|
|
|
# print("file_does_not_exists_or_is_empty {} -> call init_file".format(hdf5_name))
|
2021-10-18 18:40:50 +02:00
|
|
|
self.init_file(size_sys, size_t, size_y, size_aux_state, num_bcf_terms)
|
2021-10-15 16:18:03 +02:00
|
|
|
else:
|
|
|
|
if not read_only:
|
|
|
|
try:
|
|
|
|
self._test_file_version(hdf5_name)
|
|
|
|
except Exception as e:
|
|
|
|
print("test_file_version FAILED with exception {}".format(e))
|
|
|
|
r = input("to ignore the error type y")
|
2021-10-18 18:40:50 +02:00
|
|
|
if r != "y":
|
2021-10-15 16:18:03 +02:00
|
|
|
raise
|
|
|
|
|
|
|
|
# print("read_only", read_only)
|
|
|
|
|
|
|
|
if read_only:
|
|
|
|
# print("before h5py.File(self.hdf5_name, 'r', swmr=True, libver='latest')")
|
2021-10-18 18:40:50 +02:00
|
|
|
self.h5File = h5py.File(self.hdf5_name, "r", swmr=True, libver="latest")
|
2021-10-15 16:18:03 +02:00
|
|
|
# print("after")
|
|
|
|
# print(self.h5File)
|
|
|
|
else:
|
|
|
|
# print("before h5py.File(self.hdf5_name, 'r+', libver='latest')")
|
|
|
|
# print("open r+", self.hdf5_name)
|
|
|
|
try:
|
2021-10-18 18:40:50 +02:00
|
|
|
self.h5File = h5py.File(self.hdf5_name, "r+", libver="latest")
|
2021-10-15 16:18:03 +02:00
|
|
|
except OSError:
|
|
|
|
print("FAILED to open h5 file '{}'".format(self.hdf5_name))
|
|
|
|
raise
|
|
|
|
self.h5File.swmr_mode = True
|
|
|
|
# print("after")
|
|
|
|
# print(self.h5File)
|
|
|
|
|
|
|
|
try:
|
2021-10-18 18:40:50 +02:00
|
|
|
self.stoc_traj = self.h5File["/stoc_traj"]
|
|
|
|
self.rho_t_accum = self.h5File["/rho_t_accum"]
|
|
|
|
self.rho_t_accum_part = self.h5File["/rho_t_accum_part"]
|
2021-10-15 16:18:03 +02:00
|
|
|
self.rho_t_accum_part_tracker = self.h5File["/rho_t_accum_part_tracker"]
|
2021-10-18 18:40:50 +02:00
|
|
|
self.samples = self.h5File["/samples"]
|
|
|
|
self.largest_idx = self.h5File["/largest_idx"]
|
2021-10-15 16:18:03 +02:00
|
|
|
self.tracker = self.h5File["/tracker"]
|
2021-10-18 18:40:50 +02:00
|
|
|
self.y = self.h5File["/y"]
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
if size_aux_state != 0:
|
2021-10-18 18:40:50 +02:00
|
|
|
self.aux_states = self.h5File["/aux_states"]
|
2021-10-15 16:18:03 +02:00
|
|
|
else:
|
|
|
|
self.aux_states = None
|
2021-10-18 18:40:50 +02:00
|
|
|
if "aux_states" in self.h5File:
|
|
|
|
raise TypeError(
|
|
|
|
"HIData with aux_states=0 finds h5 file with /aux_states"
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
if num_bcf_terms != 0:
|
2021-10-18 18:40:50 +02:00
|
|
|
self.stoc_proc = self.h5File["/stoc_proc"]
|
2021-10-15 16:18:03 +02:00
|
|
|
else:
|
|
|
|
self.stoc_proc = None
|
2021-10-18 18:40:50 +02:00
|
|
|
if "stoc_proc" in self.h5File:
|
|
|
|
raise TypeError(
|
|
|
|
"HIData init FAILED: num_bcf_terms=0 but h5 file {} has /stoc_proc".format(
|
|
|
|
self.hdf5_name
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
self.time = self.h5File["/time"]
|
|
|
|
self.time_set = self.h5File["/time_set"]
|
2021-10-15 16:18:03 +02:00
|
|
|
except KeyError:
|
|
|
|
print("KeyError in hdf5 file '{}'".format(hdf5_name))
|
|
|
|
raise
|
|
|
|
|
|
|
|
self.size_t = size_t
|
|
|
|
self.size_sys = size_sys
|
|
|
|
self.size_aux_state_plus_sys = size_aux_state + size_sys
|
|
|
|
self.num_bcf_terms = num_bcf_terms
|
2021-10-18 18:40:50 +02:00
|
|
|
self.size_y = size_y
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
self._idx_cnt = len(self.tracker)
|
|
|
|
self._idx_rho_t_accum_part_tracker_cnt = len(self.rho_t_accum_part_tracker)
|
|
|
|
|
2021-10-18 18:40:50 +02:00
|
|
|
def init_file(self, size_sys, size_t, size_y, size_aux_state=0, num_bcf_terms=0):
|
2021-10-15 16:18:03 +02:00
|
|
|
|
2021-10-18 18:40:50 +02:00
|
|
|
with h5py.File(self.hdf5_name, "w", libver="latest") as h5File:
|
2021-10-15 16:18:03 +02:00
|
|
|
# mode 'x': Create file, fail if exists
|
|
|
|
|
|
|
|
if not self.accum_only:
|
|
|
|
size_stoc_traj = HIData_default_size_stoc_traj
|
|
|
|
else:
|
|
|
|
# need at least one stoch traj to show k_max convergence
|
|
|
|
size_stoc_traj = 1
|
|
|
|
|
2021-10-18 18:40:50 +02:00
|
|
|
# size_stoc_traj may be overwritten HIData_default_size_stoc_traj to account for accum_only
|
|
|
|
h5File.create_dataset(
|
|
|
|
"stoc_traj",
|
|
|
|
(size_stoc_traj, size_t, size_sys),
|
|
|
|
dtype=np.complex128,
|
|
|
|
maxshape=(None, size_t, size_sys),
|
|
|
|
chunks=(1, size_t, size_sys),
|
|
|
|
)
|
|
|
|
h5File.create_dataset(
|
|
|
|
"y",
|
|
|
|
(size_stoc_traj, size_y),
|
|
|
|
dtype=np.complex128,
|
|
|
|
maxshape=(None, size_y),
|
|
|
|
chunks=(1, size_y),
|
|
|
|
)
|
|
|
|
h5File.create_dataset(
|
|
|
|
"rho_t_accum", (size_t, size_sys, size_sys), dtype=np.complex128
|
|
|
|
)
|
|
|
|
h5File.create_dataset(
|
|
|
|
"rho_t_accum_part",
|
|
|
|
(HIData_default_size_rho_t_accum_part, size_t, size_sys, size_sys),
|
|
|
|
dtype=np.complex128,
|
|
|
|
maxshape=(None, size_t, size_sys, size_sys),
|
|
|
|
chunks=(1, size_t, size_sys, size_sys),
|
|
|
|
)
|
|
|
|
|
|
|
|
h5File.create_dataset(
|
|
|
|
"rho_t_accum_part_tracker",
|
|
|
|
data=HIData_default_size_rho_t_accum_part * [False],
|
|
|
|
dtype="bool",
|
|
|
|
maxshape=(None,),
|
|
|
|
)
|
|
|
|
|
|
|
|
h5File.create_dataset("samples", (1,), dtype=np.uint32)
|
|
|
|
h5File.create_dataset("largest_idx", (1,), dtype=np.uint32)
|
|
|
|
|
|
|
|
h5File.create_dataset(
|
|
|
|
"tracker",
|
|
|
|
data=HIData_default_size_stoc_traj * [False],
|
|
|
|
dtype="bool",
|
|
|
|
maxshape=(None,),
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
if size_aux_state != 0:
|
|
|
|
# size_stoc_traj may be overwritten HIData_default_size_stoc_traj to account for accum_only
|
2021-10-18 18:40:50 +02:00
|
|
|
print((size_stoc_traj, size_t, size_aux_state))
|
|
|
|
h5File.create_dataset(
|
|
|
|
"aux_states",
|
|
|
|
(size_stoc_traj, size_t, size_aux_state),
|
|
|
|
dtype=np.complex128,
|
|
|
|
maxshape=(None, size_t, size_aux_state),
|
|
|
|
chunks=(1, size_t, size_aux_state),
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
if num_bcf_terms != 0:
|
|
|
|
# size_stoc_traj may be overwritten HIData_default_size_stoc_traj to account for accum_only
|
2021-10-18 18:40:50 +02:00
|
|
|
h5File.create_dataset(
|
|
|
|
"stoc_proc",
|
|
|
|
(size_stoc_traj, size_t, num_bcf_terms),
|
|
|
|
dtype=np.complex128,
|
|
|
|
maxshape=(None, size_t, num_bcf_terms),
|
|
|
|
chunks=(1, size_t, num_bcf_terms),
|
|
|
|
)
|
|
|
|
|
|
|
|
h5File.create_dataset("time", (size_t,), dtype=np.float64)
|
|
|
|
h5File.create_dataset("time_set", (1,), dtype=np.bool)
|
|
|
|
h5File["/time_set"][0] = False
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
def _test_file_version(self, hdf5_name):
|
|
|
|
p = get_process_accessing_file(hdf5_name)
|
|
|
|
if len(p) > 0:
|
|
|
|
# another process accesses the file, assume that the file has allready the new format,
|
|
|
|
# since that other process has already changed it
|
|
|
|
return
|
|
|
|
|
2021-10-18 18:40:50 +02:00
|
|
|
with h5py.File(hdf5_name, libver="latest") as h5File:
|
2021-10-15 16:18:03 +02:00
|
|
|
try:
|
|
|
|
h5File.swmr_mode = True
|
|
|
|
except ValueError as e:
|
|
|
|
s = str(e)
|
|
|
|
if s.startswith("File superblock version should be at least 3"):
|
2021-10-18 18:40:50 +02:00
|
|
|
print(
|
|
|
|
"got Value Error with msg 'File superblock version should be at least 3' -> change h5 file to new version"
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
h5File.close()
|
|
|
|
change_file_version_to_latest(hdf5_name)
|
2021-10-18 18:40:50 +02:00
|
|
|
except Exception as e:
|
|
|
|
pass
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
|
|
self.close()
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
self.h5File.close()
|
|
|
|
|
|
|
|
def has_sample(self, idx):
|
|
|
|
if idx < self._idx_cnt:
|
|
|
|
return self.tracker[idx]
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
def _resize(self, size):
|
|
|
|
self.tracker.resize(size=(size,))
|
|
|
|
if not self.accum_only:
|
|
|
|
self.stoc_traj.resize(size=(size, self.size_t, self.size_sys))
|
2021-10-18 18:40:50 +02:00
|
|
|
self.y.resize(size=(size, self.size_y))
|
2021-10-15 16:18:03 +02:00
|
|
|
if self.aux_states is not None:
|
2021-10-18 18:40:50 +02:00
|
|
|
self.aux_states.resize(
|
|
|
|
size=(
|
|
|
|
size,
|
|
|
|
self.size_t,
|
|
|
|
self.size_aux_state_plus_sys - self.size_sys,
|
|
|
|
)
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
if self.stoc_proc is not None:
|
2021-10-18 18:40:50 +02:00
|
|
|
# TODO: ask richard
|
|
|
|
# self.stoc_proc.resize(size=(size, self.size_t, self.num_bcf_terms))
|
|
|
|
pass
|
2021-10-15 16:18:03 +02:00
|
|
|
self._idx_cnt = size
|
|
|
|
|
|
|
|
def _inc_size(self, idx):
|
|
|
|
if self._idx_cnt <= idx:
|
2021-10-18 18:40:50 +02:00
|
|
|
new_idx_cnt = 2 * self._idx_cnt
|
2021-10-15 16:18:03 +02:00
|
|
|
while new_idx_cnt <= idx:
|
|
|
|
new_idx_cnt *= 2
|
|
|
|
|
|
|
|
self._resize(new_idx_cnt)
|
|
|
|
|
|
|
|
def _resize_rho_t_accum_part(self, size):
|
|
|
|
self.rho_t_accum_part_tracker.resize(size=(size,))
|
2021-10-18 18:40:50 +02:00
|
|
|
self.rho_t_accum_part.resize(
|
|
|
|
size=(size, self.size_t, self.size_sys, self.size_sys)
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
self._idx_rho_t_accum_part_tracker_cnt = size
|
|
|
|
|
|
|
|
def _inc_rho_t_accum_part_tracker_size(self, n):
|
|
|
|
if self._idx_rho_t_accum_part_tracker_cnt <= n:
|
2021-10-18 18:40:50 +02:00
|
|
|
new_idx_cnt = (
|
|
|
|
self._idx_rho_t_accum_part_tracker_cnt
|
|
|
|
+ HIData_default_size_rho_t_accum_part
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
while new_idx_cnt <= n:
|
|
|
|
new_idx_cnt += HIData_default_size_rho_t_accum_part
|
|
|
|
self._resize_rho_t_accum_part(new_idx_cnt)
|
|
|
|
|
|
|
|
def has_rho_t_accum_part(self, n):
|
|
|
|
if n < self._idx_rho_t_accum_part_tracker_cnt:
|
|
|
|
return self.rho_t_accum_part_tracker[n]
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
def set_time(self, time, force=False):
|
|
|
|
if (self.time_set[0] == False) or force:
|
|
|
|
self.time[:] = time
|
|
|
|
self.time_set[0] = True
|
|
|
|
else:
|
|
|
|
warnings.warn("time has already been set (ignore new time)")
|
|
|
|
|
|
|
|
def get_time(self):
|
|
|
|
if self.time_set[0] == False:
|
|
|
|
raise RuntimeError("can not get time, time has not been set yet.")
|
|
|
|
return self.time[:]
|
|
|
|
|
2021-10-18 18:40:50 +02:00
|
|
|
def new_samples(self, idx, psi_all, result_type, normed, y):
|
2021-10-15 16:18:03 +02:00
|
|
|
self._inc_size(idx)
|
|
|
|
if (not self.accum_only) or (idx == 0):
|
|
|
|
c = psi_all.shape[1]
|
2021-10-18 18:40:50 +02:00
|
|
|
self.y[idx] = y
|
2021-10-15 16:18:03 +02:00
|
|
|
if result_type == RESULT_TYPE_ZEROTH_ORDER_ONLY:
|
|
|
|
self.stoc_traj[idx] = psi_all
|
|
|
|
elif result_type == RESULT_TYPE_ZEROTH_ORDER_AND_ETA_LAMBDA:
|
2021-10-18 18:40:50 +02:00
|
|
|
self.stoc_traj[idx] = psi_all[:, : self.size_sys]
|
|
|
|
if c > self.size_sys: # the linear HI has no stoc_proc data
|
|
|
|
self.stoc_proc[idx] = psi_all[:, self.size_sys :]
|
2021-10-15 16:18:03 +02:00
|
|
|
elif result_type == RESULT_TYPE_ALL:
|
2021-10-18 18:40:50 +02:00
|
|
|
self.stoc_traj[idx] = psi_all[:, : self.size_sys]
|
|
|
|
self.aux_states[idx] = psi_all[
|
|
|
|
:, self.size_sys : self.size_aux_state_plus_sys
|
|
|
|
]
|
|
|
|
if (
|
|
|
|
c > self.size_aux_state_plus_sys
|
|
|
|
): # the linear HI has no stoc_proc data
|
|
|
|
self.stoc_proc = psi_all[:, self.size_aux_state_plus_sys :]
|
|
|
|
|
|
|
|
n = is_int_power(self.samples[0] + 1, b=2)
|
2021-10-15 16:18:03 +02:00
|
|
|
if n is not None:
|
|
|
|
self._inc_rho_t_accum_part_tracker_size(n)
|
|
|
|
|
|
|
|
with signalDelay.sig_delay([signal.SIGINT, signal.SIGTERM]):
|
|
|
|
self.tracker[idx] = True
|
|
|
|
self.largest_idx[0] = max(self.largest_idx[0], idx)
|
|
|
|
|
2021-10-18 18:40:50 +02:00
|
|
|
self.rho_t_accum[:] += projector_psi_t(
|
|
|
|
psi_all[:, : self.size_sys], normed=normed
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
self.samples[0] += 1
|
|
|
|
|
|
|
|
if n is not None:
|
|
|
|
self.rho_t_accum_part_tracker[n] = True
|
|
|
|
self.rho_t_accum_part[n] = self.get_rho_t()
|
|
|
|
|
|
|
|
self.h5File.flush()
|
|
|
|
|
|
|
|
def get_rho_t(self, res=None):
|
|
|
|
if res is None:
|
2021-10-18 18:40:50 +02:00
|
|
|
res = np.empty(
|
|
|
|
shape=(self.size_t, self.size_sys, self.size_sys), dtype=np.complex128
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
self.rho_t_accum.read_direct(dest=res)
|
2021-10-18 18:40:50 +02:00
|
|
|
return res / self.get_samples()
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
def get_rho_t_part(self, n):
|
|
|
|
if self.has_rho_t_accum_part(n):
|
|
|
|
return self.rho_t_accum_part[n]
|
|
|
|
else:
|
2021-10-18 18:40:50 +02:00
|
|
|
raise RuntimeError(
|
|
|
|
"rho_t_accum_part with index {} has not been chrunched yet".format(n)
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
def get_samples(self):
|
|
|
|
return self.samples[0]
|
|
|
|
|
|
|
|
def clear(self):
|
|
|
|
self._resize(HIData_default_size_stoc_traj)
|
|
|
|
self._resize_rho_t_accum_part(HIData_default_size_rho_t_accum_part)
|
|
|
|
self.time[0] = False
|
|
|
|
self.rho_t_accum[:] = 0j
|
|
|
|
self.samples[0] = 0
|
|
|
|
self.tracker[:] = False
|
|
|
|
self.rho_t_accum_part_tracker[:] = False
|
|
|
|
self.largest_idx[0] = 0
|
|
|
|
|
|
|
|
def get_stoc_traj(self, idx):
|
|
|
|
if self.has_sample(idx):
|
|
|
|
return self.stoc_traj[idx]
|
|
|
|
else:
|
2021-10-18 18:40:50 +02:00
|
|
|
raise RuntimeError(
|
|
|
|
"sample with idx {} has not yet been chrunched".format(idx)
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
def get_sub_rho_t(self, idx_low, idx_high, normed, overwrite=False):
|
|
|
|
name = "{}_{}".format(int(idx_low), int(idx_high))
|
|
|
|
if overwrite and name in self.h5File:
|
|
|
|
del self.h5File[name]
|
|
|
|
|
|
|
|
if not name in self.h5File:
|
|
|
|
smp = 0
|
2021-10-18 18:40:50 +02:00
|
|
|
rho_t_accum = np.zeros(
|
|
|
|
shape=(self.size_t, self.size_sys, self.size_sys), dtype=np.complex128
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
for i in range(idx_low, idx_high):
|
|
|
|
if self.has_sample(i):
|
|
|
|
smp += 1
|
|
|
|
rho_t_accum += projector_psi_t(self.stoc_traj[i], normed=normed)
|
|
|
|
rho_t = rho_t_accum / smp
|
2021-10-18 18:40:50 +02:00
|
|
|
h5_data = self.h5File.create_dataset(
|
|
|
|
name,
|
|
|
|
shape=(self.size_t, self.size_sys, self.size_sys),
|
|
|
|
dtype=np.complex128,
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
h5_data[:] = rho_t
|
2021-10-18 18:40:50 +02:00
|
|
|
h5_data.attrs["smp"] = smp
|
2021-10-15 16:18:03 +02:00
|
|
|
else:
|
2021-10-18 18:40:50 +02:00
|
|
|
rho_t = np.empty(
|
|
|
|
shape=(self.size_t, self.size_sys, self.size_sys), dtype=np.complex128
|
|
|
|
)
|
|
|
|
self.h5File[name].read_direct(dest=rho_t)
|
|
|
|
smp = self.h5File[name].attrs["smp"]
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
return rho_t, smp
|
|
|
|
|
|
|
|
def rewrite_rho_t(self, normed):
|
|
|
|
smp = 0
|
2021-10-18 18:40:50 +02:00
|
|
|
rho_t_accum = np.zeros(
|
|
|
|
shape=(self.size_t, self.size_sys, self.size_sys), dtype=np.complex128
|
|
|
|
)
|
|
|
|
for i in range(self.largest_idx[0] + 1):
|
2021-10-15 16:18:03 +02:00
|
|
|
if self.has_sample(i):
|
|
|
|
smp += 1
|
|
|
|
rho_t_accum += projector_psi_t(self.stoc_traj[i], normed=normed)
|
|
|
|
|
|
|
|
with signalDelay.sig_delay([signal.SIGINT, signal.SIGTERM]):
|
|
|
|
self.samples[0] = smp
|
|
|
|
self.rho_t_accum[:] = rho_t_accum
|
|
|
|
|
|
|
|
|
|
|
|
class HIMetaData(object):
|
|
|
|
def __init__(self, hid_name, hid_path):
|
|
|
|
self.name = hid_name
|
2021-10-18 18:40:50 +02:00
|
|
|
self.path = os.path.join(hid_path, "__" + self.name)
|
2021-10-15 16:18:03 +02:00
|
|
|
if os.path.exists(self.path):
|
|
|
|
if not os.path.isdir(self.path):
|
2021-10-18 18:40:50 +02:00
|
|
|
raise NotADirectoryError(
|
|
|
|
"the path '{}' exists but is not a directory".format(self.path)
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
else:
|
|
|
|
os.mkdir(self.path)
|
2021-10-18 18:40:50 +02:00
|
|
|
self._fname = os.path.join(self.path, self.name + ".sqld")
|
2021-10-15 16:18:03 +02:00
|
|
|
self._l = 8
|
|
|
|
self.db = sqd.SqliteDict(filename=self._fname, autocommit=False)
|
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
|
|
self.db.close()
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
self.db.close()
|
|
|
|
|
|
|
|
def _new_rand_file_name(self, pre, end):
|
|
|
|
if not os.path.exists(self.path):
|
|
|
|
os.mkdir(self.path)
|
|
|
|
|
|
|
|
c = 0
|
|
|
|
while True:
|
|
|
|
fname = pre + rand_str(self._l) + end
|
|
|
|
full_name = os.path.join(self.path, fname)
|
|
|
|
|
|
|
|
try:
|
2021-10-18 18:40:50 +02:00
|
|
|
open(
|
|
|
|
full_name, "x"
|
|
|
|
).close() # open for exclusive creation, failing if the file already exists
|
2021-10-15 16:18:03 +02:00
|
|
|
return fname
|
|
|
|
except FileExistsError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
c += 1
|
|
|
|
if c > 10:
|
|
|
|
self._l += 2
|
|
|
|
c = 0
|
|
|
|
print("INFO: increase random file name length to", self._l)
|
|
|
|
|
|
|
|
def get_hashed_key(self, key):
|
|
|
|
binkey = bf.dump(key)
|
|
|
|
return hashlib.sha384(binkey).hexdigest()
|
|
|
|
|
|
|
|
def get_HIData_fname(self, key):
|
|
|
|
hashed_key = self.get_hashed_key(key)
|
|
|
|
# print("hashed_key", hashed_key)
|
|
|
|
try:
|
|
|
|
hdf5_name = self.db[hashed_key][0]
|
|
|
|
except KeyError:
|
2021-10-18 18:40:50 +02:00
|
|
|
hdf5_name = self._new_rand_file_name(pre=self.name + "_", end=".h5")
|
2021-10-15 16:18:03 +02:00
|
|
|
self.db[hashed_key] = (hdf5_name, key)
|
|
|
|
self.db.commit()
|
|
|
|
|
|
|
|
return hdf5_name
|
|
|
|
|
|
|
|
def get_HIData(self, key, read_only=False):
|
|
|
|
hdf5_name = self.get_HIData_fname(key)
|
|
|
|
|
|
|
|
if key.HiP.result_type == RESULT_TYPE_ZEROTH_ORDER_ONLY:
|
|
|
|
size_aux_state = 0
|
|
|
|
num_bcf_terms = 0
|
|
|
|
elif key.HiP.result_type == RESULT_TYPE_ZEROTH_ORDER_AND_ETA_LAMBDA:
|
|
|
|
size_aux_state = 0
|
|
|
|
num_bcf_terms = key.SysP.len_gw
|
|
|
|
elif key.HiP.result_type == RESULT_TYPE_ALL:
|
|
|
|
num_bcf_terms = key.SysP.len_gw
|
2021-10-18 18:40:50 +02:00
|
|
|
size_aux_state = combLib.number_of_all_combinations_old(
|
|
|
|
n=num_bcf_terms, k_max=key.HiP.k_max
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
if not key.HiP.nonlinear:
|
|
|
|
num_bcf_terms = 0
|
|
|
|
|
2021-10-18 18:40:50 +02:00
|
|
|
if hasattr(key.HiP, "accum_only"):
|
2021-10-15 16:18:03 +02:00
|
|
|
accum_only = key.HiP.accum_only
|
|
|
|
else:
|
|
|
|
accum_only = False
|
2021-10-18 18:40:50 +02:00
|
|
|
return HIData(
|
|
|
|
os.path.join(self.path, hdf5_name),
|
|
|
|
size_sys=key.SysP.H_sys.shape[0],
|
|
|
|
size_t=key.IntP.t_steps,
|
|
|
|
size_aux_state=size_aux_state,
|
|
|
|
num_bcf_terms=num_bcf_terms,
|
|
|
|
accum_only=accum_only,
|
|
|
|
read_only=read_only,
|
|
|
|
size_y=key.Eta.get_num_y()
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
|
|
|
|
def get_process_accessing_file(fname):
|
|
|
|
cmd = 'lsof "{}"'.format(fname)
|
|
|
|
if not os.path.exists(fname):
|
|
|
|
raise FileNotFoundError(fname)
|
2021-10-18 18:40:50 +02:00
|
|
|
r = subprocess.run(
|
|
|
|
cmd,
|
|
|
|
stdout=subprocess.PIPE,
|
|
|
|
stderr=subprocess.PIPE,
|
|
|
|
shell=True,
|
|
|
|
universal_newlines=True,
|
|
|
|
encoding="utf8",
|
|
|
|
)
|
|
|
|
if r.stderr != "":
|
2021-10-15 16:18:03 +02:00
|
|
|
log.info("command '{}' stderr:\n{}".format(cmd, r.stderr))
|
|
|
|
|
|
|
|
if r.returncode == 0:
|
|
|
|
# success
|
2021-10-18 18:40:50 +02:00
|
|
|
out = r.stdout.split("\n")
|
2021-10-15 16:18:03 +02:00
|
|
|
head = out[0].split()
|
2021-10-18 18:40:50 +02:00
|
|
|
idx_PID = head.index("PID")
|
2021-10-15 16:18:03 +02:00
|
|
|
pid_list = []
|
|
|
|
for l in out[1:]:
|
|
|
|
l = l.split()
|
|
|
|
if len(l) == 0:
|
|
|
|
continue
|
|
|
|
|
|
|
|
pid_list.append(int(l[idx_PID]))
|
|
|
|
return pid_list
|
|
|
|
else:
|
|
|
|
# failure, also happens when no process was found
|
2021-10-18 18:40:50 +02:00
|
|
|
if r.stdout == "":
|
|
|
|
log.info(
|
|
|
|
"lsof has non-zero return code and empty stdout -> assume not process has access to file"
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
return []
|
|
|
|
|
|
|
|
|
2021-10-18 18:40:50 +02:00
|
|
|
def get_rand_file_name(l=12, must_not_exists=True):
|
2021-10-15 16:18:03 +02:00
|
|
|
n = len(CHAR_SET)
|
|
|
|
while True:
|
|
|
|
fname = ""
|
|
|
|
for i in range(l):
|
|
|
|
fname += CHAR_SET[np.random.randint(0, n)]
|
|
|
|
if (not os.path.exists(fname)) or (not must_not_exists):
|
|
|
|
return fname
|
|
|
|
|
|
|
|
|
|
|
|
def change_file_version_to_latest(h5fname):
|
|
|
|
|
|
|
|
pid_list = get_process_accessing_file(h5fname)
|
|
|
|
if len(pid_list) > 0:
|
2021-10-18 18:40:50 +02:00
|
|
|
raise RuntimeError(
|
|
|
|
"can not change file version! the following processes have access to the file: {}".format(
|
|
|
|
pid_list
|
|
|
|
)
|
|
|
|
)
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
rand_fname = get_rand_file_name()
|
2021-10-18 18:40:50 +02:00
|
|
|
with h5py.File(rand_fname, "w", libver="latest") as f_new:
|
|
|
|
with h5py.File(h5fname, "r") as f_old:
|
2021-10-15 16:18:03 +02:00
|
|
|
for i in f_old:
|
2021-10-18 18:40:50 +02:00
|
|
|
f_old.copy(
|
|
|
|
i,
|
|
|
|
f_new["/"],
|
|
|
|
shallow=False,
|
|
|
|
expand_soft=False,
|
|
|
|
expand_external=False,
|
|
|
|
expand_refs=False,
|
|
|
|
without_attrs=False,
|
|
|
|
)
|
|
|
|
for k, v in f_old.attrs.items():
|
2021-10-15 16:18:03 +02:00
|
|
|
f_new.attrs[k] = v
|
|
|
|
print("updated h5 file {} to latest version".format(os.path.abspath(h5fname)))
|
|
|
|
|
2021-10-18 18:40:50 +02:00
|
|
|
shutil.move(h5fname, h5fname + rand_fname + ".old")
|
2021-10-15 16:18:03 +02:00
|
|
|
shutil.move(rand_fname, h5fname)
|
2021-10-18 18:40:50 +02:00
|
|
|
os.remove(h5fname + rand_fname + ".old")
|
2021-10-15 16:18:03 +02:00
|
|
|
|
|
|
|
assert not os.path.exists(rand_fname)
|