Skip to content

Commit 4f1ce75

Browse files
MesoHOPS 1.4.2
This commit introduces several minor fixes to the MesoHOPS code, including: 1. Introduction of a default dictionary for integration parameters in HopsTrajectory class. 2. Introduction of associated tests for default dictionary functionality for different user inputs. 3. Reformatting of integration parameters as properties of HopsTrajectory class. 4. Removal of redundant conditionals in HopsTrajectory init statement. 5. Removal of redundant HopsModes hierarchy parameter. 6. Change of prepare_noise() in prepare_functions.py to prepare_hops_noise() to prevent function naming conflicts. As a result, partial integration_param dictionary inputs will no longer result in unexpected errors and the integration_param dictionary will be updated with default settings.
1 parent dfd5ce3 commit 4f1ce75

File tree

6 files changed

+125
-49
lines changed

6 files changed

+125
-49
lines changed

mesohops/dynamics/hops_basis.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def __init__(self, system, hierarchy, eom):
5959
"""
6060
self.system = system
6161
self.hierarchy = hierarchy
62-
self.mode = HopsModes(system, hierarchy)
62+
self.mode = HopsModes(system)
6363
self.eom = eom
6464
self.flag_gcorr = False
6565
if self.eom.param["EQUATION_OF_MOTION"] == "NONLINEAR ABSORPTION":

mesohops/dynamics/hops_modes.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ class HopsModes:
77
between the state and auxiliary wave function bases.
88
"""
99

10-
def __init__(self, system, hierarchy):
10+
def __init__(self, system):
1111
self.system = system
12-
self.hierarchy = hierarchy
1312
self.__list_absindex_mode = []
1413
self._list_absindex_L2 = []
1514

mesohops/dynamics/hops_trajectory.py

Lines changed: 74 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,34 @@
66
from mesohops.dynamics.hops_eom import HopsEOM
77
from mesohops.dynamics.hops_hierarchy import HopsHierarchy
88
from mesohops.dynamics.hops_system import HopsSystem
9-
from mesohops.dynamics.prepare_functions import prepare_noise
9+
from mesohops.dynamics.prepare_functions import prepare_hops_noise
1010
from mesohops.dynamics.hops_storage import HopsStorage
11+
from mesohops.util.dynamic_dict import Dict_wDefaults
1112
from mesohops.util.exceptions import UnsupportedRequest, LockedException, TrajectoryError
1213
from mesohops.util.physical_constants import precision # Constant
1314

1415
__title__ = "HOPS"
15-
__author__ = "D. I. G. Bennett, L. Varvelo"
16+
__author__ = "D. I. G. Bennett, L. Varvelo, Z. W. Freeman"
1617
__version__ = "1.4"
1718

19+
INTEGRATION_DICT_DEFAULT = {
20+
"INTEGRATOR": "RUNGE_KUTTA",
21+
"EARLY_ADAPTIVE_INTEGRATOR": "INCH_WORM",
22+
"EARLY_INTEGRATOR_STEPS": 5,
23+
"INCHWORM_CAP": 5,
24+
"STATIC_BASIS": None,
25+
"EFFECTIVE_NOISE_INTEGRATION": False,
26+
}
27+
28+
INTEGRATION_DICT_TYPES = {
29+
"INTEGRATOR": [str],
30+
"EARLY_ADAPTIVE_INTEGRATOR": [str],
31+
"EARLY_INTEGRATOR_STEPS": [int],
32+
"INCHWORM_CAP": [int],
33+
"STATIC_BASIS": [type(None), list, np.ndarray],
34+
"EFFECTIVE_NOISE_INTEGRATION": [bool],
35+
}
36+
1837

1938
class HopsTrajectory:
2039
"""
@@ -28,10 +47,7 @@ def __init__(
2847
noise_param={},
2948
hierarchy_param={},
3049
storage_param={},
31-
integration_param=dict(
32-
INTEGRATOR="RUNGE_KUTTA", EARLY_ADAPTIVE_INTEGRATOR='INCH_WORM',EARLY_INTEGRATOR_STEPS=5, INCHWORM_CAP=5,
33-
STATIC_BASIS=None, EFFECTIVE_NOISE_INTEGRATION=False,
34-
),
50+
integration_param={},
3551
):
3652
"""
3753
This class manages four classes:
@@ -104,32 +120,30 @@ def __init__(
104120
self.noise_param = noise_param
105121
self.basis = HopsBasis(system, hierarchy, eom)
106122
self.storage = HopsStorage(self.basis.eom.param['ADAPTIVE'],storage_param)
107-
self.noise1 = prepare_noise(noise_param, self.basis.system.param)
123+
self.noise1 = prepare_hops_noise(noise_param, self.basis.system.param)
108124
if "L_NOISE2" in system.param.keys():
109125
noise_param2 = copy.copy(noise_param)
110126
rand = np.random.RandomState(seed=noise_param['SEED'])
111127
noise_param2['SEED'] = int(rand.randint(0, 2 ** 20, 1)[0])
112-
self.noise2 = prepare_noise(noise_param2, self.basis.system.param, flag=2)
128+
self.noise2 = prepare_hops_noise(noise_param2, self.basis.system.param, flag=2)
113129
else:
114130
noise_param2 = {
115131
"TLEN": noise_param["TLEN"],
116132
"TAU": noise_param["TAU"],
117133
"MODEL": "ZERO",
118134
}
119-
self.noise2 = prepare_noise(noise_param2, self.basis.system.param, flag=1)
135+
self.noise2 = prepare_hops_noise(noise_param2, self.basis.system.param, flag=1)
120136

121137
# Defines integration method
122138
# -------------------------
123-
self._early_integrator = integration_param['EARLY_ADAPTIVE_INTEGRATOR']
124-
self._static_basis = integration_param["STATIC_BASIS"]
125-
self._early_steps = integration_param["EARLY_INTEGRATOR_STEPS"]
139+
self.integration_param = Dict_wDefaults._initialize_dictionary(
140+
integration_param,
141+
INTEGRATION_DICT_DEFAULT,
142+
INTEGRATION_DICT_TYPES,
143+
"integration_param in the HopsTrajectory initialization",
144+
)
126145
self._early_step_counter = 0
127-
if integration_param['EARLY_ADAPTIVE_INTEGRATOR'] == 'INCH_WORM' or \
128-
integration_param['EARLY_ADAPTIVE_INTEGRATOR'] == 'STATIC_STATE_INCHWORM_HIERARCHY':
129-
self._inchworm_cap = integration_param["INCHWORM_CAP"]
130-
if "EFFECTIVE_NOISE_INTEGRATION" not in integration_param.keys():
131-
integration_param["EFFECTIVE_NOISE_INTEGRATION"] = False
132-
if integration_param["INTEGRATOR"] == "RUNGE_KUTTA":
146+
if self.integrator == "RUNGE_KUTTA":
133147
from mesohops.dynamics.integrator_rk import (
134148
runge_kutta_step,
135149
runge_kutta_variables,
@@ -138,11 +152,9 @@ def __init__(
138152
self.step = runge_kutta_step
139153
self.integration_var = runge_kutta_variables
140154
self.integrator_step = 0.5
141-
self.effective_noise_integration = integration_param[
142-
"EFFECTIVE_NOISE_INTEGRATION"]
143155
else:
144156
raise UnsupportedRequest(
145-
("Integrator of type " + str(integration_param["INTEGRATOR"])),
157+
("Integrator of type " + str(self.integrator)),
146158
type(self).__name__,
147159
)
148160

@@ -184,7 +196,7 @@ def initialize(self, psi_0):
184196
phi_tmp[: self.n_state] = np.array(psi_0)[self.state_list]
185197
self.z_mem = np.zeros(len(self.basis.system.param["L_NOISE1"]))
186198
if self.basis.adaptive:
187-
if self._static_basis is None:
199+
if self.static_basis is None:
188200
# Update Basis
189201
z_step = self._prepare_zstep(self.z_mem)
190202
(state_update, aux_update) = self.basis.define_basis(phi_tmp, 1,
@@ -197,13 +209,13 @@ def initialize(self, psi_0):
197209
# Construct initial basis
198210
list_stable_state = self.state_list
199211
list_state_new = list(
200-
set(self.state_list).union(set(self._static_basis[0])))
212+
set(self.state_list).union(set(self.static_basis[0])))
201213
list_add_state = set(list_state_new) - set(list_stable_state)
202214
state_update = (list_state_new, list_stable_state, list_add_state)
203215

204216
list_stable_aux = self.auxiliary_list
205217
list_aux_new = list(
206-
set(self.auxiliary_list).union(set(self._static_basis[1])))
218+
set(self.auxiliary_list).union(set(self.static_basis[1])))
207219
list_add_aux = set(list_aux_new) - set(list_stable_aux)
208220
aux_update = (list_aux_new, list_stable_aux, list_add_aux)
209221

@@ -337,17 +349,17 @@ def propagate(self, t_advance, tau):
337349
# Checks for Early Time Integration
338350
# ================================
339351
if self.use_early_integrator:
340-
print(f'Early Integration: Using {self._early_integrator}')
352+
print(f'Early Integration: Using {self.early_integrator}')
341353
# Early Integrator: Inch Worm
342354
# ---------------------------
343-
if self._early_integrator == 'INCH_WORM' or \
344-
self._early_integrator == 'STATIC_STATE_INCHWORM_HIERARCHY':
355+
if self.early_integrator == 'INCH_WORM' or \
356+
self.early_integrator == 'STATIC_STATE_INCHWORM_HIERARCHY':
345357
# Define New Basis
346358
z_step = self._prepare_zstep(z_mem)
347359
(state_update, aux_update) = self.basis.define_basis(phi, tau,
348360
z_step)
349-
if self._early_integrator == 'STATIC_STATE_INCHWORM_HIERARCHY':
350-
state_update = self._static_basis[0]
361+
if self.early_integrator == 'STATIC_STATE_INCHWORM_HIERARCHY':
362+
state_update = self.static_basis[0]
351363

352364
# Update basis for new step
353365
step_num = 0
@@ -356,10 +368,10 @@ def propagate(self, t_advance, tau):
356368
state_update, aux_update, phi = self.inchworm_integrate(
357369
state_update, aux_update, tau
358370
)
359-
if self._early_integrator == 'STATIC_STATE_INCHWORM_HIERARCHY':
360-
state_update = self._static_basis[0]
371+
if self.early_integrator == 'STATIC_STATE_INCHWORM_HIERARCHY':
372+
state_update = self.static_basis[0]
361373
step_num += 1
362-
if step_num >= self._inchworm_cap:
374+
if step_num >= self.inchworm_cap:
363375
break
364376

365377
# Update basis
@@ -369,11 +381,11 @@ def propagate(self, t_advance, tau):
369381

370382
# Early Integrator: Static Basis
371383
# ------------------------------
372-
elif self._early_integrator == 'STATIC':
384+
elif self.early_integrator == 'STATIC':
373385
pass
374386

375387
else:
376-
raise UnsupportedRequest(self._early_integrator,
388+
raise UnsupportedRequest(self.early_integrator,
377389
"early time integrator "
378390
"clause of the propagate")
379391

@@ -579,13 +591,13 @@ def construct_noise_correlation_function(self, n_l2, n_traj):
579591
list_ct1 = np.zeros(len(t_axis), dtype=np.complex128)
580592
list_ct2 = np.zeros(len(t_axis), dtype=np.complex128)
581593
for _ in np.arange(n_traj):
582-
noise1 = prepare_noise(self.noise_param, self.basis.system.param)
594+
noise1 = prepare_hops_noise(self.noise_param, self.basis.system.param)
583595
noise1.prepare_noise()
584596
result = np.correlate(noise1.get_noise(t_axis)[n_l2, :],
585597
noise1.get_noise(t_axis)[n_l2, :], mode='full')
586598
list_ct1 += result[result.size // 2:]
587599
if "L_NOISE2" in self.basis.system.param.keys():
588-
noise2 = prepare_noise(self.noise_param, self.basis.system.param,
600+
noise2 = prepare_hops_noise(self.noise_param, self.basis.system.param,
589601
flag=2)
590602
noise2.prepare_noise()
591603
result = np.correlate(noise2.get_noise(t_axis)[n_l2, :],
@@ -596,11 +608,31 @@ def construct_noise_correlation_function(self, n_l2, n_traj):
596608
def reset_early_time_integrator(self):
597609
"""
598610
Sets self._early_integrator_time to the current time so that the next use of
599-
propagate will make the first self._early_steps early time integrator
611+
propagate will make the first self.early_steps early time integrator
600612
propagation steps.
601613
"""
602614
self._early_step_counter = 0
603615

616+
@property
617+
def early_integrator(self):
618+
return self.integration_param["EARLY_ADAPTIVE_INTEGRATOR"]
619+
620+
@property
621+
def integrator(self):
622+
return self.integration_param["INTEGRATOR"]
623+
624+
@property
625+
def inchworm_cap(self):
626+
return self.integration_param["INCHWORM_CAP"]
627+
628+
@property
629+
def effective_noise_integration(self):
630+
return self.integration_param["EFFECTIVE_NOISE_INTEGRATION"]
631+
632+
@property
633+
def static_basis(self):
634+
return self.integration_param["STATIC_BASIS"]
635+
604636
@property
605637
def psi(self):
606638
return self.phi[: self.n_state]
@@ -645,9 +677,13 @@ def z_mem(self, z_mem):
645677
def t(self):
646678
return self._t
647679

680+
@property
681+
def early_steps(self):
682+
return self.integration_param["EARLY_INTEGRATOR_STEPS"]
683+
648684
@property
649685
def use_early_integrator(self):
650-
return self._early_step_counter < self._early_steps
686+
return self._early_step_counter < self.early_steps
651687

652688
@t.setter
653689
def t(self, t):

mesohops/dynamics/integrator_rk.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,16 @@ def runge_kutta_step(dsystem_dt, phi, z_mem, z_rnd, z_rnd2, tau):
2525
4. z_rnd : np.array(complex)
2626
Random numbers for the bath (at three time points) [units: cm^-1].
2727
28-
5. tau : float
28+
5. z_rnd2 : np.array(complex)
29+
Secondary real contribution to the noise (at three time points).
30+
Imaginary portion discarded in dsystem_dt [units: cm^-1].
31+
For primary use-case, see:
32+
33+
"Exact open quantum system dynamics using the Hierarchy of Pure States
34+
(HOPS)."
35+
Richard Hartmann J. Chem. Theory Comput. 13, p. 5834-5845 (2017)
36+
37+
6. tau : float
2938
Timestep of the calculation [units: fs].
3039
3140
Returns
@@ -87,7 +96,7 @@ def runge_kutta_variables(phi,z_mem, t, noise, noise2, tau, storage,
8796
5. noise2 : instance(HopsNoise)
8897
8998
6. tau : float
90-
Noise time step [units: fs].
99+
Integration time step [units: fs].
91100
92101
7. storage : instance(HopsStorage)
93102

mesohops/dynamics/prepare_functions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
__author__ = "D. I. G. Bennett, J. K. Lynd"
77
__version__ = "1.4"
88

9-
def prepare_noise(noise_param, system_param, flag=1):
9+
def prepare_hops_noise(noise_param, system_param, flag=1):
1010
"""
1111
Returns the proper noise class given the user inputs.
1212
@@ -48,7 +48,7 @@ def prepare_noise(noise_param, system_param, flag=1):
4848
"CORR_PARAM": system_param["PARAM_NOISE2"],
4949
}
5050
else:
51-
Exception("Unknown flag value in prepare_noise")
51+
Exception("Unknown flag value in prepare_hops_noise")
5252

5353
# Instantiate a HopsNoise subclass
5454
# --------------------------------

mesohops/testing/test_hops_trajectory.py

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from mesohops.util.physical_constants import precision # constant
1212

1313
__title__ = "test of hops_trajectory "
14-
__author__ = "D. I. G. Bennett, J. K. Lynd"
14+
__author__ = "D. I. G. Bennett, J. K. Lynd, Z. W. Freeman"
1515
__version__ = "1.4"
1616
__date__ = ""
1717

@@ -40,11 +40,19 @@
4040

4141
integrator_param = {
4242
"INTEGRATOR": "RUNGE_KUTTA",
43-
'EARLY_ADAPTIVE_INTEGRATOR':'INCH_WORM',
43+
'EARLY_ADAPTIVE_INTEGRATOR': 'INCH_WORM',
4444
'EARLY_INTEGRATOR_STEPS': 5,
4545
'INCHWORM_CAP': 5,
46-
'STATIC_BASIS':None
46+
'STATIC_BASIS': None,
47+
'EFFECTIVE_NOISE_INTEGRATION': False,
4748
}
49+
integrator_param_empty = {}
50+
integrator_param_partial = {
51+
'EARLY_INTEGRATOR_STEPS': 3
52+
}
53+
integrator_param_broken = {
54+
'PANCAKE_MIXER': 7
55+
}
4856
t_max = 10.0
4957
t_step = 2.0
5058
psi_0 = [1.0 + 0.0 * 1j, 0.0 + 0.0 * 1j]
@@ -86,7 +94,7 @@ def test_initialize():
8694
noise_param=noise_param,
8795
hierarchy_param=hier_param,
8896
eom_param=eom_param,
89-
integration_param=integrator_param,
97+
integration_param=integrator_param_empty,
9098
)
9199
hops.initialize(psi_0)
92100
storage = hops.storage
@@ -128,6 +136,30 @@ def test_initialize():
128136
known_lock = True
129137
assert lock == known_lock
130138

139+
# checks to make sure integration_param is initialized with defaults correctly
140+
assert hops.integration_param == integrator_param
141+
hops_partial = HOPS(
142+
sys_param,
143+
noise_param=noise_param,
144+
hierarchy_param=hier_param,
145+
eom_param=eom_param,
146+
integration_param=integrator_param_partial,
147+
)
148+
partial_dict = {key: val for (key, val) in integrator_param.items()}
149+
partial_dict['EARLY_INTEGRATOR_STEPS'] = 3
150+
assert hops_partial.integration_param == partial_dict
151+
try:
152+
hops_broken = HOPS(
153+
sys_param,
154+
noise_param=noise_param,
155+
hierarchy_param=hier_param,
156+
eom_param=eom_param,
157+
integration_param=integrator_param_broken,
158+
)
159+
except UnsupportedRequest as excinfo:
160+
assert ("The current code does not support PANCAKE_MIXER in the integration"
161+
in str(excinfo))
162+
131163

132164
def test_make_adaptive_delta_h_true():
133165
"""

0 commit comments

Comments
 (0)