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
westpa/tools/__init__.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'''tools -- classes for implementing command-line tools for WESTPA'''
|
|
2
|
+
|
|
3
|
+
from .core import WESTTool, WESTParallelTool, WESTToolComponent, WESTSubcommand, WESTMasterCommand, WESTMultiTool
|
|
4
|
+
from .data_reader import WESTDataReader, WESTDSSynthesizer, WESTWDSSynthesizer
|
|
5
|
+
from .iter_range import IterRangeSelection
|
|
6
|
+
from .selected_segs import SegSelector
|
|
7
|
+
from .binning import BinMappingComponent, mapper_from_dict
|
|
8
|
+
from .progress import ProgressIndicatorComponent
|
|
9
|
+
from .plot import Plotter
|
|
10
|
+
from .wipi import WIPIDataset, KineticsIteration, __get_data_for_iteration__, WIPIScheme
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
'WESTTool',
|
|
15
|
+
'WESTParallelTool',
|
|
16
|
+
'WESTToolComponent',
|
|
17
|
+
'WESTSubcommand',
|
|
18
|
+
'WESTMasterCommand',
|
|
19
|
+
'WESTMultiTool',
|
|
20
|
+
'WESTDataReader',
|
|
21
|
+
'WESTDSSynthesizer',
|
|
22
|
+
'WESTWDSSynthesizer',
|
|
23
|
+
'IterRangeSelection',
|
|
24
|
+
'SegSelector',
|
|
25
|
+
'BinMappingComponent',
|
|
26
|
+
'mapper_from_dict',
|
|
27
|
+
'ProgressIndicatorComponent',
|
|
28
|
+
'Plotter',
|
|
29
|
+
'WIPIDataset',
|
|
30
|
+
'KineticsIteration',
|
|
31
|
+
'__get_data_for_iteration__',
|
|
32
|
+
'WIPIScheme',
|
|
33
|
+
]
|
westpa/tools/binning.py
ADDED
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
from itertools import count
|
|
2
|
+
import logging
|
|
3
|
+
import math
|
|
4
|
+
import pickle
|
|
5
|
+
from pickle import PickleError
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
import westpa
|
|
11
|
+
import westpa.core.binning
|
|
12
|
+
from westpa.core.binning import RectilinearBinMapper
|
|
13
|
+
from westpa.core.data_manager import weight_dtype
|
|
14
|
+
from westpa.core.extloader import get_object
|
|
15
|
+
|
|
16
|
+
from .core import WESTToolComponent
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
EPS = np.finfo(weight_dtype).eps
|
|
20
|
+
|
|
21
|
+
log = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def mapper_from_expr(expr):
|
|
25
|
+
namespace = {'numpy': np, 'np': np, 'inf': float('inf')}
|
|
26
|
+
try:
|
|
27
|
+
mapper = RectilinearBinMapper(eval(expr, namespace))
|
|
28
|
+
except TypeError as e:
|
|
29
|
+
if 'has no len' in str(e):
|
|
30
|
+
raise ValueError('invalid bin boundary specification (a list of lists is required)')
|
|
31
|
+
else:
|
|
32
|
+
raise
|
|
33
|
+
else:
|
|
34
|
+
log.debug('loaded {!r} from expression {!r}'.format(mapper, expr))
|
|
35
|
+
return mapper
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def mapper_from_system():
|
|
39
|
+
system = westpa.rc.get_system_driver()
|
|
40
|
+
log.debug('loaded {!r} from {!r}'.format(system.bin_mapper, system))
|
|
41
|
+
return system.bin_mapper
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def mapper_from_function(funcspec):
|
|
45
|
+
'''Return a mapper constructed by calling a function in a named module.
|
|
46
|
+
``funcspec`` should be formatted as ``[PATH]:MODULE.FUNC``. This function
|
|
47
|
+
loads MODULE, optionally adding PATH to the search path, then returns MODULE.FUNC()'''
|
|
48
|
+
if ':' in funcspec:
|
|
49
|
+
(pathpart, funcpart) = funcspec.rsplit(':')
|
|
50
|
+
pathinfo = ['.'] + pathpart.split(':')
|
|
51
|
+
else:
|
|
52
|
+
funcpart = funcspec
|
|
53
|
+
pathinfo = ['.']
|
|
54
|
+
|
|
55
|
+
fn = get_object(funcpart, ['.'] + pathinfo)
|
|
56
|
+
mapper = fn()
|
|
57
|
+
log.debug('loaded {!r} from {!r}'.format(mapper, fn))
|
|
58
|
+
return mapper
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def mapper_from_hdf5(topol_group, hashval):
|
|
62
|
+
'''Retrieve the mapper identified by ``hashval`` from the given bin topology group
|
|
63
|
+
``topol_group``. Returns ``(mapper, pickle, hashval)``'''
|
|
64
|
+
try:
|
|
65
|
+
index_ds = topol_group['index']
|
|
66
|
+
pickle_ds = topol_group['pickles']
|
|
67
|
+
except KeyError:
|
|
68
|
+
log.debug('binhash {} not found'.format(hashval), exc_info=True)
|
|
69
|
+
raise KeyError('binhash {} not found'.format(hashval))
|
|
70
|
+
|
|
71
|
+
n_entries = len(index_ds)
|
|
72
|
+
if n_entries == 0:
|
|
73
|
+
raise KeyError('hash {} not found'.format(hashval))
|
|
74
|
+
|
|
75
|
+
chunksize = 256
|
|
76
|
+
for istart in range(0, n_entries, chunksize):
|
|
77
|
+
chunk = index_ds[istart : min(istart + chunksize, n_entries)]
|
|
78
|
+
for i in range(len(chunk)):
|
|
79
|
+
if chunk[i]['hash'] == bytes(hashval, 'utf-8'):
|
|
80
|
+
pkldat = bytes(pickle_ds[istart + i, 0 : chunk[i]['pickle_len']].data)
|
|
81
|
+
# mapper = pickle.loads(pkldat, encoding='latin1')
|
|
82
|
+
mapper = pickle.loads(pkldat)
|
|
83
|
+
log.debug('loaded {!r} from {!r}'.format(mapper, topol_group))
|
|
84
|
+
log.debug('hash value {!r}'.format(hashval))
|
|
85
|
+
return mapper, pkldat, hashval
|
|
86
|
+
|
|
87
|
+
raise KeyError('hash {} not found'.format(hashval))
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def mapper_from_yaml(yamlfilename):
|
|
91
|
+
import yaml
|
|
92
|
+
|
|
93
|
+
ydict = yaml.load(open(yamlfilename, 'rt'), Loader=yaml.Loader)
|
|
94
|
+
ybins = ydict['bins']
|
|
95
|
+
from westpa.core._rc import bins_from_yaml_dict
|
|
96
|
+
|
|
97
|
+
# return mapper_from_dict(ybins)
|
|
98
|
+
return bins_from_yaml_dict(ybins)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# We want this function to live on...
|
|
102
|
+
def mapper_from_dict(ybins):
|
|
103
|
+
typename = ybins.pop('type')
|
|
104
|
+
kwargs = ybins
|
|
105
|
+
|
|
106
|
+
try:
|
|
107
|
+
mapper_type = getattr(sys.modules['westpa.core.binning'], typename)
|
|
108
|
+
except AttributeError:
|
|
109
|
+
raise KeyError('unknown bin mapper type {!r}'.format(typename))
|
|
110
|
+
|
|
111
|
+
if typename == 'RectilinearBinMapper':
|
|
112
|
+
boundary_lists = kwargs.pop('boundaries')
|
|
113
|
+
for ilist, boundaries in enumerate(boundary_lists):
|
|
114
|
+
boundary_lists[ilist] = list(
|
|
115
|
+
map((lambda x: float('inf') if (x if isinstance(x, str) else '').lower() == 'inf' else x), boundaries)
|
|
116
|
+
)
|
|
117
|
+
return mapper_type(boundary_lists)
|
|
118
|
+
else:
|
|
119
|
+
try:
|
|
120
|
+
return mapper_type(**kwargs)
|
|
121
|
+
except Exception:
|
|
122
|
+
log.exception('exception instantiating mapper')
|
|
123
|
+
raise
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def write_bin_info(mapper, assignments, weights, n_target_states, outfile=sys.stdout, detailed=False):
|
|
127
|
+
'''Write information about binning to ``outfile``, given a mapper (``mapper``) and the weights
|
|
128
|
+
(``weights``) and bin assignments (``assignments``) of a set of segments, along with a target state
|
|
129
|
+
count (``n_target_states``). If ``detailed`` is true, then per-bin information is written as well as
|
|
130
|
+
summary information about all bins.'''
|
|
131
|
+
|
|
132
|
+
norm = weights.sum()
|
|
133
|
+
enorm = norm - 1.0
|
|
134
|
+
enormeps = abs(enorm / EPS)
|
|
135
|
+
bincounts = np.bincount(assignments, minlength=len(assignments))
|
|
136
|
+
n_occupied = np.count_nonzero(bincounts)
|
|
137
|
+
binweights = np.bincount(assignments, weights, minlength=len(assignments))
|
|
138
|
+
nonzero_counts = bincounts > 0
|
|
139
|
+
n_active = mapper.nbins - n_target_states
|
|
140
|
+
weights_by_bin = [[] for _i in range(mapper.nbins)]
|
|
141
|
+
|
|
142
|
+
min_bin_weight = binweights[nonzero_counts].min()
|
|
143
|
+
max_bin_weight = binweights.max()
|
|
144
|
+
min_seg_weight = weights.min()
|
|
145
|
+
max_seg_weight = weights.max()
|
|
146
|
+
|
|
147
|
+
ndec = int(math.ceil(-math.log10(1 / n_active)))
|
|
148
|
+
|
|
149
|
+
outfile.write('{:d} segments\n'.format(len(weights)))
|
|
150
|
+
outfile.write(
|
|
151
|
+
'{:d} bins total, {:d} targets, {:d} ({:.{ndec}%}) occupied\n'.format(
|
|
152
|
+
mapper.nbins, n_target_states, n_occupied, n_occupied / n_active, ndec=ndec
|
|
153
|
+
)
|
|
154
|
+
)
|
|
155
|
+
outfile.write('Minimum probability by bin: {:23.17e}\n'.format(min_bin_weight))
|
|
156
|
+
outfile.write('Maximum probability by bin: {:23.17e}\n'.format(max_bin_weight))
|
|
157
|
+
outfile.write('Dynamic range (by bin): {:g} kT\n'.format(-math.log(min_bin_weight / max_bin_weight)))
|
|
158
|
+
outfile.write('Minimum probability by segment: {:23.17e}\n'.format(min_seg_weight))
|
|
159
|
+
outfile.write('Maximum probability by segment: {:23.17e}\n'.format(max_seg_weight))
|
|
160
|
+
outfile.write('Dynamic range (by segment): {:g} kT\n'.format(-math.log(min_seg_weight / max_seg_weight)))
|
|
161
|
+
outfile.write('Norm = {:g}, error in norm = {:g} ({:.0f} epsilon)\n'.format(norm, enorm, enormeps))
|
|
162
|
+
|
|
163
|
+
if not detailed:
|
|
164
|
+
return
|
|
165
|
+
|
|
166
|
+
outfile.write('\n')
|
|
167
|
+
for iseg, weight in enumerate(weights):
|
|
168
|
+
weights_by_bin[assignments[iseg]].append(weight)
|
|
169
|
+
|
|
170
|
+
mw = max(6, max(len(str(mapper.nbins - 1)), len(str(bincounts.max()))))
|
|
171
|
+
fmt = ' '.join(
|
|
172
|
+
[
|
|
173
|
+
'{ibin:{mw}d}',
|
|
174
|
+
'{nwalkers:{mw}d}',
|
|
175
|
+
'{weight:23.17e}',
|
|
176
|
+
'{min_weight:23.17e}',
|
|
177
|
+
'{max_weight:23.17e}',
|
|
178
|
+
'{weight_ratio:12.5f}',
|
|
179
|
+
'{label}\n',
|
|
180
|
+
]
|
|
181
|
+
)
|
|
182
|
+
outfile.write(
|
|
183
|
+
'{:>{mw}s} {:>{mw}s} {:23s} {:23s} {:23s} {:12s} {}\n'.format(
|
|
184
|
+
'Index', 'Count', 'Total weight', 'Min seg weight', 'Max seg weight', 'Weight ratio', 'Label', mw=mw
|
|
185
|
+
)
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
for ibin, label, nwalkers, total_weight, seg_weights in zip(count(), mapper.labels, bincounts, binweights, weights_by_bin):
|
|
189
|
+
if nwalkers > 0:
|
|
190
|
+
min_seg_weight = min(seg_weights)
|
|
191
|
+
max_seg_weight = max(seg_weights)
|
|
192
|
+
weight_ratio = max_seg_weight / min_seg_weight
|
|
193
|
+
else:
|
|
194
|
+
min_seg_weight = 0
|
|
195
|
+
max_seg_weight = 0
|
|
196
|
+
weight_ratio = 0
|
|
197
|
+
outfile.write(
|
|
198
|
+
fmt.format(
|
|
199
|
+
ibin=ibin,
|
|
200
|
+
label=label,
|
|
201
|
+
nwalkers=nwalkers,
|
|
202
|
+
weight=total_weight,
|
|
203
|
+
min_weight=min_seg_weight,
|
|
204
|
+
max_weight=max_seg_weight,
|
|
205
|
+
weight_ratio=weight_ratio,
|
|
206
|
+
mw=mw,
|
|
207
|
+
)
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def write_bin_labels(mapper, dest, header='# bin labels:\n', fmt='# bin {index:{max_iwidth}d} -- {label!s}\n'):
|
|
212
|
+
'''Print labels for all bins in ``mapper`` to the file-like object``dest``.
|
|
213
|
+
|
|
214
|
+
If provided, ``header`` is printed prior to any labels. A number of expansions
|
|
215
|
+
are available in ``header``:
|
|
216
|
+
* ``mapper`` -- the mapper itself (from which most of the following can be obtained)
|
|
217
|
+
* ``classname`` -- the class name of the mapper
|
|
218
|
+
* ``nbins`` -- number of bins in the mapper
|
|
219
|
+
|
|
220
|
+
The ``fmt`` string specifies how bin labels are to be printed. A number of
|
|
221
|
+
expansions are available in ``fmt``:
|
|
222
|
+
* ``index`` -- the zero-based index of the bin
|
|
223
|
+
* ``label`` -- the label of the bin
|
|
224
|
+
* ``max_iwidth`` -- the maximum width (in characters) of the bin index, for pretty alignment
|
|
225
|
+
'''
|
|
226
|
+
|
|
227
|
+
if header:
|
|
228
|
+
dest.write(header.format(mapper=mapper, classname=mapper.__class__.__name__, nbins=mapper.bins))
|
|
229
|
+
|
|
230
|
+
max_iwidth = len(str(mapper.nbins - 1))
|
|
231
|
+
for ibin, label in enumerate(mapper.labels):
|
|
232
|
+
dest.write(fmt.format(index=ibin, label=label, max_iwidth=max_iwidth))
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class BinMappingComponent(WESTToolComponent):
|
|
236
|
+
'''Component for obtaining a bin mapper from one of several places based on
|
|
237
|
+
command-line arguments. Such locations include an HDF5 file that contains
|
|
238
|
+
pickled mappers (including the primary WEST HDF5 file), the system object,
|
|
239
|
+
an external function, or (in the common case of rectilinear bins) a
|
|
240
|
+
list of lists of bin boundaries.
|
|
241
|
+
|
|
242
|
+
Some configuration is necessary prior to calling process_args() if loading a
|
|
243
|
+
mapper from HDF5. Specifically, either set_we_h5file_info() or
|
|
244
|
+
set_other_h5file_info() must be called to describe where to find the
|
|
245
|
+
appropriate mapper. In the case of set_we_h5file_info(), the mapper used for
|
|
246
|
+
WE at the end of a given iteration will be loaded. In the case of
|
|
247
|
+
set_other_h5file_info(), an arbitrary group and hash value are specified;
|
|
248
|
+
the mapper corresponding to that hash in the given group will be returned.
|
|
249
|
+
|
|
250
|
+
In the absence of arguments, the mapper contained in an existing HDF5 file
|
|
251
|
+
is preferred; if that is not available, the mapper from the system driver
|
|
252
|
+
is used.
|
|
253
|
+
|
|
254
|
+
This component adds the following arguments to argument parsers:
|
|
255
|
+
|
|
256
|
+
--bins-from-system
|
|
257
|
+
Obtain bins from the system driver
|
|
258
|
+
|
|
259
|
+
--bins-from-expr=EXPR
|
|
260
|
+
Construct rectilinear bins by parsing EXPR and calling
|
|
261
|
+
RectilinearBinMapper() with the result. EXPR must therefore be a list of
|
|
262
|
+
lists.
|
|
263
|
+
|
|
264
|
+
--bins-from-function=[PATH:]MODULE.FUNC
|
|
265
|
+
Call an external function FUNC in module MODULE (optionally adding PATH
|
|
266
|
+
to the search path when loading MODULE) which, when called, returns a
|
|
267
|
+
fully-constructed bin mapper.
|
|
268
|
+
|
|
269
|
+
--bins-from-file
|
|
270
|
+
Load bin definitions from a YAML configuration file.
|
|
271
|
+
|
|
272
|
+
--bins-from-h5file
|
|
273
|
+
Load bins from the file being considered; this is intended to mean the
|
|
274
|
+
master WEST HDF5 file or results of other binning calculations, as
|
|
275
|
+
appropriate.
|
|
276
|
+
'''
|
|
277
|
+
|
|
278
|
+
def __init__(self):
|
|
279
|
+
# The final mapper
|
|
280
|
+
self.mapper = None
|
|
281
|
+
self.mapper_hash = None
|
|
282
|
+
self.mapper_pickle = None
|
|
283
|
+
self.mapper_source = None
|
|
284
|
+
self.mapper_source_desc = None
|
|
285
|
+
self.bin_target_counts = None
|
|
286
|
+
self.target_counts_required = False
|
|
287
|
+
|
|
288
|
+
# Cues for where to load a mapper from, for the external file case
|
|
289
|
+
self.mapper_source_group = None
|
|
290
|
+
self.mapper_source_n_iter = None
|
|
291
|
+
self.mapper_source_hash = None
|
|
292
|
+
|
|
293
|
+
self._parse_target_count_args = False
|
|
294
|
+
|
|
295
|
+
def add_args(self, parser, description='binning options', suppress=[]):
|
|
296
|
+
suppressed_options = set(suppress)
|
|
297
|
+
|
|
298
|
+
group = parser.add_argument_group(description)
|
|
299
|
+
egroup = group.add_mutually_exclusive_group()
|
|
300
|
+
if '--bins-from-system' not in suppressed_options:
|
|
301
|
+
egroup.add_argument(
|
|
302
|
+
'--bins-from-system',
|
|
303
|
+
action='store_true',
|
|
304
|
+
help='''Bins are constructed by the system driver specified in the WEST configuration file
|
|
305
|
+
(default where stored bin definitions not available).''',
|
|
306
|
+
)
|
|
307
|
+
if '--bins-from-expr' not in suppressed_options:
|
|
308
|
+
egroup.add_argument(
|
|
309
|
+
'--bins-from-expr',
|
|
310
|
+
'--binbounds',
|
|
311
|
+
dest='bins_from_expr',
|
|
312
|
+
help='''Construct bins on a rectilinear grid according to the given BINEXPR. This must
|
|
313
|
+
be a list of lists of bin boundaries (one list of bin boundaries for each dimension
|
|
314
|
+
of the progress coordinate), formatted as a Python expression. E.g. "[[0,1,2,4,inf],[-inf,0,inf]]".
|
|
315
|
+
The numpy module and the special symbol "inf" (for floating-point infinity) are available
|
|
316
|
+
for use within BINEXPR.''',
|
|
317
|
+
)
|
|
318
|
+
if '--bins-from-function' not in suppressed_options:
|
|
319
|
+
egroup.add_argument(
|
|
320
|
+
'--bins-from-function',
|
|
321
|
+
'--binfunc',
|
|
322
|
+
dest='bins_from_function',
|
|
323
|
+
help='''Supply an external function which, when called, returns a properly constructed
|
|
324
|
+
bin mapper which will then be used for bin assignments. This should be formatted as
|
|
325
|
+
"[PATH:]MODULE.FUNC", where the function FUNC in module MODULE will be used; the optional
|
|
326
|
+
PATH will be prepended to the module search path when loading MODULE.''',
|
|
327
|
+
)
|
|
328
|
+
if '--bins-from-file' not in suppressed_options:
|
|
329
|
+
egroup.add_argument(
|
|
330
|
+
'--bins-from-file',
|
|
331
|
+
'--binfile',
|
|
332
|
+
dest='bins_from_file',
|
|
333
|
+
metavar='BINFILE',
|
|
334
|
+
help='''Load bin specification from the YAML file BINFILE. This currently
|
|
335
|
+
takes the form {'bins': {'type': 'RectilinearBinMapper', 'boundaries':
|
|
336
|
+
[[boundset1], [boundset2], ... ]}}; only rectilinear bin bounds are supported.''',
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
if '--bins-from-h5file' not in suppressed_options:
|
|
340
|
+
egroup.add_argument(
|
|
341
|
+
'--bins-from-h5file',
|
|
342
|
+
action='store_true',
|
|
343
|
+
help='''Load bin specification from the data file being examined
|
|
344
|
+
(default where stored bin definitions available).''',
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
def add_target_count_args(self, parser, description='bin target count options'):
|
|
348
|
+
'''Add options to the given parser corresponding to target counts.'''
|
|
349
|
+
|
|
350
|
+
self._parse_target_count_args = True
|
|
351
|
+
group = parser.add_argument_group(description)
|
|
352
|
+
egroup = group.add_mutually_exclusive_group()
|
|
353
|
+
|
|
354
|
+
egroup.add_argument(
|
|
355
|
+
'--target-counts',
|
|
356
|
+
help='''Use TARGET_COUNTS instead of stored or system driver target counts.
|
|
357
|
+
TARGET_COUNTS is a comma-separated list of integers. As a special case, a single
|
|
358
|
+
integer is acceptable, in which case the same target count is used for all bins.''',
|
|
359
|
+
)
|
|
360
|
+
egroup.add_argument(
|
|
361
|
+
'--target-counts-from',
|
|
362
|
+
metavar='FILENAME',
|
|
363
|
+
help='''Read target counts from the text file FILENAME instead of using stored or system
|
|
364
|
+
driver target counts. FILENAME must contain a list of integers, separated by arbitrary
|
|
365
|
+
whitespace (including newlines).''',
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
def process_args(self, args):
|
|
369
|
+
# User may have suppressed any of these arguments
|
|
370
|
+
bins_from_system = getattr(args, 'bins_from_system', None)
|
|
371
|
+
bins_from_expr = getattr(args, 'bins_from_expr', None)
|
|
372
|
+
bins_from_function = getattr(args, 'bins_from_function', None)
|
|
373
|
+
bins_from_file = getattr(args, 'bins_from_file', None)
|
|
374
|
+
bins_from_h5file = getattr(args, 'bins_from_h5file', None)
|
|
375
|
+
|
|
376
|
+
if not any([bins_from_system, bins_from_expr, bins_from_function, bins_from_h5file, bins_from_file]):
|
|
377
|
+
log.debug('no argument provided')
|
|
378
|
+
if self.mapper_source_group is None:
|
|
379
|
+
log.info('using bins from system file')
|
|
380
|
+
bins_from_system = True
|
|
381
|
+
else:
|
|
382
|
+
log.info('using bins from HDF5 file')
|
|
383
|
+
bins_from_h5file = True
|
|
384
|
+
|
|
385
|
+
if bins_from_h5file:
|
|
386
|
+
# it is an error to call process_args() prior to setting source group and hash,
|
|
387
|
+
# preferably using the set_*_h5file_info() functions.
|
|
388
|
+
assert self.mapper_source_group is not None
|
|
389
|
+
assert self.mapper_source_hash is not None
|
|
390
|
+
self.mapper, self.mapper_pickle, self.mapper_hash = mapper_from_hdf5(self.mapper_source_group, self.mapper_source_hash)
|
|
391
|
+
self.mapper_source = 'file'
|
|
392
|
+
self.mapper_source_desc = 'HDF5 file {} (group "{}")'.format(
|
|
393
|
+
self.mapper_source_group.file.filename, self.mapper_source_group.name
|
|
394
|
+
)
|
|
395
|
+
elif bins_from_file:
|
|
396
|
+
self.mapper = mapper_from_yaml(args.bins_from_file)
|
|
397
|
+
self.mapper_source = args.bins_from_file
|
|
398
|
+
self.mapper_source_desc = 'YAML file {!r}'.format(args.bins_from_file)
|
|
399
|
+
elif bins_from_system:
|
|
400
|
+
self.mapper = mapper_from_system()
|
|
401
|
+
self.mapper_source = 'system'
|
|
402
|
+
self.mapper_source_desc = 'system driver'
|
|
403
|
+
elif bins_from_expr:
|
|
404
|
+
self.mapper = mapper_from_expr(args.bins_from_expr)
|
|
405
|
+
self.mapper_source = 'expr'
|
|
406
|
+
self.mapper_source_desc = 'boundary expression'
|
|
407
|
+
elif bins_from_function:
|
|
408
|
+
self.mapper = mapper_from_function(args.bins_from_function)
|
|
409
|
+
self.mapper_source = 'func'
|
|
410
|
+
self.mapper_source_desc = 'external function'
|
|
411
|
+
|
|
412
|
+
if self.mapper and not self.mapper_hash:
|
|
413
|
+
try:
|
|
414
|
+
self.mapper_pickle, self.mapper_hash = self.mapper.pickle_and_hash()
|
|
415
|
+
except PickleError as e:
|
|
416
|
+
log.debug('could not pickle bin mapper: {}'.format(e))
|
|
417
|
+
self.mapper_pickle = self.mapper_hash = None
|
|
418
|
+
|
|
419
|
+
log.info('loaded mapper {!r} from {}'.format(self.mapper, self.mapper_source_desc))
|
|
420
|
+
|
|
421
|
+
if self._parse_target_count_args and self.target_counts_required:
|
|
422
|
+
import re
|
|
423
|
+
|
|
424
|
+
if args.target_counts is not None:
|
|
425
|
+
self.bin_target_counts = np.array(list(map(int, re.split(r'\s*,\s*', args.target_counts))))
|
|
426
|
+
elif args.target_counts_from is not None:
|
|
427
|
+
self.bin_target_counts = np.array(list(map(int, re.split(r'\s*,\s*', open(args.target_counts_from, 'rt').read()))))
|
|
428
|
+
else:
|
|
429
|
+
# if target counts required, they will have already been loaded from a master
|
|
430
|
+
if self.bin_target_counts is None and self.target_counts_required:
|
|
431
|
+
raise EnvironmentError('target counts are required but none have been provided')
|
|
432
|
+
|
|
433
|
+
if len(self.bin_target_counts) == 1:
|
|
434
|
+
flat_target_count = self.bin_target_counts
|
|
435
|
+
self.bin_target_counts = np.empty((self.mapper.nbins,), int)
|
|
436
|
+
self.bin_target_counts[:] = flat_target_count
|
|
437
|
+
log.debug('bin target counts = {!r}'.format(self.bin_target_counts))
|
|
438
|
+
|
|
439
|
+
def set_we_h5file_info(self, n_iter=None, data_manager=None, required=False):
|
|
440
|
+
'''Set up to load a bin mapper from the master WEST HDF5 file. The mapper is actually loaded
|
|
441
|
+
from the file when self.load_bin_mapper() is called, if and only if command line arguments
|
|
442
|
+
direct this. If ``required`` is true, then a mapper must be available at iteration ``n_iter``,
|
|
443
|
+
or else an exception will be raised.'''
|
|
444
|
+
|
|
445
|
+
data_manager = data_manager or westpa.rc.get_data_manager()
|
|
446
|
+
n_iter = n_iter or data_manager.current_iteration
|
|
447
|
+
iter_group = data_manager.get_iter_group(n_iter)
|
|
448
|
+
|
|
449
|
+
try:
|
|
450
|
+
self.mapper_source_group = data_manager.we_h5file['/bin_topologies']
|
|
451
|
+
self.mapper_source_group['index'] # raises KeyError if missing
|
|
452
|
+
self.mapper_source_group['pickles'] # raises KeyError if missing
|
|
453
|
+
self.mapper_source_hash = iter_group.attrs['binhash']
|
|
454
|
+
except TypeError:
|
|
455
|
+
if required:
|
|
456
|
+
raise EnvironmentError('HDF5 file not open')
|
|
457
|
+
except KeyError:
|
|
458
|
+
if required:
|
|
459
|
+
raise EnvironmentError('bin topologies not available')
|
|
460
|
+
|
|
461
|
+
try:
|
|
462
|
+
self.bin_target_counts = iter_group['bin_target_counts'][...]
|
|
463
|
+
except KeyError:
|
|
464
|
+
pass
|
|
465
|
+
|
|
466
|
+
def set_other_h5file_info(self, topology_group, hashval):
|
|
467
|
+
'''Set up to load a bin mapper from (any) open HDF5 file, where bin topologies are
|
|
468
|
+
stored in ``topology_group`` (an h5py Group object) and the desired mapper has hash
|
|
469
|
+
value ``hashval``. The mapper itself is loaded when self.load_bin_mapper() is called.'''
|
|
470
|
+
|
|
471
|
+
self.mapper_source_group = topology_group
|
|
472
|
+
self.mapper_source_hash = hashval
|