westpa 2022.12__cp313-cp313-macosx_11_0_arm64.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.

Files changed (149) hide show
  1. westpa/__init__.py +14 -0
  2. westpa/_version.py +21 -0
  3. westpa/analysis/__init__.py +5 -0
  4. westpa/analysis/core.py +746 -0
  5. westpa/analysis/statistics.py +27 -0
  6. westpa/analysis/trajectories.py +360 -0
  7. westpa/cli/__init__.py +0 -0
  8. westpa/cli/core/__init__.py +0 -0
  9. westpa/cli/core/w_fork.py +152 -0
  10. westpa/cli/core/w_init.py +230 -0
  11. westpa/cli/core/w_run.py +77 -0
  12. westpa/cli/core/w_states.py +212 -0
  13. westpa/cli/core/w_succ.py +99 -0
  14. westpa/cli/core/w_truncate.py +68 -0
  15. westpa/cli/tools/__init__.py +0 -0
  16. westpa/cli/tools/ploterr.py +506 -0
  17. westpa/cli/tools/plothist.py +706 -0
  18. westpa/cli/tools/w_assign.py +596 -0
  19. westpa/cli/tools/w_bins.py +166 -0
  20. westpa/cli/tools/w_crawl.py +119 -0
  21. westpa/cli/tools/w_direct.py +547 -0
  22. westpa/cli/tools/w_dumpsegs.py +94 -0
  23. westpa/cli/tools/w_eddist.py +506 -0
  24. westpa/cli/tools/w_fluxanl.py +376 -0
  25. westpa/cli/tools/w_ipa.py +833 -0
  26. westpa/cli/tools/w_kinavg.py +127 -0
  27. westpa/cli/tools/w_kinetics.py +96 -0
  28. westpa/cli/tools/w_multi_west.py +414 -0
  29. westpa/cli/tools/w_ntop.py +213 -0
  30. westpa/cli/tools/w_pdist.py +515 -0
  31. westpa/cli/tools/w_postanalysis_matrix.py +82 -0
  32. westpa/cli/tools/w_postanalysis_reweight.py +53 -0
  33. westpa/cli/tools/w_red.py +491 -0
  34. westpa/cli/tools/w_reweight.py +780 -0
  35. westpa/cli/tools/w_select.py +226 -0
  36. westpa/cli/tools/w_stateprobs.py +111 -0
  37. westpa/cli/tools/w_trace.py +599 -0
  38. westpa/core/__init__.py +0 -0
  39. westpa/core/_rc.py +673 -0
  40. westpa/core/binning/__init__.py +55 -0
  41. westpa/core/binning/_assign.cpython-313-darwin.so +0 -0
  42. westpa/core/binning/assign.py +455 -0
  43. westpa/core/binning/binless.py +96 -0
  44. westpa/core/binning/binless_driver.py +54 -0
  45. westpa/core/binning/binless_manager.py +190 -0
  46. westpa/core/binning/bins.py +47 -0
  47. westpa/core/binning/mab.py +506 -0
  48. westpa/core/binning/mab_driver.py +54 -0
  49. westpa/core/binning/mab_manager.py +198 -0
  50. westpa/core/data_manager.py +1694 -0
  51. westpa/core/extloader.py +74 -0
  52. westpa/core/h5io.py +995 -0
  53. westpa/core/kinetics/__init__.py +24 -0
  54. westpa/core/kinetics/_kinetics.cpython-313-darwin.so +0 -0
  55. westpa/core/kinetics/events.py +147 -0
  56. westpa/core/kinetics/matrates.py +156 -0
  57. westpa/core/kinetics/rate_averaging.py +266 -0
  58. westpa/core/progress.py +218 -0
  59. westpa/core/propagators/__init__.py +54 -0
  60. westpa/core/propagators/executable.py +719 -0
  61. westpa/core/reweight/__init__.py +14 -0
  62. westpa/core/reweight/_reweight.cpython-313-darwin.so +0 -0
  63. westpa/core/reweight/matrix.py +126 -0
  64. westpa/core/segment.py +119 -0
  65. westpa/core/sim_manager.py +835 -0
  66. westpa/core/states.py +359 -0
  67. westpa/core/systems.py +93 -0
  68. westpa/core/textio.py +74 -0
  69. westpa/core/trajectory.py +330 -0
  70. westpa/core/we_driver.py +910 -0
  71. westpa/core/wm_ops.py +43 -0
  72. westpa/core/yamlcfg.py +391 -0
  73. westpa/fasthist/__init__.py +34 -0
  74. westpa/fasthist/_fasthist.cpython-313-darwin.so +0 -0
  75. westpa/mclib/__init__.py +271 -0
  76. westpa/mclib/__main__.py +28 -0
  77. westpa/mclib/_mclib.cpython-313-darwin.so +0 -0
  78. westpa/oldtools/__init__.py +4 -0
  79. westpa/oldtools/aframe/__init__.py +35 -0
  80. westpa/oldtools/aframe/atool.py +75 -0
  81. westpa/oldtools/aframe/base_mixin.py +26 -0
  82. westpa/oldtools/aframe/binning.py +178 -0
  83. westpa/oldtools/aframe/data_reader.py +560 -0
  84. westpa/oldtools/aframe/iter_range.py +200 -0
  85. westpa/oldtools/aframe/kinetics.py +117 -0
  86. westpa/oldtools/aframe/mcbs.py +153 -0
  87. westpa/oldtools/aframe/output.py +39 -0
  88. westpa/oldtools/aframe/plotting.py +90 -0
  89. westpa/oldtools/aframe/trajwalker.py +126 -0
  90. westpa/oldtools/aframe/transitions.py +469 -0
  91. westpa/oldtools/cmds/__init__.py +0 -0
  92. westpa/oldtools/cmds/w_ttimes.py +361 -0
  93. westpa/oldtools/files.py +34 -0
  94. westpa/oldtools/miscfn.py +23 -0
  95. westpa/oldtools/stats/__init__.py +4 -0
  96. westpa/oldtools/stats/accumulator.py +35 -0
  97. westpa/oldtools/stats/edfs.py +129 -0
  98. westpa/oldtools/stats/mcbs.py +96 -0
  99. westpa/tools/__init__.py +33 -0
  100. westpa/tools/binning.py +472 -0
  101. westpa/tools/core.py +340 -0
  102. westpa/tools/data_reader.py +159 -0
  103. westpa/tools/dtypes.py +31 -0
  104. westpa/tools/iter_range.py +198 -0
  105. westpa/tools/kinetics_tool.py +340 -0
  106. westpa/tools/plot.py +283 -0
  107. westpa/tools/progress.py +17 -0
  108. westpa/tools/selected_segs.py +154 -0
  109. westpa/tools/wipi.py +751 -0
  110. westpa/trajtree/__init__.py +4 -0
  111. westpa/trajtree/_trajtree.cpython-313-darwin.so +0 -0
  112. westpa/trajtree/trajtree.py +117 -0
  113. westpa/westext/__init__.py +0 -0
  114. westpa/westext/adaptvoronoi/__init__.py +3 -0
  115. westpa/westext/adaptvoronoi/adaptVor_driver.py +214 -0
  116. westpa/westext/hamsm_restarting/__init__.py +3 -0
  117. westpa/westext/hamsm_restarting/example_overrides.py +35 -0
  118. westpa/westext/hamsm_restarting/restart_driver.py +1165 -0
  119. westpa/westext/stringmethod/__init__.py +11 -0
  120. westpa/westext/stringmethod/fourier_fitting.py +69 -0
  121. westpa/westext/stringmethod/string_driver.py +253 -0
  122. westpa/westext/stringmethod/string_method.py +306 -0
  123. westpa/westext/weed/BinCluster.py +180 -0
  124. westpa/westext/weed/ProbAdjustEquil.py +100 -0
  125. westpa/westext/weed/UncertMath.py +247 -0
  126. westpa/westext/weed/__init__.py +10 -0
  127. westpa/westext/weed/weed_driver.py +192 -0
  128. westpa/westext/wess/ProbAdjust.py +101 -0
  129. westpa/westext/wess/__init__.py +6 -0
  130. westpa/westext/wess/wess_driver.py +217 -0
  131. westpa/work_managers/__init__.py +57 -0
  132. westpa/work_managers/core.py +396 -0
  133. westpa/work_managers/environment.py +134 -0
  134. westpa/work_managers/mpi.py +318 -0
  135. westpa/work_managers/processes.py +187 -0
  136. westpa/work_managers/serial.py +28 -0
  137. westpa/work_managers/threads.py +79 -0
  138. westpa/work_managers/zeromq/__init__.py +20 -0
  139. westpa/work_managers/zeromq/core.py +641 -0
  140. westpa/work_managers/zeromq/node.py +131 -0
  141. westpa/work_managers/zeromq/work_manager.py +526 -0
  142. westpa/work_managers/zeromq/worker.py +320 -0
  143. westpa-2022.12.dist-info/AUTHORS +22 -0
  144. westpa-2022.12.dist-info/LICENSE +21 -0
  145. westpa-2022.12.dist-info/METADATA +193 -0
  146. westpa-2022.12.dist-info/RECORD +149 -0
  147. westpa-2022.12.dist-info/WHEEL +6 -0
  148. westpa-2022.12.dist-info/entry_points.txt +29 -0
  149. westpa-2022.12.dist-info/top_level.txt +1 -0
@@ -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
+ ]
@@ -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