westpa 2022.13__cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- westpa/__init__.py +14 -0
- westpa/_version.py +21 -0
- westpa/analysis/__init__.py +5 -0
- westpa/analysis/core.py +749 -0
- westpa/analysis/statistics.py +27 -0
- westpa/analysis/trajectories.py +369 -0
- westpa/cli/__init__.py +0 -0
- westpa/cli/core/__init__.py +0 -0
- westpa/cli/core/w_fork.py +152 -0
- westpa/cli/core/w_init.py +230 -0
- westpa/cli/core/w_run.py +77 -0
- westpa/cli/core/w_states.py +212 -0
- westpa/cli/core/w_succ.py +99 -0
- westpa/cli/core/w_truncate.py +68 -0
- westpa/cli/tools/__init__.py +0 -0
- westpa/cli/tools/ploterr.py +506 -0
- westpa/cli/tools/plothist.py +706 -0
- westpa/cli/tools/w_assign.py +597 -0
- westpa/cli/tools/w_bins.py +166 -0
- westpa/cli/tools/w_crawl.py +119 -0
- westpa/cli/tools/w_direct.py +557 -0
- westpa/cli/tools/w_dumpsegs.py +94 -0
- westpa/cli/tools/w_eddist.py +506 -0
- westpa/cli/tools/w_fluxanl.py +376 -0
- westpa/cli/tools/w_ipa.py +832 -0
- westpa/cli/tools/w_kinavg.py +127 -0
- westpa/cli/tools/w_kinetics.py +96 -0
- westpa/cli/tools/w_multi_west.py +414 -0
- westpa/cli/tools/w_ntop.py +213 -0
- westpa/cli/tools/w_pdist.py +515 -0
- westpa/cli/tools/w_postanalysis_matrix.py +82 -0
- westpa/cli/tools/w_postanalysis_reweight.py +53 -0
- westpa/cli/tools/w_red.py +491 -0
- westpa/cli/tools/w_reweight.py +780 -0
- westpa/cli/tools/w_select.py +226 -0
- westpa/cli/tools/w_stateprobs.py +111 -0
- westpa/cli/tools/w_timings.py +113 -0
- westpa/cli/tools/w_trace.py +599 -0
- westpa/core/__init__.py +0 -0
- westpa/core/_rc.py +673 -0
- westpa/core/binning/__init__.py +55 -0
- westpa/core/binning/_assign.c +36018 -0
- westpa/core/binning/_assign.cpython-312-aarch64-linux-gnu.so +0 -0
- westpa/core/binning/_assign.pyx +370 -0
- westpa/core/binning/assign.py +454 -0
- westpa/core/binning/binless.py +96 -0
- westpa/core/binning/binless_driver.py +54 -0
- westpa/core/binning/binless_manager.py +189 -0
- westpa/core/binning/bins.py +47 -0
- westpa/core/binning/mab.py +506 -0
- westpa/core/binning/mab_driver.py +54 -0
- westpa/core/binning/mab_manager.py +197 -0
- westpa/core/data_manager.py +1761 -0
- westpa/core/extloader.py +74 -0
- westpa/core/h5io.py +1079 -0
- westpa/core/kinetics/__init__.py +24 -0
- westpa/core/kinetics/_kinetics.c +45174 -0
- westpa/core/kinetics/_kinetics.cpython-312-aarch64-linux-gnu.so +0 -0
- westpa/core/kinetics/_kinetics.pyx +815 -0
- westpa/core/kinetics/events.py +147 -0
- westpa/core/kinetics/matrates.py +156 -0
- westpa/core/kinetics/rate_averaging.py +266 -0
- westpa/core/progress.py +218 -0
- westpa/core/propagators/__init__.py +54 -0
- westpa/core/propagators/executable.py +592 -0
- westpa/core/propagators/loaders.py +196 -0
- westpa/core/reweight/__init__.py +14 -0
- westpa/core/reweight/_reweight.c +36899 -0
- westpa/core/reweight/_reweight.cpython-312-aarch64-linux-gnu.so +0 -0
- westpa/core/reweight/_reweight.pyx +439 -0
- westpa/core/reweight/matrix.py +126 -0
- westpa/core/segment.py +119 -0
- westpa/core/sim_manager.py +839 -0
- westpa/core/states.py +359 -0
- westpa/core/systems.py +93 -0
- westpa/core/textio.py +74 -0
- westpa/core/trajectory.py +603 -0
- westpa/core/we_driver.py +910 -0
- westpa/core/wm_ops.py +43 -0
- westpa/core/yamlcfg.py +298 -0
- westpa/fasthist/__init__.py +34 -0
- westpa/fasthist/_fasthist.c +38755 -0
- westpa/fasthist/_fasthist.cpython-312-aarch64-linux-gnu.so +0 -0
- westpa/fasthist/_fasthist.pyx +222 -0
- westpa/mclib/__init__.py +271 -0
- westpa/mclib/__main__.py +28 -0
- westpa/mclib/_mclib.c +34610 -0
- westpa/mclib/_mclib.cpython-312-aarch64-linux-gnu.so +0 -0
- westpa/mclib/_mclib.pyx +226 -0
- westpa/oldtools/__init__.py +4 -0
- westpa/oldtools/aframe/__init__.py +35 -0
- westpa/oldtools/aframe/atool.py +75 -0
- westpa/oldtools/aframe/base_mixin.py +26 -0
- westpa/oldtools/aframe/binning.py +178 -0
- westpa/oldtools/aframe/data_reader.py +560 -0
- westpa/oldtools/aframe/iter_range.py +200 -0
- westpa/oldtools/aframe/kinetics.py +117 -0
- westpa/oldtools/aframe/mcbs.py +153 -0
- westpa/oldtools/aframe/output.py +39 -0
- westpa/oldtools/aframe/plotting.py +88 -0
- westpa/oldtools/aframe/trajwalker.py +126 -0
- westpa/oldtools/aframe/transitions.py +469 -0
- westpa/oldtools/cmds/__init__.py +0 -0
- westpa/oldtools/cmds/w_ttimes.py +361 -0
- westpa/oldtools/files.py +34 -0
- westpa/oldtools/miscfn.py +23 -0
- westpa/oldtools/stats/__init__.py +4 -0
- westpa/oldtools/stats/accumulator.py +35 -0
- westpa/oldtools/stats/edfs.py +129 -0
- westpa/oldtools/stats/mcbs.py +96 -0
- westpa/tools/__init__.py +33 -0
- westpa/tools/binning.py +472 -0
- westpa/tools/core.py +340 -0
- westpa/tools/data_reader.py +159 -0
- westpa/tools/dtypes.py +31 -0
- westpa/tools/iter_range.py +198 -0
- westpa/tools/kinetics_tool.py +343 -0
- westpa/tools/plot.py +283 -0
- westpa/tools/progress.py +17 -0
- westpa/tools/selected_segs.py +154 -0
- westpa/tools/wipi.py +751 -0
- westpa/trajtree/__init__.py +4 -0
- westpa/trajtree/_trajtree.c +17829 -0
- westpa/trajtree/_trajtree.cpython-312-aarch64-linux-gnu.so +0 -0
- westpa/trajtree/_trajtree.pyx +130 -0
- westpa/trajtree/trajtree.py +117 -0
- westpa/westext/__init__.py +0 -0
- westpa/westext/adaptvoronoi/__init__.py +3 -0
- westpa/westext/adaptvoronoi/adaptVor_driver.py +214 -0
- westpa/westext/hamsm_restarting/__init__.py +3 -0
- westpa/westext/hamsm_restarting/example_overrides.py +35 -0
- westpa/westext/hamsm_restarting/restart_driver.py +1165 -0
- westpa/westext/stringmethod/__init__.py +11 -0
- westpa/westext/stringmethod/fourier_fitting.py +69 -0
- westpa/westext/stringmethod/string_driver.py +253 -0
- westpa/westext/stringmethod/string_method.py +306 -0
- westpa/westext/weed/BinCluster.py +180 -0
- westpa/westext/weed/ProbAdjustEquil.py +100 -0
- westpa/westext/weed/UncertMath.py +247 -0
- westpa/westext/weed/__init__.py +10 -0
- westpa/westext/weed/weed_driver.py +192 -0
- westpa/westext/wess/ProbAdjust.py +101 -0
- westpa/westext/wess/__init__.py +6 -0
- westpa/westext/wess/wess_driver.py +217 -0
- westpa/work_managers/__init__.py +57 -0
- westpa/work_managers/core.py +396 -0
- westpa/work_managers/environment.py +134 -0
- westpa/work_managers/mpi.py +318 -0
- westpa/work_managers/processes.py +201 -0
- westpa/work_managers/serial.py +28 -0
- westpa/work_managers/threads.py +79 -0
- westpa/work_managers/zeromq/__init__.py +20 -0
- westpa/work_managers/zeromq/core.py +635 -0
- westpa/work_managers/zeromq/node.py +131 -0
- westpa/work_managers/zeromq/work_manager.py +526 -0
- westpa/work_managers/zeromq/worker.py +320 -0
- westpa-2022.13.dist-info/METADATA +179 -0
- westpa-2022.13.dist-info/RECORD +162 -0
- westpa-2022.13.dist-info/WHEEL +7 -0
- westpa-2022.13.dist-info/entry_points.txt +30 -0
- westpa-2022.13.dist-info/licenses/LICENSE +21 -0
- westpa-2022.13.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import operator
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
import westpa
|
|
7
|
+
from westpa.core.yamlcfg import check_bool
|
|
8
|
+
from westpa.core.kinetics import RateAverager
|
|
9
|
+
from westpa.westext.weed.ProbAdjustEquil import probAdjustEquil
|
|
10
|
+
from westpa.core._rc import bins_from_yaml_dict
|
|
11
|
+
|
|
12
|
+
EPS = np.finfo(np.float64).eps
|
|
13
|
+
|
|
14
|
+
log = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class WEEDDriver:
|
|
18
|
+
def __init__(self, sim_manager, plugin_config):
|
|
19
|
+
if not sim_manager.work_manager.is_master:
|
|
20
|
+
return
|
|
21
|
+
|
|
22
|
+
self.sim_manager = sim_manager
|
|
23
|
+
self.data_manager = sim_manager.data_manager
|
|
24
|
+
self.system = sim_manager.system
|
|
25
|
+
self.work_manager = sim_manager.work_manager
|
|
26
|
+
|
|
27
|
+
self.do_reweight = check_bool(
|
|
28
|
+
plugin_config.get('do_equilibrium_reweighting', False) or plugin_config.get('do_reweighting', False)
|
|
29
|
+
)
|
|
30
|
+
self.windowsize = 0.5
|
|
31
|
+
self.windowtype = 'fraction'
|
|
32
|
+
|
|
33
|
+
windowsize = plugin_config.get('window_size')
|
|
34
|
+
if windowsize is not None:
|
|
35
|
+
if isinstance(windowsize, float):
|
|
36
|
+
self.windowsize = windowsize
|
|
37
|
+
self.windowtype = 'fraction'
|
|
38
|
+
if self.windowsize <= 0 or self.windowsize > 1:
|
|
39
|
+
raise ValueError('WEED parameter error -- fractional window size must be in (0,1]')
|
|
40
|
+
elif isinstance(windowsize, int):
|
|
41
|
+
self.windowsize = int(windowsize)
|
|
42
|
+
self.windowtype = 'fixed'
|
|
43
|
+
else:
|
|
44
|
+
raise ValueError('WEED parameter error -- invalid window size {!r}'.format(windowsize))
|
|
45
|
+
log.info('using window size of {!r} ({})'.format(self.windowsize, self.windowtype))
|
|
46
|
+
|
|
47
|
+
self.max_windowsize = plugin_config.get('max_window_size')
|
|
48
|
+
if self.max_windowsize is not None:
|
|
49
|
+
log.info('Using max windowsize of {:d}'.format(self.max_windowsize))
|
|
50
|
+
|
|
51
|
+
self.reweight_period = plugin_config.get('reweight_period', 0)
|
|
52
|
+
self.priority = plugin_config.get('priority', 0)
|
|
53
|
+
|
|
54
|
+
self.rate_calc_queue_size = plugin_config.get('rate_calc_queue_size', 1)
|
|
55
|
+
self.rate_calc_n_blocks = plugin_config.get('rate_calc_n_blocks', 1)
|
|
56
|
+
|
|
57
|
+
bin_obj = plugin_config.get('bins', None)
|
|
58
|
+
if isinstance(bin_obj, dict):
|
|
59
|
+
bin_obj = bins_from_yaml_dict(bin_obj)
|
|
60
|
+
self.bin_mapper = bin_obj
|
|
61
|
+
|
|
62
|
+
if self.do_reweight:
|
|
63
|
+
sim_manager.register_callback(sim_manager.prepare_new_iteration, self.prepare_new_iteration, self.priority)
|
|
64
|
+
|
|
65
|
+
def get_rates(self, n_iter, mapper):
|
|
66
|
+
'''Get rates and associated uncertainties as of n_iter, according to the window size the user
|
|
67
|
+
has selected (self.windowsize)'''
|
|
68
|
+
|
|
69
|
+
if self.windowtype == 'fraction':
|
|
70
|
+
if self.max_windowsize is not None:
|
|
71
|
+
eff_windowsize = min(self.max_windowsize, int(n_iter * self.windowsize))
|
|
72
|
+
else:
|
|
73
|
+
eff_windowsize = int(n_iter * self.windowsize)
|
|
74
|
+
else: # self.windowtype == 'fixed':
|
|
75
|
+
eff_windowsize = min(n_iter, self.windowsize or 0)
|
|
76
|
+
|
|
77
|
+
averager = RateAverager(mapper, self.system, self.data_manager, self.work_manager)
|
|
78
|
+
averager.calculate(max(1, n_iter - eff_windowsize), n_iter + 1, self.rate_calc_n_blocks, self.rate_calc_queue_size)
|
|
79
|
+
self.eff_windowsize = eff_windowsize
|
|
80
|
+
|
|
81
|
+
return averager
|
|
82
|
+
|
|
83
|
+
def prepare_new_iteration(self):
|
|
84
|
+
n_iter = self.sim_manager.n_iter
|
|
85
|
+
we_driver = self.sim_manager.we_driver
|
|
86
|
+
|
|
87
|
+
if we_driver.target_states and self.do_reweight:
|
|
88
|
+
log.warning('equilibrium reweighting requested but target states (sinks) present; reweighting disabled')
|
|
89
|
+
return
|
|
90
|
+
|
|
91
|
+
if not self.do_reweight:
|
|
92
|
+
# Reweighting not requested
|
|
93
|
+
log.debug('Equilibrium reweighting not enabled')
|
|
94
|
+
return
|
|
95
|
+
|
|
96
|
+
with self.data_manager.lock:
|
|
97
|
+
weed_global_group = self.data_manager.we_h5file.require_group('weed')
|
|
98
|
+
reweighting_history_dataset = weed_global_group.require_dataset(
|
|
99
|
+
'reweighting_history', (1,), maxshape=(None,), dtype=int
|
|
100
|
+
)
|
|
101
|
+
last_reweighting = int(weed_global_group.attrs.get('last_reweighting', 0))
|
|
102
|
+
if last_reweighting > n_iter:
|
|
103
|
+
last_reweighting = n_iter - 1
|
|
104
|
+
reweighting_history = reweighting_history_dataset[:]
|
|
105
|
+
reweighting_history = reweighting_history[reweighting_history < n_iter]
|
|
106
|
+
reweighting_history_dataset.resize((reweighting_history.size), axis=0)
|
|
107
|
+
|
|
108
|
+
if n_iter - last_reweighting < self.reweight_period:
|
|
109
|
+
# Not time to reweight yet
|
|
110
|
+
log.debug('not reweighting')
|
|
111
|
+
return
|
|
112
|
+
else:
|
|
113
|
+
log.debug('reweighting')
|
|
114
|
+
|
|
115
|
+
if self.bin_mapper is None:
|
|
116
|
+
mapper = we_driver.bin_mapper
|
|
117
|
+
bins = we_driver.next_iter_binning
|
|
118
|
+
westpa.rc.pstatus('\nReweighting using the simulation bin mapper:\n{}'.format(mapper))
|
|
119
|
+
else:
|
|
120
|
+
mapper = self.bin_mapper
|
|
121
|
+
bins = mapper.construct_bins()
|
|
122
|
+
|
|
123
|
+
segments = [s for s in we_driver.next_iter_segments]
|
|
124
|
+
pcoords = self.system.new_pcoord_array(len(segments))
|
|
125
|
+
for iseg, segment in enumerate(segments):
|
|
126
|
+
pcoords[iseg] = segment.pcoord[0]
|
|
127
|
+
assignments = mapper.assign(pcoords)
|
|
128
|
+
for segment, assignment in zip(segments, assignments):
|
|
129
|
+
bins[assignment].add(segment)
|
|
130
|
+
|
|
131
|
+
westpa.rc.pstatus('\nReweighting using a different bin mapper than simulation:\n{}'.format(mapper))
|
|
132
|
+
|
|
133
|
+
n_bins = len(bins)
|
|
134
|
+
|
|
135
|
+
# Create storage for ourselves
|
|
136
|
+
with self.data_manager.lock:
|
|
137
|
+
iter_group = self.data_manager.get_iter_group(n_iter)
|
|
138
|
+
try:
|
|
139
|
+
del iter_group['weed']
|
|
140
|
+
except KeyError:
|
|
141
|
+
pass
|
|
142
|
+
|
|
143
|
+
weed_iter_group = iter_group.create_group('weed')
|
|
144
|
+
avg_populations_ds = weed_iter_group.create_dataset('avg_populations', shape=(n_bins,), dtype=np.float64)
|
|
145
|
+
unc_populations_ds = weed_iter_group.create_dataset('unc_populations', shape=(n_bins,), dtype=np.float64)
|
|
146
|
+
avg_flux_ds = weed_iter_group.create_dataset('avg_fluxes', shape=(n_bins, n_bins), dtype=np.float64)
|
|
147
|
+
unc_flux_ds = weed_iter_group.create_dataset('unc_fluxes', shape=(n_bins, n_bins), dtype=np.float64)
|
|
148
|
+
avg_rates_ds = weed_iter_group.create_dataset('avg_rates', shape=(n_bins, n_bins), dtype=np.float64)
|
|
149
|
+
unc_rates_ds = weed_iter_group.create_dataset('unc_rates', shape=(n_bins, n_bins), dtype=np.float64)
|
|
150
|
+
|
|
151
|
+
averager = self.get_rates(n_iter, mapper)
|
|
152
|
+
|
|
153
|
+
with self.data_manager.flushing_lock():
|
|
154
|
+
avg_populations_ds[...] = averager.average_populations
|
|
155
|
+
unc_populations_ds[...] = averager.stderr_populations
|
|
156
|
+
avg_flux_ds[...] = averager.average_flux
|
|
157
|
+
unc_flux_ds[...] = averager.stderr_flux
|
|
158
|
+
avg_rates_ds[...] = averager.average_rate
|
|
159
|
+
unc_rates_ds[...] = averager.stderr_rate
|
|
160
|
+
|
|
161
|
+
binprobs = np.fromiter(map(operator.attrgetter('weight'), bins), dtype=np.float64, count=n_bins)
|
|
162
|
+
orig_binprobs = binprobs.copy()
|
|
163
|
+
|
|
164
|
+
westpa.rc.pstatus('Calculating equilibrium reweighting using window size of {:d}'.format(self.eff_windowsize))
|
|
165
|
+
westpa.rc.pstatus('\nBin probabilities prior to reweighting:\n{!s}'.format(binprobs))
|
|
166
|
+
westpa.rc.pflush()
|
|
167
|
+
|
|
168
|
+
probAdjustEquil(binprobs, averager.average_rate, averager.stderr_rate)
|
|
169
|
+
|
|
170
|
+
# Check to see if reweighting has set non-zero bins to zero probability (should never happen)
|
|
171
|
+
assert (~((orig_binprobs > 0) & (binprobs == 0))).all(), 'populated bin reweighted to zero probability'
|
|
172
|
+
|
|
173
|
+
# Check to see if reweighting has set zero bins to nonzero probability (may happen)
|
|
174
|
+
z2nz_mask = (orig_binprobs == 0) & (binprobs > 0)
|
|
175
|
+
if (z2nz_mask).any():
|
|
176
|
+
westpa.rc.pstatus('Reweighting would assign nonzero probability to an empty bin; not reweighting this iteration.')
|
|
177
|
+
westpa.rc.pstatus('Empty bins assigned nonzero probability: {!s}.'.format(np.array_str(np.arange(n_bins)[z2nz_mask])))
|
|
178
|
+
else:
|
|
179
|
+
westpa.rc.pstatus('\nBin populations after reweighting:\n{!s}'.format(binprobs))
|
|
180
|
+
for bin, newprob in zip(bins, binprobs):
|
|
181
|
+
bin.reweight(newprob)
|
|
182
|
+
|
|
183
|
+
reweighting_history_dataset.resize((reweighting_history_dataset.shape[0] + 1), axis=0)
|
|
184
|
+
reweighting_history_dataset[-1] = n_iter
|
|
185
|
+
weed_global_group.attrs['last_reweighting'] = n_iter
|
|
186
|
+
|
|
187
|
+
assert (
|
|
188
|
+
abs(1 - np.fromiter(map(operator.attrgetter('weight'), bins), dtype=np.float64, count=n_bins).sum())
|
|
189
|
+
< EPS * np.fromiter(map(len, bins), dtype=int, count=n_bins).sum()
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
westpa.rc.pflush()
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import scipy.optimize
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def solve_steady_state(T, U, target_bins_index):
|
|
6
|
+
ntarget = len(target_bins_index) # Number of target states
|
|
7
|
+
nstates = T.shape[0] # Number of total states
|
|
8
|
+
|
|
9
|
+
# Number of active states
|
|
10
|
+
nsolve = nstates - ntarget
|
|
11
|
+
|
|
12
|
+
# list of active states
|
|
13
|
+
sactive = sorted(list(set(range(nstates)) - set(target_bins_index)))
|
|
14
|
+
|
|
15
|
+
W = np.zeros((nsolve, nsolve))
|
|
16
|
+
W_unc = np.zeros((nsolve, nsolve))
|
|
17
|
+
S = np.zeros((nsolve,))
|
|
18
|
+
|
|
19
|
+
for iiw, iit in zip(range(nsolve), sactive):
|
|
20
|
+
for jjw, jjt in zip(range(nsolve), sactive):
|
|
21
|
+
W[iiw, jjw] = T[jjt, iit]
|
|
22
|
+
W_unc[iiw, jjw] = U[jjt, iit]
|
|
23
|
+
|
|
24
|
+
for ii in range(nsolve):
|
|
25
|
+
W[ii, ii] = 0.0
|
|
26
|
+
for jj in range(nstates): # nstates
|
|
27
|
+
if jj != ii:
|
|
28
|
+
W[ii, ii] -= T[ii, jj]
|
|
29
|
+
|
|
30
|
+
# we have n equations, but only n-1 linearly independent equations
|
|
31
|
+
# set one equation to constraint sum(Pi)=1
|
|
32
|
+
|
|
33
|
+
# Pick row that contains the largest uncertainty to replace
|
|
34
|
+
ii = np.unravel_index(np.argmax(W_unc), W_unc.shape)[1]
|
|
35
|
+
|
|
36
|
+
S[ii] = 1.0
|
|
37
|
+
W[ii, :] = 1.0
|
|
38
|
+
|
|
39
|
+
# P = np.linalg.solve(W,S)
|
|
40
|
+
try:
|
|
41
|
+
P, err = scipy.optimize.nnls(W, S)
|
|
42
|
+
except RuntimeError:
|
|
43
|
+
print('Solve did not converge')
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
# There are some instances where a single bin has its prob set
|
|
47
|
+
# to 1.0; In this case do not reweight
|
|
48
|
+
if np.allclose(np.max(P), 1.0):
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
pp = np.matrix(W) * np.matrix(P.reshape(-1, 1))
|
|
52
|
+
|
|
53
|
+
print('WESS: M*p = {}'.format(pp))
|
|
54
|
+
print('WESS: max = {}'.format(np.max(pp)))
|
|
55
|
+
|
|
56
|
+
return P, err, sactive
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def prob_adjust(binprob, rates, uncert, oldindex, targets=[]):
|
|
60
|
+
nbins = binprob.size
|
|
61
|
+
|
|
62
|
+
result = solve_steady_state(rates, uncert, targets)
|
|
63
|
+
|
|
64
|
+
if result is None:
|
|
65
|
+
return binprob
|
|
66
|
+
else:
|
|
67
|
+
ss_estimate, err, active_bins = result
|
|
68
|
+
|
|
69
|
+
print('WESS NNLS norm: {}'.format(err))
|
|
70
|
+
|
|
71
|
+
# now remap new_weights onto the bin indices
|
|
72
|
+
MappedActiveBins = []
|
|
73
|
+
for ibin in active_bins:
|
|
74
|
+
MappedActiveBins.append(oldindex[ibin])
|
|
75
|
+
|
|
76
|
+
mapped_new_weights = np.zeros((nbins,))
|
|
77
|
+
mapped_new_weights[MappedActiveBins] = ss_estimate
|
|
78
|
+
|
|
79
|
+
# Check to make sure no bins with non-zero probability end up with zero prob after reweighting
|
|
80
|
+
orig_nzi = np.nonzero(binprob)[0] # bins that originally had non-zero prob
|
|
81
|
+
new_zi = np.where(mapped_new_weights == 0.0)[0] # bins that after reweight have zero prob
|
|
82
|
+
ri = np.intersect1d(orig_nzi, new_zi) # bins to reset
|
|
83
|
+
mapped_new_weights[ri] = 1.0e-16
|
|
84
|
+
|
|
85
|
+
# Check to make sure no bins with zero probability end up with nonzero prob after reweighting
|
|
86
|
+
orig_zi = np.where(binprob == 0.0)[0] # bins that originally had zero prob
|
|
87
|
+
new_nzi = np.nonzero(mapped_new_weights)[0] # bins that after reweight have non-zero prob
|
|
88
|
+
ri = np.intersect1d(orig_zi, new_nzi) # bins to reset
|
|
89
|
+
mapped_new_weights[ri] = 0.0
|
|
90
|
+
|
|
91
|
+
# Ensure that all target bins have their weight set to zero
|
|
92
|
+
MappedTargetBins = []
|
|
93
|
+
for ibin in targets:
|
|
94
|
+
MappedTargetBins.append(oldindex[ibin])
|
|
95
|
+
mapped_new_weights[MappedTargetBins] = 0.0
|
|
96
|
+
|
|
97
|
+
mapped_new_weights /= np.sum(mapped_new_weights)
|
|
98
|
+
|
|
99
|
+
assert not (mapped_new_weights < 0).any()
|
|
100
|
+
|
|
101
|
+
return mapped_new_weights
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import operator
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
import westpa
|
|
7
|
+
from westpa.core.yamlcfg import check_bool
|
|
8
|
+
from westpa.core.kinetics import RateAverager
|
|
9
|
+
from westpa.westext.wess.ProbAdjust import prob_adjust
|
|
10
|
+
from westpa.core._rc import bins_from_yaml_dict
|
|
11
|
+
|
|
12
|
+
EPS = np.finfo(np.float64).eps
|
|
13
|
+
|
|
14
|
+
log = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def reduce_array(Aij):
|
|
18
|
+
"""Remove empty rows and columns from an array Aij and return the reduced
|
|
19
|
+
array Bij and the list of non-empty states"""
|
|
20
|
+
|
|
21
|
+
nonempty = list(range(0, Aij.shape[0]))
|
|
22
|
+
eps = np.finfo(Aij.dtype).eps
|
|
23
|
+
|
|
24
|
+
for i in range(0, Aij.shape[0]):
|
|
25
|
+
if (Aij[i, :] < eps).all() and (Aij[:, i] < eps).all():
|
|
26
|
+
nonempty.pop(nonempty.index(i))
|
|
27
|
+
|
|
28
|
+
nne = len(nonempty)
|
|
29
|
+
Bij = np.zeros((nne, nne))
|
|
30
|
+
|
|
31
|
+
for i in range(0, nne):
|
|
32
|
+
for j in range(0, nne):
|
|
33
|
+
Bij[i, j] = Aij[nonempty[i], nonempty[j]]
|
|
34
|
+
|
|
35
|
+
return Bij, nonempty
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class WESSDriver:
|
|
39
|
+
def __init__(self, sim_manager, plugin_config):
|
|
40
|
+
if not sim_manager.work_manager.is_master:
|
|
41
|
+
return
|
|
42
|
+
|
|
43
|
+
self.sim_manager = sim_manager
|
|
44
|
+
self.data_manager = sim_manager.data_manager
|
|
45
|
+
self.system = sim_manager.system
|
|
46
|
+
self.work_manager = sim_manager.work_manager
|
|
47
|
+
|
|
48
|
+
self.do_reweight = check_bool(plugin_config.get('do_reweighting', False))
|
|
49
|
+
self.windowsize = 0.5
|
|
50
|
+
self.windowtype = 'fraction'
|
|
51
|
+
|
|
52
|
+
windowsize = plugin_config.get('window_size')
|
|
53
|
+
if windowsize is not None:
|
|
54
|
+
if isinstance(windowsize, float):
|
|
55
|
+
self.windowsize = windowsize
|
|
56
|
+
self.windowtype = 'fraction'
|
|
57
|
+
if self.windowsize <= 0 or self.windowsize > 1:
|
|
58
|
+
raise ValueError('WESS parameter error -- fractional window size must be in (0,1]')
|
|
59
|
+
elif isinstance(windowsize, int):
|
|
60
|
+
self.windowsize = int(windowsize)
|
|
61
|
+
self.windowtype = 'fixed'
|
|
62
|
+
else:
|
|
63
|
+
raise ValueError('WESS parameter error -- invalid window size {!r}'.format(windowsize))
|
|
64
|
+
log.info('using window size of {!r} ({})'.format(self.windowsize, self.windowtype))
|
|
65
|
+
|
|
66
|
+
self.max_windowsize = plugin_config.get('max_window_size')
|
|
67
|
+
if self.max_windowsize is not None:
|
|
68
|
+
log.info('Using max windowsize of {:d}'.format(self.max_windowsize))
|
|
69
|
+
|
|
70
|
+
self.reweight_period = plugin_config.get('reweight_period', 0)
|
|
71
|
+
self.priority = plugin_config.get('priority', 0)
|
|
72
|
+
|
|
73
|
+
self.rate_calc_queue_size = plugin_config.get('rate_calc_queue_size', 1)
|
|
74
|
+
self.rate_calc_n_blocks = plugin_config.get('rate_calc_n_blocks', 1)
|
|
75
|
+
|
|
76
|
+
bin_obj = plugin_config.get('bins', None)
|
|
77
|
+
if isinstance(bin_obj, dict):
|
|
78
|
+
bin_obj = bins_from_yaml_dict(bin_obj)
|
|
79
|
+
self.bin_mapper = bin_obj
|
|
80
|
+
|
|
81
|
+
if self.do_reweight:
|
|
82
|
+
sim_manager.register_callback(sim_manager.prepare_new_iteration, self.prepare_new_iteration, self.priority)
|
|
83
|
+
|
|
84
|
+
self.write_matrices = plugin_config.get('write_matrices', False)
|
|
85
|
+
|
|
86
|
+
def get_rates(self, n_iter, mapper):
|
|
87
|
+
'''Get rates and associated uncertainties as of n_iter, according to the window size the user
|
|
88
|
+
has selected (self.windowsize)'''
|
|
89
|
+
|
|
90
|
+
if self.windowtype == 'fraction':
|
|
91
|
+
if self.max_windowsize is not None:
|
|
92
|
+
eff_windowsize = min(self.max_windowsize, int(n_iter * self.windowsize))
|
|
93
|
+
else:
|
|
94
|
+
eff_windowsize = int(n_iter * self.windowsize)
|
|
95
|
+
else: # self.windowtype == 'fixed':
|
|
96
|
+
eff_windowsize = min(n_iter, self.windowsize or 0)
|
|
97
|
+
|
|
98
|
+
averager = RateAverager(mapper, self.system, self.data_manager, self.work_manager)
|
|
99
|
+
averager.calculate(max(1, n_iter - eff_windowsize), n_iter + 1, self.rate_calc_n_blocks, self.rate_calc_queue_size)
|
|
100
|
+
self.eff_windowsize = eff_windowsize
|
|
101
|
+
|
|
102
|
+
return averager
|
|
103
|
+
|
|
104
|
+
def prepare_new_iteration(self):
|
|
105
|
+
n_iter = self.sim_manager.n_iter
|
|
106
|
+
we_driver = self.sim_manager.we_driver
|
|
107
|
+
|
|
108
|
+
if not self.do_reweight:
|
|
109
|
+
# Reweighting not requested (or not possible)
|
|
110
|
+
log.debug('Reweighting not enabled')
|
|
111
|
+
return
|
|
112
|
+
|
|
113
|
+
with self.data_manager.lock:
|
|
114
|
+
wess_global_group = self.data_manager.we_h5file.require_group('wess')
|
|
115
|
+
reweighting_history_dataset = wess_global_group.require_dataset(
|
|
116
|
+
'reweighting_history', (1,), maxshape=(None,), dtype=int
|
|
117
|
+
)
|
|
118
|
+
last_reweighting = int(wess_global_group.attrs.get('last_reweighting', 0))
|
|
119
|
+
if last_reweighting > n_iter:
|
|
120
|
+
last_reweighting = n_iter - 1
|
|
121
|
+
reweighting_history = reweighting_history_dataset[:]
|
|
122
|
+
reweighting_history = reweighting_history[reweighting_history < n_iter]
|
|
123
|
+
reweighting_history_dataset.resize((reweighting_history.size), axis=0)
|
|
124
|
+
|
|
125
|
+
if n_iter - last_reweighting < self.reweight_period:
|
|
126
|
+
# Not time to reweight yet
|
|
127
|
+
log.debug('not reweighting')
|
|
128
|
+
return
|
|
129
|
+
else:
|
|
130
|
+
log.debug('reweighting')
|
|
131
|
+
|
|
132
|
+
if self.bin_mapper is None:
|
|
133
|
+
mapper = we_driver.bin_mapper
|
|
134
|
+
bins = we_driver.next_iter_binning
|
|
135
|
+
target_regions = list(we_driver.target_states.keys())
|
|
136
|
+
westpa.rc.pstatus('\nReweighting using the simulation bin mapper:\n{}'.format(mapper))
|
|
137
|
+
else:
|
|
138
|
+
mapper = self.bin_mapper
|
|
139
|
+
bins = mapper.construct_bins()
|
|
140
|
+
|
|
141
|
+
segments = [s for s in we_driver.next_iter_segments]
|
|
142
|
+
pcoords = self.system.new_pcoord_array(len(segments))
|
|
143
|
+
for iseg, segment in enumerate(segments):
|
|
144
|
+
pcoords[iseg] = segment.pcoord[0]
|
|
145
|
+
assignments = mapper.assign(pcoords)
|
|
146
|
+
for segment, assignment in zip(segments, assignments):
|
|
147
|
+
bins[assignment].add(segment)
|
|
148
|
+
|
|
149
|
+
target_states = list(we_driver.target_states.values())
|
|
150
|
+
target_regions = []
|
|
151
|
+
for tstate in target_states:
|
|
152
|
+
tstate_assignment = mapper.assign([tstate.pcoord])[0]
|
|
153
|
+
target_regions.append(tstate_assignment)
|
|
154
|
+
westpa.rc.pstatus('\nReweighting using a different bin mapper than simulation:\n{}'.format(mapper))
|
|
155
|
+
|
|
156
|
+
n_bins = len(bins)
|
|
157
|
+
westpa.rc.pstatus('Averaging rates')
|
|
158
|
+
averager = self.get_rates(n_iter, mapper)
|
|
159
|
+
binprobs = np.fromiter(map(operator.attrgetter('weight'), bins), dtype=np.float64, count=n_bins)
|
|
160
|
+
orig_binprobs = binprobs.copy()
|
|
161
|
+
|
|
162
|
+
if self.write_matrices:
|
|
163
|
+
# Create storage for ourselves
|
|
164
|
+
with self.data_manager.lock:
|
|
165
|
+
iter_group = self.data_manager.get_iter_group(n_iter)
|
|
166
|
+
try:
|
|
167
|
+
del iter_group['wess']
|
|
168
|
+
except KeyError:
|
|
169
|
+
pass
|
|
170
|
+
|
|
171
|
+
wess_iter_group = iter_group.create_group('wess')
|
|
172
|
+
wess_iter_group.create_dataset('avg_populations', data=averager.average_populations, compression=4)
|
|
173
|
+
wess_iter_group.create_dataset('unc_populations', data=averager.stderr_populations, compression=4)
|
|
174
|
+
wess_iter_group.create_dataset('avg_fluxes', data=averager.average_flux, compression=4)
|
|
175
|
+
wess_iter_group.create_dataset('unc_fluxes', data=averager.stderr_flux, compression=4)
|
|
176
|
+
wess_iter_group.create_dataset('avg_rates', data=averager.average_rate, compression=4)
|
|
177
|
+
wess_iter_group.create_dataset('unc_rates', data=averager.stderr_rate, compression=4)
|
|
178
|
+
|
|
179
|
+
westpa.rc.pstatus('Calculating reweighting using window size of {:d}'.format(self.eff_windowsize))
|
|
180
|
+
westpa.rc.pstatus('\nBin probabilities prior to reweighting:\n{!s}'.format(binprobs))
|
|
181
|
+
westpa.rc.pflush()
|
|
182
|
+
|
|
183
|
+
rij, oldindex = reduce_array(averager.average_rate)
|
|
184
|
+
uij = averager.stderr_rate[np.ix_(oldindex, oldindex)]
|
|
185
|
+
|
|
186
|
+
flat_target_regions = []
|
|
187
|
+
for target_region in target_regions:
|
|
188
|
+
if target_region in oldindex: # it is possible that the target region was removed (ie if no recycling has occurred)
|
|
189
|
+
new_ibin = oldindex.index(target_region) # this is in terms of the Rij
|
|
190
|
+
flat_target_regions.append(new_ibin)
|
|
191
|
+
|
|
192
|
+
binprobs = prob_adjust(binprobs, rij, uij, oldindex, flat_target_regions)
|
|
193
|
+
|
|
194
|
+
# Check to see if reweighting has set non-zero bins to zero probability (should never happen)
|
|
195
|
+
assert (~((orig_binprobs > 0) & (binprobs == 0))).all(), 'populated bin reweighted to zero probability'
|
|
196
|
+
|
|
197
|
+
# Check to see if reweighting has set zero bins to nonzero probability (may happen)
|
|
198
|
+
z2nz_mask = (orig_binprobs == 0) & (binprobs > 0)
|
|
199
|
+
if (z2nz_mask).any():
|
|
200
|
+
westpa.rc.pstatus('Reweighting would assign nonzero probability to an empty bin; not reweighting this iteration.')
|
|
201
|
+
westpa.rc.pstatus('Empty bins assigned nonzero probability: {!s}.'.format(np.array_str(np.arange(n_bins)[z2nz_mask])))
|
|
202
|
+
else:
|
|
203
|
+
westpa.rc.pstatus('\nBin populations after reweighting:\n{!s}'.format(binprobs))
|
|
204
|
+
for bin, newprob in zip(bins, binprobs):
|
|
205
|
+
if len(bin):
|
|
206
|
+
bin.reweight(newprob)
|
|
207
|
+
|
|
208
|
+
reweighting_history_dataset.resize((reweighting_history_dataset.shape[0] + 1), axis=0)
|
|
209
|
+
reweighting_history_dataset[-1] = n_iter
|
|
210
|
+
wess_global_group.attrs['last_reweighting'] = n_iter
|
|
211
|
+
|
|
212
|
+
assert (
|
|
213
|
+
abs(1 - np.fromiter(map(operator.attrgetter('weight'), bins), dtype=np.float64, count=n_bins).sum())
|
|
214
|
+
< EPS * np.fromiter(map(len, bins), dtype=int, count=n_bins).sum()
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
westpa.rc.pflush()
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'''A system for parallel, remote execution of multiple arbitrary tasks.
|
|
2
|
+
Much of this, both in concept and execution, was inspired by (and in some
|
|
3
|
+
cases based heavily on) the ``concurrent.futures`` package from Python 3.2,
|
|
4
|
+
with some simplifications and adaptations (thanks to Brian Quinlan and his
|
|
5
|
+
futures implementation).
|
|
6
|
+
'''
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
from .core import WorkManager, WMFuture, FutureWatcher # noqa
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# Import core work managers, which should run most everywhere that
|
|
14
|
+
# Python does
|
|
15
|
+
from . import serial, threads, processes # noqa
|
|
16
|
+
from .serial import SerialWorkManager
|
|
17
|
+
from .threads import ThreadsWorkManager
|
|
18
|
+
from .processes import ProcessWorkManager
|
|
19
|
+
|
|
20
|
+
log = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
_available_work_managers = {'serial': SerialWorkManager, 'threads': ThreadsWorkManager, 'processes': ProcessWorkManager}
|
|
23
|
+
|
|
24
|
+
# Import ZeroMQ work manager if available
|
|
25
|
+
try:
|
|
26
|
+
from . import zeromq # noqa
|
|
27
|
+
from .zeromq import ZMQWorkManager
|
|
28
|
+
except ImportError:
|
|
29
|
+
log.info('ZeroMQ work manager not available')
|
|
30
|
+
log.debug('traceback follows', exc_info=True)
|
|
31
|
+
else:
|
|
32
|
+
_available_work_managers['zmq'] = ZMQWorkManager
|
|
33
|
+
|
|
34
|
+
# Import MPI work manager if available
|
|
35
|
+
try:
|
|
36
|
+
from . import mpi # noqa
|
|
37
|
+
from .mpi import MPIWorkManager
|
|
38
|
+
except ImportError:
|
|
39
|
+
log.info('MPI work manager not available')
|
|
40
|
+
log.debug('traceback follows', exc_info=True)
|
|
41
|
+
else:
|
|
42
|
+
_available_work_managers['mpi'] = MPIWorkManager
|
|
43
|
+
|
|
44
|
+
from . import environment # noqa
|
|
45
|
+
from .environment import make_work_manager # noqa
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
__all__ = [
|
|
49
|
+
'serial',
|
|
50
|
+
'threads',
|
|
51
|
+
'processes',
|
|
52
|
+
'SerialWorkManager',
|
|
53
|
+
'ThreadsWorkManager',
|
|
54
|
+
'ProcessWorkManager',
|
|
55
|
+
'environment',
|
|
56
|
+
'make_work_manager',
|
|
57
|
+
]
|