westpa 2022.12__cp312-cp312-macosx_10_13_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.

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-312-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-312-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-312-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-312-darwin.so +0 -0
  75. westpa/mclib/__init__.py +271 -0
  76. westpa/mclib/__main__.py +28 -0
  77. westpa/mclib/_mclib.cpython-312-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-312-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,706 @@
1
+ import logging
2
+ import os
3
+ import re
4
+
5
+ import h5py
6
+ import numpy as np
7
+
8
+ import matplotlib
9
+ from matplotlib import pyplot
10
+ from matplotlib.image import NonUniformImage
11
+
12
+ from westpa.tools import WESTMasterCommand, WESTSubcommand
13
+ from westpa.core import h5io, textio
14
+ from westpa.fasthist import normhistnd
15
+ from westpa.core.extloader import get_object
16
+
17
+ log = logging.getLogger('plothist')
18
+
19
+ # Suppress divide-by-zero in log
20
+ np.seterr(divide='ignore', invalid='ignore')
21
+
22
+
23
+ def sum_except_along(array, axes):
24
+ '''Reduce the given array by addition over all axes except those listed in the scalar or
25
+ iterable ``axes``'''
26
+
27
+ try:
28
+ iter(axes)
29
+ except TypeError:
30
+ axes = [axes]
31
+
32
+ kept = set(axes)
33
+ summed = list(set(range(array.ndim)) - kept)
34
+
35
+ # Reorder axes so that the kept axes are first, and in the order they
36
+ # were given
37
+ array = np.transpose(array, list(axes) + summed).copy()
38
+
39
+ # Now, the last len(summed) axes are summed over
40
+ for _ in range(len(summed)):
41
+ array = np.add.reduce(array, axis=-1)
42
+
43
+ return array
44
+
45
+
46
+ class PlotHistBase(WESTSubcommand):
47
+ def __init__(self, parent):
48
+ super().__init__(parent)
49
+
50
+ self.input_arg_group = None
51
+ self.output_arg_group = None
52
+
53
+ self.input_h5 = None
54
+ self.opmode = None
55
+ self.plotscale = None
56
+ self.enerzero = None
57
+ self.plotrange = None
58
+ self.plottitle = None
59
+ self.postprocess_function = None
60
+ self.plot_contour = None
61
+
62
+ # Iteration range for average/evolution
63
+ self.avail_iter_start = None
64
+ self.avail_iter_stop = None
65
+ self.avail_iter_step = None
66
+ self.iter_start = None
67
+ self.iter_stop = None
68
+ self.iter_step = None
69
+
70
+ # Iteration for single point
71
+ self.n_iter = None
72
+
73
+ # An array of dicts describing what dimensions to work with and
74
+ # what their ranges should be for the plots.
75
+ self.dimensions = []
76
+
77
+ self.plot_output_filename = None
78
+ self.text_output_filename = None
79
+ self.hdf5_output_filename = None
80
+
81
+ def add_args(self, parser):
82
+ igroup = self.input_arg_group = parser.add_argument_group('input options')
83
+ igroup.add_argument('input', help='HDF5 file containing histogram data')
84
+ igroup.add_argument(
85
+ 'firstdim',
86
+ nargs='?',
87
+ metavar='DIMENSION',
88
+ help='''Plot for the given DIMENSION, specified as INT[:[LB,UB]:LABEL], where
89
+ INT is a zero-based integer identifying the dimension in the histogram,
90
+ LB and UB are lower and upper bounds for plotting, and LABEL is the label for
91
+ the plot axis. (Default: dimension 0, full range.)''',
92
+ )
93
+
94
+ ogroup = self.output_arg_group = parser.add_argument_group('output options')
95
+ ogroup.add_argument(
96
+ '-o',
97
+ '--output',
98
+ '--plot-output',
99
+ dest='plot_output',
100
+ default='hist.pdf',
101
+ metavar='PLOT_OUTPUT',
102
+ help='''Store plot as PLOT_OUTPUT. This may be set to an empty string
103
+ (e.g. --plot-output='') to suppress plotting entirely. The output
104
+ format is determined by filename extension (and thus defaults to PDF).
105
+ Default: "%(default)s".''',
106
+ )
107
+ ogroup.add_argument('--hdf5-output', help='''Store plot data in the HDF5 file HDF5_OUTPUT.''')
108
+ ogroup.add_argument(
109
+ '--plot-contour',
110
+ dest='plot_contour',
111
+ action='store_const',
112
+ const=True,
113
+ default=False,
114
+ help='''Determines whether or not to superimpose a contour plot over the heatmap for 2D objects.''',
115
+ )
116
+
117
+ pgroup = parser.add_argument_group('plot options')
118
+ pmgroup = pgroup.add_mutually_exclusive_group()
119
+ pgroup.add_argument('--title', dest='title', help='Include TITLE as the top-of-graph title')
120
+ pmgroup.add_argument(
121
+ '--linear', dest='plotscale', action='store_const', const='linear', help='Plot the histogram on a linear scale.'
122
+ )
123
+ pmgroup.add_argument(
124
+ '--energy',
125
+ dest='plotscale',
126
+ action='store_const',
127
+ const='energy',
128
+ help='Plot the histogram on an inverted natural log scale, corresponding to (free) energy (default).',
129
+ )
130
+ pmgroup.add_argument(
131
+ '--zero-energy',
132
+ dest='enerzero',
133
+ metavar='E',
134
+ default='min',
135
+ help='Set the zero of energy to E, which may be a scalar, "min" or "max"',
136
+ )
137
+ pmgroup.add_argument(
138
+ '--log10', dest='plotscale', action='store_const', const='log10', help='Plot the histogram on a base-10 log scale.'
139
+ )
140
+ pgroup.add_argument(
141
+ '--range',
142
+ help='''Plot histogram ordinates over the given RANGE, specified as "LB,UB",
143
+ where LB and UB are the lower and upper bounds, respectively. For 1-D plots,
144
+ this is the Y axis. For 2-D plots, this is the colorbar axis.
145
+ (Default: full range.)''',
146
+ )
147
+ pgroup.add_argument(
148
+ '--postprocess-function',
149
+ help='''Names a function (as in module.function) that will be called just prior
150
+ to saving the plot. The function will be called as ``postprocess(hist, midpoints, binbounds)``
151
+ where ``hist`` is the histogram that was plotted, ``midpoints`` is the bin midpoints for
152
+ each dimension, and ``binbounds`` is the bin boundaries for each dimension for 2-D plots,
153
+ or None otherwise. The plot must be modified in place using the pyplot stateful interface.''',
154
+ )
155
+
156
+ parser.set_defaults(plotscale='energy')
157
+
158
+ def process_args(self, args):
159
+ self.plotscale = args.plotscale
160
+ self.input_h5 = h5py.File(args.input, 'r')
161
+ self.plot_output_filename = args.plot_output
162
+ self.hdf5_output_filename = args.hdf5_output
163
+ self.plot_contour = args.plot_contour
164
+
165
+ if args.title:
166
+ self.plottitle = args.title
167
+
168
+ if args.range:
169
+ self.plotrange = self.parse_range(args.range)
170
+
171
+ if args.firstdim:
172
+ self.dimensions.append(self.parse_dimspec(args.firstdim))
173
+
174
+ if not args.firstdim:
175
+ self.dimensions.append({'idim': 0, 'label': 'dimension 0'})
176
+
177
+ if args.enerzero:
178
+ lenerzero = args.enerzero.lower()
179
+ if lenerzero not in ('min', 'max'):
180
+ try:
181
+ self.enerzero = float(args.enerzero)
182
+ except ValueError:
183
+ raise ValueError('invalid energy zero point {!r}'.format(args.enerzero))
184
+ else:
185
+ self.enerzero = lenerzero
186
+ else:
187
+ self.enerzero = 'min'
188
+
189
+ self.avail_iter_start, self.avail_iter_stop = h5io.get_iter_range(self.input_h5['histograms'])
190
+ try:
191
+ self.avail_iter_step = h5io.get_iter_step(self.input_h5['histograms'])
192
+ except KeyError:
193
+ self.avail_iter_step = 1
194
+ log.info(
195
+ 'HDF5 file {!r} contains data for iterations {} -- {} with a step of {}'.format(
196
+ args.input, self.avail_iter_start, self.avail_iter_stop, self.avail_iter_step
197
+ )
198
+ )
199
+ if args.postprocess_function:
200
+ self.postprocess_function = get_object(args.postprocess_function, path=['.'])
201
+
202
+ def parse_dimspec(self, dimspec):
203
+ dimdata = {}
204
+ match = re.match(r'([0-9]+)(?::(?:([^,]+),([^:,]+))?(?::(.*))?)?', dimspec)
205
+ if not match:
206
+ raise ValueError('invalid dimension specification {!r}'.format(dimspec))
207
+
208
+ (idim_txt, lb_txt, ub_txt, label) = match.groups()
209
+ try:
210
+ dimdata['idim'] = int(idim_txt)
211
+ if lb_txt:
212
+ dimdata['lb'] = float(lb_txt)
213
+ if ub_txt:
214
+ dimdata['ub'] = float(ub_txt)
215
+ if label:
216
+ dimdata['label'] = label
217
+ else:
218
+ dimdata['label'] = 'dimension {}'.format(dimdata['idim'])
219
+ except ValueError as e:
220
+ raise ValueError('invalid dimension specification {!r}: {!r}'.format(dimspec, e))
221
+ return dimdata
222
+
223
+ def parse_range(self, rangespec):
224
+ try:
225
+ (lbt, ubt) = rangespec.split(',')
226
+ return float(lbt), float(ubt)
227
+ except (ValueError, TypeError) as e:
228
+ raise ValueError('invalid range specification {!r}: {!r}'.format(rangespec, e))
229
+
230
+ def _ener_zero(self, hist):
231
+ hist = -np.log(hist)
232
+ if self.enerzero == 'min':
233
+ np.subtract(hist, hist.min(), out=hist, casting="unsafe")
234
+ elif self.enerzero == 'max':
235
+ np.subtract(hist, hist.max(), out=hist, casting="unsafe")
236
+ else:
237
+ np.subtract(hist, self.enerzero, out=hist, casting="unsafe")
238
+ return hist
239
+
240
+
241
+ class PlotSupports2D(PlotHistBase):
242
+ def __init__(self, parent):
243
+ super().__init__(parent)
244
+
245
+ def add_args(self, parser):
246
+ self.input_arg_group.add_argument(
247
+ 'seconddim',
248
+ nargs='?',
249
+ metavar='ADDTLDIM',
250
+ help='''For instantaneous/average plots, plot along the given additional
251
+ dimension, producing a color map.''',
252
+ )
253
+ self.output_arg_group.add_argument(
254
+ '--text-output',
255
+ help='''Store plot data in a text format at TEXT_OUTPUT. This option is
256
+ only valid for 1-D histograms. (Default: no text output.)''',
257
+ )
258
+
259
+ def process_args(self, args):
260
+ self.text_output_filename = args.text_output
261
+ if args.seconddim is not None:
262
+ self.dimensions.append(self.parse_dimspec(args.seconddim))
263
+
264
+ def _do_1d_output(self, hist, idim, midpoints):
265
+ enehist = self._ener_zero(hist)
266
+ log10hist = np.log10(hist)
267
+
268
+ if self.hdf5_output_filename:
269
+ with h5py.File(self.hdf5_output_filename, 'w') as output_h5:
270
+ h5io.stamp_creator_data(output_h5)
271
+ output_h5.attrs['source_data'] = os.path.abspath(self.input_h5.filename)
272
+ output_h5.attrs['source_dimension'] = idim
273
+ output_h5['midpoints'] = midpoints
274
+ output_h5['histogram'] = hist
275
+
276
+ if self.text_output_filename:
277
+ with textio.NumericTextOutputFormatter(self.text_output_filename) as output_file:
278
+ output_file.write_header('source data: {} dimension {}'.format(os.path.abspath(self.input_h5.filename), idim))
279
+ output_file.write_header('column 0: midpoint of bin')
280
+ output_file.write_header('column 1: probability in bin')
281
+ output_file.write_header('column 2: -ln P')
282
+ output_file.write_header('column 3: log10 P')
283
+ np.savetxt(output_file, np.column_stack([midpoints, hist, enehist, log10hist]))
284
+
285
+ if self.plot_output_filename:
286
+ if self.plotscale == 'energy':
287
+ plothist = enehist
288
+ label = r'$-\ln\,P(x)$'
289
+ elif self.plotscale == 'log10':
290
+ plothist = log10hist
291
+ label = r'$\log_{10}\ P(x)$'
292
+ else:
293
+ plothist = hist
294
+ label = r'$P(x)$'
295
+ pyplot.figure()
296
+ pyplot.plot(midpoints, plothist)
297
+ pyplot.xlim(self.dimensions[0].get('lb'), self.dimensions[0].get('ub'))
298
+ if self.plotrange:
299
+ pyplot.ylim(*self.plotrange)
300
+ pyplot.xlabel(self.dimensions[0]['label'])
301
+ pyplot.ylabel(label)
302
+ if self.plottitle:
303
+ pyplot.title(self.plottitle)
304
+ if self.postprocess_function:
305
+ self.postprocess_function(plothist, midpoints, None)
306
+ pyplot.savefig(self.plot_output_filename)
307
+
308
+ def _do_2d_output(self, hist, idims, midpoints, binbounds):
309
+ enehist = self._ener_zero(hist)
310
+ log10hist = np.log10(hist)
311
+
312
+ if self.hdf5_output_filename:
313
+ with h5py.File(self.hdf5_output_filename, 'w') as output_h5:
314
+ h5io.stamp_creator_data(output_h5)
315
+ output_h5.attrs['source_data'] = os.path.abspath(self.input_h5.filename)
316
+ output_h5.attrs['source_dimensions'] = np.array(idims, np.min_scalar_type(max(idims)))
317
+ output_h5.attrs['source_dimension_labels'] = np.array([dim['label'] for dim in self.dimensions])
318
+ for idim in idims:
319
+ output_h5['midpoints_{}'.format(idim)] = midpoints[idim]
320
+ output_h5['histogram'] = hist
321
+
322
+ if self.plot_output_filename:
323
+ if self.plotscale == 'energy':
324
+ plothist = enehist
325
+ label = r'$-\ln\,P(x)$'
326
+ elif self.plotscale == 'log10':
327
+ plothist = log10hist
328
+ label = r'$\log_{10}\ P(\vec{x})$'
329
+ else:
330
+ plothist = hist
331
+ plothist[~np.isfinite(plothist)] = np.nan
332
+ label = r'$P(\vec{x})$'
333
+
334
+ try:
335
+ vmin, vmax = self.plotrange
336
+ except TypeError:
337
+ vmin, vmax = None, None
338
+
339
+ pyplot.figure()
340
+ # Transpose input so that axis 0 is displayed as x and axis 1 is displayed as y
341
+ # pyplot.imshow(plothist.T, interpolation='nearest', aspect='auto',
342
+ # extent=(midpoints[0][0], midpoints[0][-1], midpoints[1][0], midpoints[1][-1]),
343
+ # origin='lower', vmin=vmin, vmax=vmax)
344
+
345
+ # The following reproduces the former calls to imshow and colorbar
346
+ norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax)
347
+ ax = pyplot.gca()
348
+ nui = NonUniformImage(
349
+ ax, extent=(midpoints[0][0], midpoints[0][-1], midpoints[1][0], midpoints[1][-1]), origin='lower', norm=norm
350
+ )
351
+ nui.set_data(midpoints[0], midpoints[1], plothist.T)
352
+ ax.add_image(nui)
353
+ ax.set_xlim(midpoints[0][0], midpoints[0][-1])
354
+ ax.set_ylim(midpoints[1][0], midpoints[1][-1])
355
+ cb = pyplot.colorbar(nui)
356
+ cb.set_label(label)
357
+
358
+ pyplot.xlabel(self.dimensions[0]['label'])
359
+ pyplot.xlim(self.dimensions[0].get('lb'), self.dimensions[0].get('ub'))
360
+ pyplot.ylabel(self.dimensions[1]['label'])
361
+ pyplot.ylim(self.dimensions[1].get('lb'), self.dimensions[1].get('ub'))
362
+ if self.plottitle:
363
+ pyplot.title(self.plottitle)
364
+ if self.postprocess_function:
365
+ self.postprocess_function(plothist, midpoints, binbounds)
366
+ if self.plot_contour:
367
+ pyplot.contour(midpoints[0], midpoints[1], plothist.T)
368
+ pyplot.savefig(self.plot_output_filename)
369
+
370
+
371
+ class InstantPlotHist(PlotSupports2D):
372
+ subcommand = 'instant'
373
+ help_text = 'plot probability distribution for a single WE iteration'
374
+ description = '''\
375
+ Plot a probability distribution for a single WE iteration. The probability
376
+ distribution must have been previously extracted with ``w_pdist`` (or, at
377
+ least, must be compatible with the output format of ``w_pdist``; see
378
+ ``w_pdist --help`` for more information).
379
+ '''
380
+
381
+ def add_args(self, parser):
382
+ self.input_arg_group.add_argument(
383
+ '--iter',
384
+ metavar='N_ITER',
385
+ dest='n_iter',
386
+ type=int,
387
+ help='''Plot distribution for iteration N_ITER
388
+ (default: last completed iteration).''',
389
+ )
390
+
391
+ def process_args(self, args):
392
+ if args.n_iter:
393
+ self.n_iter = min(args.n_iter, self.avail_iter_stop - 1)
394
+ else:
395
+ self.n_iter = self.avail_iter_stop - 1
396
+
397
+ def do_instant_plot_1d(self):
398
+ '''Plot the histogram for iteration self.n_iter'''
399
+
400
+ idim = self.dimensions[0]['idim']
401
+ n_iters = self.input_h5['n_iter'][...]
402
+ iiter = np.searchsorted(n_iters, self.n_iter)
403
+ binbounds = self.input_h5['binbounds_{}'.format(idim)][...]
404
+ midpoints = self.input_h5['midpoints_{}'.format(idim)][...]
405
+ hist = self.input_h5['histograms'][iiter]
406
+
407
+ # Average over other dimensions
408
+ hist = sum_except_along(hist, idim)
409
+ normhistnd(hist, [binbounds])
410
+ self._do_1d_output(hist, idim, midpoints)
411
+
412
+ def do_instant_plot_2d(self):
413
+ '''Plot the histogram for iteration self.n_iter'''
414
+
415
+ idim0 = self.dimensions[0]['idim']
416
+ idim1 = self.dimensions[1]['idim']
417
+
418
+ n_iters = self.input_h5['n_iter'][...]
419
+ iiter = np.searchsorted(n_iters, self.n_iter)
420
+ binbounds_0 = self.input_h5['binbounds_{}'.format(idim0)][...]
421
+ midpoints_0 = self.input_h5['midpoints_{}'.format(idim0)][...]
422
+ binbounds_1 = self.input_h5['binbounds_{}'.format(idim1)][...]
423
+ midpoints_1 = self.input_h5['midpoints_{}'.format(idim1)][...]
424
+
425
+ hist = self.input_h5['histograms'][iiter]
426
+
427
+ # Average over other dimensions
428
+ hist = sum_except_along(hist, [idim0, idim1])
429
+ normhistnd(hist, [binbounds_0, binbounds_1])
430
+ self._do_2d_output(hist, [idim0, idim1], [midpoints_0, midpoints_1], [binbounds_0, binbounds_1])
431
+
432
+ def go(self):
433
+ if len(self.dimensions) == 2:
434
+ self.do_instant_plot_2d()
435
+ else:
436
+ self.do_instant_plot_1d()
437
+
438
+
439
+ class AveragePlotHist(PlotSupports2D):
440
+ subcommand = 'average'
441
+ help_text = 'plot average of a probability distribution over a WE simulation'
442
+ description = '''\
443
+ Plot a probability distribution averaged over multiple iterations. The
444
+ probability distribution must have been previously extracted with ``w_pdist``
445
+ (or, at least, must be compatible with the output format of ``w_pdist``; see
446
+ ``w_pdist --help`` for more information).
447
+ '''
448
+
449
+ def add_args(self, parser):
450
+ igroup = self.input_arg_group
451
+ igroup.add_argument(
452
+ '--first-iter',
453
+ dest='first_iter',
454
+ type=int,
455
+ metavar='N_ITER',
456
+ default=1,
457
+ help='''Begin averaging at iteration N_ITER (default: %(default)d).''',
458
+ )
459
+ igroup.add_argument(
460
+ '--last-iter',
461
+ dest='last_iter',
462
+ type=int,
463
+ metavar='N_ITER',
464
+ help='''Conclude averaging with N_ITER, inclusive (default: last completed iteration).''',
465
+ )
466
+
467
+ def process_args(self, args):
468
+ if args.first_iter:
469
+ self.iter_start = max(args.first_iter, self.avail_iter_start)
470
+ else:
471
+ self.iter_start = self.avail_iter_start
472
+
473
+ if args.last_iter:
474
+ self.iter_stop = min(args.last_iter + 1, self.avail_iter_stop)
475
+ else:
476
+ self.iter_stop = self.avail_iter_stop
477
+
478
+ def do_average_plot_1d(self):
479
+ '''Plot the average histogram for iterations self.iter_start to self.iter_stop'''
480
+
481
+ idim = self.dimensions[0]['idim']
482
+ n_iters = self.input_h5['n_iter'][...]
483
+ iiter_start = np.searchsorted(n_iters, self.iter_start)
484
+ iiter_stop = np.searchsorted(n_iters, self.iter_stop)
485
+ binbounds = self.input_h5['binbounds_{}'.format(idim)][...]
486
+ midpoints = self.input_h5['midpoints_{}'.format(idim)][...]
487
+ # hist = self.input_h5['histograms'][iiter_start:iiter_stop]
488
+
489
+ for iiter in range(iiter_start, iiter_stop):
490
+ iter_hist = sum_except_along(self.input_h5['histograms'][iiter], idim)
491
+ if iiter == iiter_start:
492
+ hist = iter_hist
493
+ else:
494
+ hist += iter_hist
495
+ del iter_hist
496
+
497
+ normhistnd(hist, [binbounds])
498
+ self._do_1d_output(hist, idim, midpoints)
499
+
500
+ def do_average_plot_2d(self):
501
+ '''Plot the histogram for iteration self.n_iter'''
502
+
503
+ idim0 = self.dimensions[0]['idim']
504
+ idim1 = self.dimensions[1]['idim']
505
+
506
+ n_iters = self.input_h5['n_iter'][...]
507
+ iiter_start = np.searchsorted(n_iters, self.iter_start)
508
+ iiter_stop = np.searchsorted(n_iters, self.iter_stop)
509
+
510
+ binbounds_0 = self.input_h5['binbounds_{}'.format(idim0)][...]
511
+ midpoints_0 = self.input_h5['midpoints_{}'.format(idim0)][...]
512
+ binbounds_1 = self.input_h5['binbounds_{}'.format(idim1)][...]
513
+ midpoints_1 = self.input_h5['midpoints_{}'.format(idim1)][...]
514
+
515
+ for iiter in range(iiter_start, iiter_stop):
516
+ iter_hist = sum_except_along(self.input_h5['histograms'][iiter], [idim0, idim1])
517
+ if iiter == iiter_start:
518
+ hist = iter_hist
519
+ else:
520
+ hist += iter_hist
521
+
522
+ normhistnd(hist, [binbounds_0, binbounds_1])
523
+ self._do_2d_output(hist, [idim0, idim1], [midpoints_0, midpoints_1], [binbounds_0, binbounds_1])
524
+
525
+ def go(self):
526
+ if len(self.dimensions) == 2:
527
+ self.do_average_plot_2d()
528
+ else:
529
+ self.do_average_plot_1d()
530
+
531
+
532
+ class EvolutionPlotHist(PlotHistBase):
533
+ subcommand = 'evolution'
534
+ help_text = 'plot evolution of a probability distribution over the course of a WE simulation'
535
+ description = '''\
536
+ Plot a probability distribution as it evolves over iterations. The
537
+ probability distribution must have been previously extracted with ``w_pdist``
538
+ (or, at least, must be compatible with the output format of ``w_pdist``; see
539
+ ``w_pdist --help`` for more information).
540
+ '''
541
+
542
+ def add_args(self, parser):
543
+ igroup = self.input_arg_group
544
+ igroup.add_argument(
545
+ '--first-iter',
546
+ dest='first_iter',
547
+ type=int,
548
+ metavar='N_ITER',
549
+ default=1,
550
+ help='''Begin analysis at iteration N_ITER (default: %(default)d).''',
551
+ )
552
+ igroup.add_argument(
553
+ '--last-iter',
554
+ dest='last_iter',
555
+ type=int,
556
+ metavar='N_ITER',
557
+ help='''Conclude analysis with N_ITER, inclusive (default: last completed iteration).''',
558
+ )
559
+ igroup.add_argument(
560
+ '--step-iter', dest='step_iter', type=int, metavar='STEP', help='''Average in blocks of STEP iterations.'''
561
+ )
562
+
563
+ def process_args(self, args):
564
+ if args.first_iter:
565
+ self.iter_start = max(args.first_iter, self.avail_iter_start)
566
+ else:
567
+ self.iter_start = self.avail_iter_start
568
+
569
+ if args.last_iter:
570
+ self.iter_stop = min(args.last_iter + 1, self.avail_iter_stop)
571
+ else:
572
+ self.iter_stop = self.avail_iter_stop
573
+
574
+ if args.step_iter:
575
+ self.iter_step = max(args.step_iter, self.avail_iter_step)
576
+ else:
577
+ self.iter_step = self.avail_iter_step
578
+ log.info('using data for iterations {} -- {} with a step of {}'.format(self.iter_start, self.iter_stop, self.iter_step))
579
+
580
+ def go(self):
581
+ '''Plot the evolution of the histogram for iterations self.iter_start to self.iter_stop'''
582
+
583
+ idim = self.dimensions[0]['idim']
584
+ n_iters = self.input_h5['n_iter'][...]
585
+ iiter_start = np.searchsorted(n_iters, self.iter_start)
586
+ iiter_stop = np.searchsorted(n_iters, self.iter_stop)
587
+ binbounds = self.input_h5['binbounds_{}'.format(idim)][...]
588
+ midpoints = self.input_h5['midpoints_{}'.format(idim)][...]
589
+ hists_ds = self.input_h5['histograms']
590
+
591
+ itercount = self.iter_stop - self.iter_start
592
+
593
+ # We always round down, so that we don't have a dangling partial block at the end
594
+ nblocks = itercount // self.iter_step
595
+
596
+ block_iters = np.empty((nblocks, 2), dtype=n_iters.dtype)
597
+ blocked_hists = np.zeros((nblocks, hists_ds.shape[1 + idim]), dtype=hists_ds.dtype)
598
+
599
+ for iblock, istart in enumerate(range(iiter_start, iiter_start + nblocks * self.iter_step, self.iter_step)):
600
+ istop = min(istart + self.iter_step, iiter_stop)
601
+ histslice = hists_ds[istart:istop]
602
+
603
+ # Sum over time
604
+ histslice = np.add.reduce(histslice, axis=0)
605
+
606
+ # Sum over other dimensions
607
+ blocked_hists[iblock] = sum_except_along(histslice, idim)
608
+
609
+ # Normalize
610
+ normhistnd(blocked_hists[iblock], [binbounds])
611
+
612
+ block_iters[iblock, 0] = n_iters[istart]
613
+ block_iters[iblock, 1] = n_iters[istop - 1] + 1
614
+
615
+ # enehists = -np.log(blocked_hists)
616
+ enehists = self._ener_zero(blocked_hists)
617
+ log10hists = np.log10(blocked_hists)
618
+
619
+ if self.hdf5_output_filename:
620
+ with h5py.File(self.hdf5_output_filename, 'w') as output_h5:
621
+ h5io.stamp_creator_data(output_h5)
622
+ output_h5.attrs['source_data'] = os.path.abspath(self.input_h5.filename)
623
+ output_h5.attrs['source_dimension'] = idim
624
+ output_h5['midpoints'] = midpoints
625
+ output_h5['histograms'] = blocked_hists
626
+ output_h5['n_iter'] = block_iters
627
+
628
+ if self.plot_output_filename:
629
+ if self.plotscale == 'energy':
630
+ plothist = enehists
631
+ label = r'$-\ln\,P(x)$'
632
+ elif self.plotscale == 'log10':
633
+ plothist = log10hists
634
+ label = r'$\log_{10}\ P(x)$'
635
+ else:
636
+ plothist = blocked_hists
637
+ label = r'$P(x)$'
638
+
639
+ try:
640
+ vmin, vmax = self.plotrange
641
+ except TypeError:
642
+ vmin, vmax = None, None
643
+
644
+ pyplot.figure()
645
+ norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax)
646
+ ax = pyplot.gca()
647
+ nui = NonUniformImage(
648
+ ax, extent=(midpoints[0], midpoints[-1], block_iters[0, -1], block_iters[-1, -1]), origin='lower', norm=norm
649
+ )
650
+
651
+ # not sure why plothist works but plothist.T doesn't, and the opposite is true
652
+ # for _do_2d_output
653
+ nui.set_data(midpoints, block_iters[:, -1], plothist)
654
+ ax.add_image(nui)
655
+ ax.set_xlim(midpoints[0], midpoints[-1])
656
+ ax.set_ylim(block_iters[0, -1], block_iters[-1, -1])
657
+ cb = pyplot.colorbar(nui)
658
+ cb.set_label(label)
659
+ pyplot.xlabel(self.dimensions[0]['label'])
660
+ pyplot.xlim(self.dimensions[0].get('lb'), self.dimensions[0].get('ub'))
661
+ pyplot.ylabel('WE Iteration')
662
+ if self.plottitle:
663
+ pyplot.title(self.plottitle)
664
+ if self.postprocess_function:
665
+ self.postprocess_function(plothist, midpoints, binbounds)
666
+ pyplot.savefig(self.plot_output_filename)
667
+
668
+
669
+ class PlotHistTool(WESTMasterCommand):
670
+ prog = 'plothist'
671
+ subparsers_title = 'plotting modes'
672
+ subcommands = [InstantPlotHist, AveragePlotHist, EvolutionPlotHist]
673
+ description = '''\
674
+ Plot probability density functions (histograms) generated by w_pdist or other
675
+ programs conforming to the same output format. This program operates in one of
676
+ three modes:
677
+
678
+ instant
679
+ Plot 1-D and 2-D histograms for an individual iteration. See
680
+ ``plothist instant --help`` for more information.
681
+
682
+ average
683
+ Plot 1-D and 2-D histograms, averaged over several iterations. See
684
+ ``plothist average --help`` for more information.
685
+
686
+ evolution
687
+ Plot the time evolution 1-D histograms as waterfall (heat map) plots.
688
+ See ``plothist evolution --help`` for more information.
689
+
690
+ This program takes the output of ``w_pdist`` as input (see ``w_pdist --help``
691
+ for more information), and can generate any kind of graphical output that
692
+ matplotlib supports.
693
+
694
+
695
+ ------------------------------------------------------------------------------
696
+ Command-line options
697
+ ------------------------------------------------------------------------------
698
+ '''
699
+
700
+
701
+ def entry_point():
702
+ PlotHistTool().main()
703
+
704
+
705
+ if __name__ == '__main__':
706
+ entry_point()