westpa 2022.10__cp312-cp312-macosx_10_9_x86_64.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.
Potentially problematic release.
This version of westpa might be problematic. Click here for more details.
- westpa/__init__.py +14 -0
- westpa/_version.py +21 -0
- westpa/analysis/__init__.py +5 -0
- westpa/analysis/core.py +746 -0
- westpa/analysis/statistics.py +27 -0
- westpa/analysis/trajectories.py +360 -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 +59 -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 +596 -0
- westpa/cli/tools/w_bins.py +166 -0
- westpa/cli/tools/w_crawl.py +119 -0
- westpa/cli/tools/w_direct.py +547 -0
- westpa/cli/tools/w_dumpsegs.py +94 -0
- westpa/cli/tools/w_eddist.py +506 -0
- westpa/cli/tools/w_fluxanl.py +378 -0
- westpa/cli/tools/w_ipa.py +833 -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 +486 -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_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.cpython-312-darwin.so +0 -0
- westpa/core/binning/assign.py +449 -0
- westpa/core/binning/binless.py +96 -0
- westpa/core/binning/binless_driver.py +54 -0
- westpa/core/binning/binless_manager.py +190 -0
- westpa/core/binning/bins.py +47 -0
- westpa/core/binning/mab.py +427 -0
- westpa/core/binning/mab_driver.py +54 -0
- westpa/core/binning/mab_manager.py +198 -0
- westpa/core/data_manager.py +1694 -0
- westpa/core/extloader.py +74 -0
- westpa/core/h5io.py +995 -0
- westpa/core/kinetics/__init__.py +24 -0
- westpa/core/kinetics/_kinetics.cpython-312-darwin.so +0 -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 +715 -0
- westpa/core/reweight/__init__.py +14 -0
- westpa/core/reweight/_reweight.cpython-312-darwin.so +0 -0
- westpa/core/reweight/matrix.py +126 -0
- westpa/core/segment.py +119 -0
- westpa/core/sim_manager.py +830 -0
- westpa/core/states.py +359 -0
- westpa/core/systems.py +93 -0
- westpa/core/textio.py +74 -0
- westpa/core/trajectory.py +330 -0
- westpa/core/we_driver.py +908 -0
- westpa/core/wm_ops.py +43 -0
- westpa/core/yamlcfg.py +391 -0
- westpa/fasthist/__init__.py +34 -0
- westpa/fasthist/__main__.py +110 -0
- westpa/fasthist/_fasthist.cpython-312-darwin.so +0 -0
- westpa/mclib/__init__.py +264 -0
- westpa/mclib/__main__.py +28 -0
- westpa/mclib/_mclib.cpython-312-darwin.so +0 -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 +146 -0
- westpa/oldtools/aframe/output.py +39 -0
- westpa/oldtools/aframe/plotting.py +90 -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 +358 -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 +89 -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 +340 -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.cpython-312-darwin.so +0 -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 +182 -0
- westpa/westext/wess/ProbAdjust.py +101 -0
- westpa/westext/wess/__init__.py +6 -0
- westpa/westext/wess/wess_driver.py +207 -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 +187 -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 +641 -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.10.dist-info/AUTHORS +22 -0
- westpa-2022.10.dist-info/LICENSE +21 -0
- westpa-2022.10.dist-info/METADATA +183 -0
- westpa-2022.10.dist-info/RECORD +150 -0
- westpa-2022.10.dist-info/WHEEL +5 -0
- westpa-2022.10.dist-info/entry_points.txt +29 -0
- westpa-2022.10.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
import westpa
|
|
7
|
+
from westpa.oldtools.aframe import AnalysisMixin, ArgumentError
|
|
8
|
+
|
|
9
|
+
log = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class IterRangeMixin(AnalysisMixin):
|
|
13
|
+
'''A mixin for limiting the range of data considered for a given analysis. This should go after
|
|
14
|
+
DataManagerMixin'''
|
|
15
|
+
|
|
16
|
+
def __init__(self):
|
|
17
|
+
super().__init__()
|
|
18
|
+
|
|
19
|
+
self.first_iter = None
|
|
20
|
+
self.last_iter = None
|
|
21
|
+
self.iter_step = 1
|
|
22
|
+
|
|
23
|
+
include_args = self.include_args.setdefault('IterRangeMixin', {})
|
|
24
|
+
include_args.setdefault('first_iter', True)
|
|
25
|
+
include_args.setdefault('last_iter', True)
|
|
26
|
+
include_args.setdefault('iter_step', True)
|
|
27
|
+
|
|
28
|
+
def add_args(self, parser, upcall=True):
|
|
29
|
+
if upcall:
|
|
30
|
+
try:
|
|
31
|
+
upfunc = super().add_args
|
|
32
|
+
except AttributeError:
|
|
33
|
+
pass
|
|
34
|
+
else:
|
|
35
|
+
upfunc(parser)
|
|
36
|
+
|
|
37
|
+
group = parser.add_argument_group('analysis range')
|
|
38
|
+
if self.include_args['IterRangeMixin']['first_iter']:
|
|
39
|
+
group.add_argument(
|
|
40
|
+
'--start',
|
|
41
|
+
'--begin',
|
|
42
|
+
'--first',
|
|
43
|
+
dest='first_iter',
|
|
44
|
+
type=int,
|
|
45
|
+
metavar='N_ITER',
|
|
46
|
+
default=1,
|
|
47
|
+
help='''Begin analysis at iteration N_ITER (default: %(default)d).''',
|
|
48
|
+
)
|
|
49
|
+
if self.include_args['IterRangeMixin']['last_iter']:
|
|
50
|
+
group.add_argument(
|
|
51
|
+
'--stop',
|
|
52
|
+
'--end',
|
|
53
|
+
'--last',
|
|
54
|
+
dest='last_iter',
|
|
55
|
+
type=int,
|
|
56
|
+
metavar='N_ITER',
|
|
57
|
+
help='''Conclude analysis with N_ITER, inclusive (default: last completed iteration).''',
|
|
58
|
+
)
|
|
59
|
+
if self.include_args['IterRangeMixin']['iter_step']:
|
|
60
|
+
group.add_argument(
|
|
61
|
+
'--step', dest='iter_step', type=int, metavar='STEP', help='''Analyze/report in blocks of STEP iterations.'''
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
def process_args(self, args, upcall=True):
|
|
65
|
+
if self.include_args['IterRangeMixin']['first_iter']:
|
|
66
|
+
self.first_iter = args.first_iter or 1
|
|
67
|
+
if self.include_args['IterRangeMixin']['last_iter']:
|
|
68
|
+
self.last_iter = args.last_iter
|
|
69
|
+
if self.include_args['IterRangeMixin']['iter_step']:
|
|
70
|
+
self.iter_step = args.iter_step or 1
|
|
71
|
+
|
|
72
|
+
if upcall:
|
|
73
|
+
try:
|
|
74
|
+
upfunc = super().process_args
|
|
75
|
+
except AttributeError:
|
|
76
|
+
pass
|
|
77
|
+
else:
|
|
78
|
+
upfunc(args)
|
|
79
|
+
|
|
80
|
+
def check_iter_range(self):
|
|
81
|
+
assert hasattr(self, 'data_manager') and self.data_manager is not None
|
|
82
|
+
|
|
83
|
+
self.first_iter = int(max(self.first_iter, 1))
|
|
84
|
+
if self.last_iter is None or self.last_iter > self.data_manager.current_iteration - 1:
|
|
85
|
+
self.last_iter = int(self.data_manager.current_iteration - 1)
|
|
86
|
+
|
|
87
|
+
if self.first_iter == self.last_iter:
|
|
88
|
+
raise ArgumentError('first and last iterations are the same')
|
|
89
|
+
|
|
90
|
+
westpa.rc.pstatus(
|
|
91
|
+
'Processing iterations from {self.first_iter:d} to {self.last_iter:d}, inclusive (step size {self.iter_step:d})'.format(
|
|
92
|
+
self=self
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
def iter_block_iter(self):
|
|
97
|
+
'''Return an iterable of (block_first,block_last+1) over the blocks of iterations
|
|
98
|
+
selected by --first/--last/--step. NOTE WELL that the second of the pair follows Python
|
|
99
|
+
iterator conventions and returns one past the last element of the block.'''
|
|
100
|
+
|
|
101
|
+
for blkfirst in range(self.first_iter, self.last_iter + 1, self.iter_step):
|
|
102
|
+
yield (blkfirst, min(self.last_iter, blkfirst + self.iter_step - 1) + 1)
|
|
103
|
+
|
|
104
|
+
def n_iter_blocks(self):
|
|
105
|
+
'''Return the number of blocks of iterations (as returned by ``iter_block_iter``) selected by --first/--last/--step.'''
|
|
106
|
+
npoints = self.last_iter - self.first_iter + 1
|
|
107
|
+
if npoints % self.iter_step == 0:
|
|
108
|
+
return npoints // self.iter_step
|
|
109
|
+
else:
|
|
110
|
+
return npoints // self.iter_step + 1
|
|
111
|
+
|
|
112
|
+
def record_data_iter_range(self, h5object, first_iter=None, last_iter=None):
|
|
113
|
+
'''Store attributes ``first_iter`` and ``last_iter`` on the given HDF5 object (group/dataset)'''
|
|
114
|
+
first_iter = first_iter or self.first_iter
|
|
115
|
+
last_iter = last_iter or self.last_iter
|
|
116
|
+
h5object.attrs['first_iter'] = first_iter
|
|
117
|
+
h5object.attrs['last_iter'] = last_iter
|
|
118
|
+
|
|
119
|
+
def record_data_iter_step(self, h5object, iter_step=None):
|
|
120
|
+
'''Store attribute ``iter_step`` on the given HDF5 object (group/dataset).'''
|
|
121
|
+
iter_step = iter_step or self.iter_step
|
|
122
|
+
h5object.attrs['iter_step'] = iter_step
|
|
123
|
+
|
|
124
|
+
def check_data_iter_range_least(self, h5object, first_iter=None, last_iter=None):
|
|
125
|
+
'''Check that the given HDF5 object contains (as denoted by its ``first_iter``/``last_iter`` attributes) at least the
|
|
126
|
+
data range specified.'''
|
|
127
|
+
first_iter = first_iter or self.first_iter
|
|
128
|
+
last_iter = last_iter or self.last_iter
|
|
129
|
+
|
|
130
|
+
obj_first_iter = h5object.attrs.get('first_iter')
|
|
131
|
+
obj_last_iter = h5object.attrs.get('last_iter')
|
|
132
|
+
|
|
133
|
+
return obj_first_iter <= first_iter and obj_last_iter >= last_iter
|
|
134
|
+
|
|
135
|
+
def check_data_iter_range_equal(self, h5object, first_iter=None, last_iter=None):
|
|
136
|
+
'''Check that the given HDF5 object contains per-iteration data for exactly the specified iterations (as denoted by the
|
|
137
|
+
object's ``first_iter`` and ``last_iter`` attributes'''
|
|
138
|
+
|
|
139
|
+
first_iter = first_iter or self.first_iter
|
|
140
|
+
last_iter = last_iter or self.last_iter
|
|
141
|
+
|
|
142
|
+
obj_first_iter = h5object.attrs.get('first_iter')
|
|
143
|
+
obj_last_iter = h5object.attrs.get('last_iter')
|
|
144
|
+
|
|
145
|
+
return obj_first_iter == first_iter and obj_last_iter == last_iter
|
|
146
|
+
|
|
147
|
+
def check_data_iter_step_conformant(self, h5object, iter_step=None):
|
|
148
|
+
'''Check that the given HDF5 object contains per-iteration data at an iteration stride suitable for extracting data
|
|
149
|
+
with the given stride. (In other words, is the given ``iter_step`` a multiple of the stride with
|
|
150
|
+
which data was recorded.)'''
|
|
151
|
+
|
|
152
|
+
iter_step = iter_step or self.iter_step
|
|
153
|
+
obj_iter_step = h5object.attrs.get('iter_step')
|
|
154
|
+
return obj_iter_step % iter_step == 0
|
|
155
|
+
|
|
156
|
+
def check_data_iter_step_equal(self, h5object, iter_step=None):
|
|
157
|
+
'''Check that the given HDF5 object contains per-iteration data at an iteration stride the same as
|
|
158
|
+
that specified.'''
|
|
159
|
+
iter_step = iter_step or self.iter_step
|
|
160
|
+
obj_iter_step = h5object.attrs.get('iter_step')
|
|
161
|
+
return obj_iter_step == iter_step
|
|
162
|
+
|
|
163
|
+
def slice_per_iter_data(self, dataset, first_iter=None, last_iter=None, iter_step=None, axis=0):
|
|
164
|
+
'''Return the subset of the given dataset corresponding to the given iteration range and stride. Unless
|
|
165
|
+
otherwise specified, the first dimension of the dataset is the one sliced.'''
|
|
166
|
+
|
|
167
|
+
first_iter = first_iter or self.first_iter
|
|
168
|
+
last_iter = last_iter or self.last_iter
|
|
169
|
+
iter_step = iter_step or self.iter_step
|
|
170
|
+
|
|
171
|
+
ds_first_iter = dataset.attrs['first_iter']
|
|
172
|
+
ds_last_iter = dataset.attrs['last_iter']
|
|
173
|
+
ds_iter_step = dataset.attrs.get('iter_step', 1)
|
|
174
|
+
|
|
175
|
+
if first_iter < ds_first_iter or last_iter > ds_last_iter or ds_iter_step % iter_step > 0:
|
|
176
|
+
raise IndexError(
|
|
177
|
+
'Cannot slice requested iterations [{:d},{:d}] (stride={:d}) from dataset {!r} with range [{:d},{:d}] (stride={:d}).'.format(
|
|
178
|
+
first_iter, last_iter, iter_step, dataset, ds_first_iter, ds_last_iter, ds_iter_step
|
|
179
|
+
)
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
dimslices = []
|
|
183
|
+
for idim in range(len(dataset.shape)):
|
|
184
|
+
if idim == axis:
|
|
185
|
+
dimslices.append(slice(first_iter - ds_first_iter, last_iter - ds_first_iter + iter_step, iter_step))
|
|
186
|
+
else:
|
|
187
|
+
dimslices.append(slice(None, None, None))
|
|
188
|
+
|
|
189
|
+
dimslices = tuple(dimslices)
|
|
190
|
+
log.debug('slicing {!r} with {!r}'.format(dataset, dimslices))
|
|
191
|
+
data = dataset[dimslices]
|
|
192
|
+
log.debug('resulting data is of shape {!r}'.format(data.shape))
|
|
193
|
+
return data
|
|
194
|
+
|
|
195
|
+
def iter_range(self, first_iter=None, last_iter=None, iter_step=None):
|
|
196
|
+
first_iter = first_iter or self.first_iter
|
|
197
|
+
last_iter = last_iter or self.last_iter
|
|
198
|
+
iter_step = iter_step or self.iter_step
|
|
199
|
+
|
|
200
|
+
return np.arange(first_iter, last_iter + 1, iter_step)
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
import logging
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
import westpa
|
|
8
|
+
from westpa.oldtools.aframe import AnalysisMixin
|
|
9
|
+
|
|
10
|
+
log = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class KineticsAnalysisMixin(AnalysisMixin):
|
|
14
|
+
def __init__(self):
|
|
15
|
+
super().__init__()
|
|
16
|
+
|
|
17
|
+
self.dt = None
|
|
18
|
+
self.analysis_initial_bins = None
|
|
19
|
+
self.analysis_final_bins = None
|
|
20
|
+
|
|
21
|
+
def add_args(self, parser, upcall=True):
|
|
22
|
+
if upcall:
|
|
23
|
+
try:
|
|
24
|
+
upfunc = super().add_args
|
|
25
|
+
except AttributeError:
|
|
26
|
+
pass
|
|
27
|
+
else:
|
|
28
|
+
upfunc(parser)
|
|
29
|
+
|
|
30
|
+
group = parser.add_argument_group('kinetics analysis options')
|
|
31
|
+
group.add_argument(
|
|
32
|
+
'--dt', dest='dt', type=float, default=1.0, help='Assume input data has a time spacing of DT (default: %(default)s).'
|
|
33
|
+
)
|
|
34
|
+
group.add_argument(
|
|
35
|
+
'--initial-bins',
|
|
36
|
+
dest='ibins_string',
|
|
37
|
+
metavar='ILIST',
|
|
38
|
+
help='''Only calculate statistics for transitions starting in bin ILIST. This may be specified as a
|
|
39
|
+
comma-separated list of integers or ranges, as in "0,2-4,5,9"''',
|
|
40
|
+
)
|
|
41
|
+
group.add_argument(
|
|
42
|
+
'--final-bins',
|
|
43
|
+
dest='fbins_string',
|
|
44
|
+
metavar='FLIST',
|
|
45
|
+
help='''Only calculate statistics for transitions ending in bin FLIST. This may be specified as a
|
|
46
|
+
comma-separated list of integers or ranges, as in "0,2-4,5,9"''',
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def process_args(self, args, upcall=True):
|
|
50
|
+
self.dt = args.dt
|
|
51
|
+
westpa.rc.pstatus('Assuming input data timestep of {:g}'.format(self.dt))
|
|
52
|
+
|
|
53
|
+
if args.ibins_string:
|
|
54
|
+
self.analysis_initial_bins = self.parse_bin_range(args.ibins_string)
|
|
55
|
+
westpa.rc.pstatus(
|
|
56
|
+
'Will calculate kinetics data from transitions beginning in the following bins: {!s}'.format(
|
|
57
|
+
sorted(self.analysis_initial_bins)
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
else:
|
|
61
|
+
westpa.rc.pstatus('Will calculate kinetics data from transitions beginning in any bin.')
|
|
62
|
+
|
|
63
|
+
if args.fbins_string:
|
|
64
|
+
self.analysis_final_bins = self.parse_bin_range(args.fbins_string)
|
|
65
|
+
westpa.rc.pstatus(
|
|
66
|
+
'Will calculate kinetics data from transitions ending in the following bins: {!s}'.format(
|
|
67
|
+
sorted(self.analysis_final_bins)
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
else:
|
|
71
|
+
westpa.rc.pstatus('Will calculate kinetics data from transitions ending in any bin.')
|
|
72
|
+
|
|
73
|
+
if upcall:
|
|
74
|
+
try:
|
|
75
|
+
upfunc = super().process_args
|
|
76
|
+
except AttributeError:
|
|
77
|
+
pass
|
|
78
|
+
else:
|
|
79
|
+
upfunc(args)
|
|
80
|
+
|
|
81
|
+
def parse_bin_range(self, range_string):
|
|
82
|
+
try:
|
|
83
|
+
entries = set()
|
|
84
|
+
fields = re.split(r'\s*,\s*', range_string)
|
|
85
|
+
for field in fields:
|
|
86
|
+
if '-' in field:
|
|
87
|
+
lb, ub = list(map(int, re.split(r'\s*-\s*', field)))
|
|
88
|
+
entries.update(list(range(lb, ub + 1)))
|
|
89
|
+
else:
|
|
90
|
+
entries.add(int(field))
|
|
91
|
+
except (ValueError, TypeError):
|
|
92
|
+
raise ValueError('invalid bin range string {!r}'.format(range_string))
|
|
93
|
+
else:
|
|
94
|
+
return entries
|
|
95
|
+
|
|
96
|
+
def check_bin_selection(self, n_bins=None):
|
|
97
|
+
'''Check to see that the bin ranges selected by the user conform to the available bins (i.e.,
|
|
98
|
+
bin indices are within the permissible range). Also assigns the complete bin range if the
|
|
99
|
+
user has not explicitly limited the bins to be considered.'''
|
|
100
|
+
|
|
101
|
+
n_bins = n_bins or self.n_bins
|
|
102
|
+
|
|
103
|
+
if self.analysis_initial_bins:
|
|
104
|
+
if (np.array(list(self.analysis_initial_bins)) >= n_bins).any():
|
|
105
|
+
raise ValueError('One or more initial bin indices is out of range.')
|
|
106
|
+
else:
|
|
107
|
+
self.analysis_initial_bins = set(range(n_bins))
|
|
108
|
+
|
|
109
|
+
if self.analysis_final_bins:
|
|
110
|
+
if (np.array(list(self.analysis_final_bins)) >= n_bins).any():
|
|
111
|
+
raise ValueError('One or more final bin indices is out of range.')
|
|
112
|
+
else:
|
|
113
|
+
self.analysis_final_bins = set(range(n_bins))
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def selected_bin_pair_iter(self):
|
|
117
|
+
return (tuple(pair) for pair in itertools.product(self.analysis_initial_bins, self.analysis_final_bins))
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
'''
|
|
2
|
+
Tools for Monte Carlo bootstrap error analysis
|
|
3
|
+
'''
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import math
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
import westpa
|
|
11
|
+
from westpa.oldtools.aframe import AnalysisMixin
|
|
12
|
+
|
|
13
|
+
log = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class MCBSMixin(AnalysisMixin):
|
|
17
|
+
def __init__(self):
|
|
18
|
+
super().__init__()
|
|
19
|
+
self.mcbs_alpha = None
|
|
20
|
+
self.mcbs_nsets = None
|
|
21
|
+
self.mcbs_display_confidence = None
|
|
22
|
+
|
|
23
|
+
def add_args(self, parser, upcall=True):
|
|
24
|
+
if upcall:
|
|
25
|
+
try:
|
|
26
|
+
upfunc = super().add_args
|
|
27
|
+
except AttributeError:
|
|
28
|
+
pass
|
|
29
|
+
else:
|
|
30
|
+
upfunc(parser)
|
|
31
|
+
group = parser.add_argument_group('Monte Carlo bootstrap options')
|
|
32
|
+
group.add_argument(
|
|
33
|
+
'--confidence',
|
|
34
|
+
dest='mcbs_confidence',
|
|
35
|
+
type=float,
|
|
36
|
+
default=0.95,
|
|
37
|
+
metavar='P',
|
|
38
|
+
help='''Construct a confidence interval of width P (default: 0.95=95%%).''',
|
|
39
|
+
)
|
|
40
|
+
group.add_argument(
|
|
41
|
+
'--bssize',
|
|
42
|
+
dest='mcbs_nsets',
|
|
43
|
+
type=int,
|
|
44
|
+
metavar='NSETS',
|
|
45
|
+
help='''Use NSETS synthetic data sets to calculate confidence intervals (default:
|
|
46
|
+
calculated based on confidence level, but not less than 1000).''',
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def process_args(self, args, upcall=True):
|
|
50
|
+
self.mcbs_alpha = 1 - args.mcbs_confidence
|
|
51
|
+
self.mcbs_nsets = args.mcbs_size if args.mcbs_nsets else min(1000, calc_mcbs_nsets(self.mcbs_alpha))
|
|
52
|
+
self.mcbs_display_confidence = '{:.{cp}f}'.format(
|
|
53
|
+
100 * args.mcbs_confidence, cp=-int(math.floor(math.log10(self.mcbs_alpha))) - 2
|
|
54
|
+
)
|
|
55
|
+
westpa.rc.pstatus(
|
|
56
|
+
'Using bootstrap of {:d} sets to calculate {:s}% confidence interval (alpha={:g}).'.format(
|
|
57
|
+
self.mcbs_nsets, self.mcbs_display_confidence, self.mcbs_alpha
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
if upcall:
|
|
62
|
+
try:
|
|
63
|
+
upfunc = super().process_args
|
|
64
|
+
except AttributeError:
|
|
65
|
+
pass
|
|
66
|
+
else:
|
|
67
|
+
upfunc(args)
|
|
68
|
+
|
|
69
|
+
def calc_mcbs_nsets(self, alpha=None):
|
|
70
|
+
alpha = alpha or self.mcbs_alpha
|
|
71
|
+
return calc_mcbs_nsets(alpha)
|
|
72
|
+
|
|
73
|
+
def calc_ci_bound_indices(self, n_sets=None, alpha=None):
|
|
74
|
+
n_sets = n_sets or self.mcbs_nsets
|
|
75
|
+
alpha = alpha or self.mcbs_alpha
|
|
76
|
+
return calc_ci_bound_indices(n_sets, alpha)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
ciinfo_dtype = np.dtype([('expectation', np.float64), ('ci_lower', np.float64), ('ci_upper', np.float64)])
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def calc_mcbs_nsets(alpha):
|
|
83
|
+
'''Return a bootstrap data set size appropriate for the given confidence level.'''
|
|
84
|
+
return int(10 ** (math.ceil(-math.log10(alpha)) + 1))
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def calc_ci_bound_indices(n_sets, alpha):
|
|
88
|
+
return (int(math.floor(n_sets * alpha / 2)), int(math.ceil(n_sets * (1 - alpha / 2))))
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def bootstrap_ci_ll(estimator, data, alpha, n_sets, storage, sort, eargs=(), ekwargs={}, fhat=None):
|
|
92
|
+
'''Low-level routine for calculating bootstrap error estimates. Arguments and return values are as those for
|
|
93
|
+
``bootstrap_ci``, except that no argument is optional except additional arguments for the estimator (``eargs``, ``ekwargs``).
|
|
94
|
+
``data`` must be an array (or subclass), and an additional array ``storage`` must be provided, which
|
|
95
|
+
must be appropriately shaped and typed to hold ``n_sets`` results from ``estimator``. Further, if the
|
|
96
|
+
value ``fhat`` of the estimator must be pre-calculated to allocate ``storage``, then its value may be
|
|
97
|
+
passed; otherwise, ``estimator(data,*eargs,**kwargs)`` will be called to calculate it.'''
|
|
98
|
+
|
|
99
|
+
if fhat is None:
|
|
100
|
+
fhat = estimator(data, *eargs, **ekwargs)
|
|
101
|
+
dlen = len(data)
|
|
102
|
+
|
|
103
|
+
for iset in range(n_sets):
|
|
104
|
+
indices = np.random.randint(dlen, size=(dlen,))
|
|
105
|
+
storage[iset] = estimator(data[indices], *eargs, **ekwargs)
|
|
106
|
+
|
|
107
|
+
synth_sorted = sort(storage)
|
|
108
|
+
lbi = int(math.floor(n_sets * alpha / 2))
|
|
109
|
+
ubi = int(math.ceil(n_sets * (1 - alpha / 2)))
|
|
110
|
+
|
|
111
|
+
lb = synth_sorted[lbi]
|
|
112
|
+
ub = synth_sorted[ubi]
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
return (fhat, lb, ub, ub - lb, abs((ub - lb) / fhat) if fhat else 0, max(ub - fhat, fhat - lb))
|
|
116
|
+
finally:
|
|
117
|
+
del fhat, lb, ub, indices
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def bootstrap_ci(estimator, data, alpha, n_sets=None, sort=np.msort, eargs=(), ekwargs={}):
|
|
121
|
+
'''Perform a Monte Carlo bootstrap of a (1-alpha) confidence interval for the given ``estimator``.
|
|
122
|
+
Returns (fhat, ci_lower, ci_upper), where fhat is the result of ``estimator(data, *eargs, **ekwargs)``,
|
|
123
|
+
and ``ci_lower`` and ``ci_upper`` are the lower and upper bounds of the surrounding confidence
|
|
124
|
+
interval, calculated by calling ``estimator(syndata, *eargs, **ekwargs)`` on each synthetic data
|
|
125
|
+
set ``syndata``. If ``n_sets`` is provided, that is the number of synthetic data sets generated,
|
|
126
|
+
otherwise an appropriate size is selected automatically (see ``calc_mcbs_nsets()``).
|
|
127
|
+
|
|
128
|
+
``sort``, if given, is applied to sort the results of calling ``estimator`` on each
|
|
129
|
+
synthetic data set prior to obtaining the confidence interval. This function must sort
|
|
130
|
+
on the last index.
|
|
131
|
+
|
|
132
|
+
Individual entries in synthetic data sets are selected by the first index of ``data``, allowing this
|
|
133
|
+
function to be used on arrays of multidimensional data.
|
|
134
|
+
|
|
135
|
+
Returns (fhat, lb, ub, ub-lb, abs((ub-lb)/fhat), and max(ub-fhat,fhat-lb)) (that is, the estimated value, the
|
|
136
|
+
lower and upper bounds of the confidence interval, the width of the confidence interval, the relative
|
|
137
|
+
width of the confidence interval, and the symmetrized error bar of the confidence interval).'''
|
|
138
|
+
|
|
139
|
+
data = np.asanyarray(data)
|
|
140
|
+
fhat = np.squeeze(estimator(data, *eargs, **ekwargs))
|
|
141
|
+
n_sets = n_sets or calc_mcbs_nsets(alpha)
|
|
142
|
+
fsynth = np.empty((n_sets,), dtype=fhat.dtype)
|
|
143
|
+
try:
|
|
144
|
+
return bootstrap_ci_ll(estimator, data, alpha, n_sets or calc_mcbs_nsets(alpha), fsynth, sort, eargs, ekwargs, fhat)
|
|
145
|
+
finally:
|
|
146
|
+
del fsynth
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from westpa.oldtools.aframe import AnalysisMixin
|
|
4
|
+
|
|
5
|
+
log = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CommonOutputMixin(AnalysisMixin):
|
|
9
|
+
def __init__(self):
|
|
10
|
+
super().__init__()
|
|
11
|
+
|
|
12
|
+
include_args = self.include_args.setdefault('CommonOutputMixin', {})
|
|
13
|
+
include_args.setdefault('suppress_headers', True)
|
|
14
|
+
include_args.setdefault('print_bin_labels', True)
|
|
15
|
+
|
|
16
|
+
self.output_suppress_headers = False
|
|
17
|
+
self.output_print_bin_labels = False
|
|
18
|
+
|
|
19
|
+
def add_common_output_args(self, parser_or_group):
|
|
20
|
+
if self.include_args['CommonOutputMixin']['suppress_headers']:
|
|
21
|
+
parser_or_group.add_argument(
|
|
22
|
+
'--noheaders',
|
|
23
|
+
dest='suppress_headers',
|
|
24
|
+
action='store_true',
|
|
25
|
+
help='Do not include headers in text output files (default: include headers)',
|
|
26
|
+
)
|
|
27
|
+
if self.include_args['CommonOutputMixin']['print_bin_labels']:
|
|
28
|
+
parser_or_group.add_argument(
|
|
29
|
+
'--binlabels',
|
|
30
|
+
dest='print_bin_labels',
|
|
31
|
+
action='store_true',
|
|
32
|
+
help='Print bin labels in output files, if available (default: do not print bin labels)',
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def process_common_output_args(self, args):
|
|
36
|
+
if self.include_args['CommonOutputMixin']['suppress_headers']:
|
|
37
|
+
self.output_suppress_headers = bool(args.suppress_headers)
|
|
38
|
+
if self.include_args['CommonOutputMixin']['print_bin_labels']:
|
|
39
|
+
self.output_print_bin_labels = bool(args.print_bin_labels)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from westpa.oldtools.aframe import AnalysisMixin
|
|
6
|
+
|
|
7
|
+
log = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
import matplotlib
|
|
11
|
+
except ImportError:
|
|
12
|
+
matplotlib = None
|
|
13
|
+
pyplot = None
|
|
14
|
+
cm_hovmol = None
|
|
15
|
+
cm_hovmol_r = None
|
|
16
|
+
else:
|
|
17
|
+
try:
|
|
18
|
+
matplotlib.use('PDF')
|
|
19
|
+
from matplotlib import pyplot
|
|
20
|
+
except Exception as e:
|
|
21
|
+
log.info('could not select matplotlib PDF backend: {}'.format(e))
|
|
22
|
+
matplotlib = None
|
|
23
|
+
pyplot = None
|
|
24
|
+
|
|
25
|
+
cmap_data = np.array(
|
|
26
|
+
[
|
|
27
|
+
(124, 0, 24),
|
|
28
|
+
(211, 0, 32),
|
|
29
|
+
(244, 184, 0),
|
|
30
|
+
(245, 235, 0),
|
|
31
|
+
(129, 183, 2),
|
|
32
|
+
(32, 128, 38),
|
|
33
|
+
(21, 27, 87),
|
|
34
|
+
(36, 62, 137),
|
|
35
|
+
(178, 220, 245),
|
|
36
|
+
(255, 255, 255),
|
|
37
|
+
],
|
|
38
|
+
np.float32,
|
|
39
|
+
)
|
|
40
|
+
cmap_data /= 255.0
|
|
41
|
+
cm_hovmol = matplotlib.colors.LinearSegmentedColormap.from_list('hovmol', cmap_data)
|
|
42
|
+
cm_hovmol_r = matplotlib.colors.LinearSegmentedColormap.from_list('hovmol_r', np.flipud(cmap_data))
|
|
43
|
+
|
|
44
|
+
_pdr_data = {
|
|
45
|
+
'red': [
|
|
46
|
+
(0.0, 1.0, 1.0),
|
|
47
|
+
(0.25, 1.0, 1.0),
|
|
48
|
+
(0.50, 1.0, 1.0),
|
|
49
|
+
(0.75, 0.0, 0.0),
|
|
50
|
+
(0.90, 0.50, 0.50),
|
|
51
|
+
(0.95, 0.0, 0.0),
|
|
52
|
+
(1.0, 1.0, 1.0),
|
|
53
|
+
],
|
|
54
|
+
'green': [
|
|
55
|
+
(0.0, 1.0, 1.0),
|
|
56
|
+
(0.25, 0.0, 0.0),
|
|
57
|
+
(0.50, 1.0, 1.0),
|
|
58
|
+
(0.75, 1.0, 1.0),
|
|
59
|
+
(0.90, 0.86, 0.86),
|
|
60
|
+
(0.95, 0.0, 0.0),
|
|
61
|
+
(1.0, 1.0, 1.0),
|
|
62
|
+
],
|
|
63
|
+
'blue': [(0.0, 1.0, 1.0), (0.25, 0.0, 0.0), (0.75, 0.0, 0.0), (0.90, 1.0, 1.0), (0.95, 1.0, 1.0), (1.0, 1.0, 1.0)],
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
cm_pdr = matplotlib.colors.LinearSegmentedColormap('pdr', _pdr_data, 2048)
|
|
67
|
+
cm_pdr_r = cm_pdr.reversed()
|
|
68
|
+
|
|
69
|
+
matplotlib.cm.register_cmap('pdr', cm_pdr)
|
|
70
|
+
matplotlib.cm.register_cmap('pdr_r', cm_pdr_r)
|
|
71
|
+
matplotlib.cm.register_cmap('hovmol', cm_hovmol)
|
|
72
|
+
matplotlib.cm.register_cmap('hovmol_r', cm_hovmol_r)
|
|
73
|
+
|
|
74
|
+
del cmap_data
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class PlottingMixin(AnalysisMixin):
|
|
78
|
+
def __init__(self):
|
|
79
|
+
global matplotlib, pyplot
|
|
80
|
+
|
|
81
|
+
super().__init__()
|
|
82
|
+
|
|
83
|
+
self.matplotlib_avail = matplotlib is not None and pyplot is not None
|
|
84
|
+
|
|
85
|
+
def require_matplotlib(self):
|
|
86
|
+
global matplotlib
|
|
87
|
+
if not self.matplotlib_avail:
|
|
88
|
+
raise RuntimeError('matplotlib is not available')
|
|
89
|
+
else:
|
|
90
|
+
return matplotlib
|