westpa 2022.12__cp313-cp313-manylinux_2_17_x86_64.manylinux2014_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 +68 -0
- westpa/cli/tools/__init__.py +0 -0
- westpa/cli/tools/ploterr.py +506 -0
- westpa/cli/tools/plothist.py +706 -0
- westpa/cli/tools/w_assign.py +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 +376 -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 +491 -0
- westpa/cli/tools/w_reweight.py +780 -0
- westpa/cli/tools/w_select.py +226 -0
- westpa/cli/tools/w_stateprobs.py +111 -0
- westpa/cli/tools/w_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-313-x86_64-linux-gnu.so +0 -0
- westpa/core/binning/assign.py +455 -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 +506 -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-313-x86_64-linux-gnu.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 +719 -0
- westpa/core/reweight/__init__.py +14 -0
- westpa/core/reweight/_reweight.cpython-313-x86_64-linux-gnu.so +0 -0
- westpa/core/reweight/matrix.py +126 -0
- westpa/core/segment.py +119 -0
- westpa/core/sim_manager.py +835 -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 +910 -0
- westpa/core/wm_ops.py +43 -0
- westpa/core/yamlcfg.py +391 -0
- westpa/fasthist/__init__.py +34 -0
- westpa/fasthist/_fasthist.cpython-313-x86_64-linux-gnu.so +0 -0
- westpa/mclib/__init__.py +271 -0
- westpa/mclib/__main__.py +28 -0
- westpa/mclib/_mclib.cpython-313-x86_64-linux-gnu.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 +153 -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 +361 -0
- westpa/oldtools/files.py +34 -0
- westpa/oldtools/miscfn.py +23 -0
- westpa/oldtools/stats/__init__.py +4 -0
- westpa/oldtools/stats/accumulator.py +35 -0
- westpa/oldtools/stats/edfs.py +129 -0
- westpa/oldtools/stats/mcbs.py +96 -0
- westpa/tools/__init__.py +33 -0
- westpa/tools/binning.py +472 -0
- westpa/tools/core.py +340 -0
- westpa/tools/data_reader.py +159 -0
- westpa/tools/dtypes.py +31 -0
- westpa/tools/iter_range.py +198 -0
- westpa/tools/kinetics_tool.py +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-313-x86_64-linux-gnu.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 +192 -0
- westpa/westext/wess/ProbAdjust.py +101 -0
- westpa/westext/wess/__init__.py +6 -0
- westpa/westext/wess/wess_driver.py +217 -0
- westpa/work_managers/__init__.py +57 -0
- westpa/work_managers/core.py +396 -0
- westpa/work_managers/environment.py +134 -0
- westpa/work_managers/mpi.py +318 -0
- westpa/work_managers/processes.py +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.12.dist-info/AUTHORS +22 -0
- westpa-2022.12.dist-info/LICENSE +21 -0
- westpa-2022.12.dist-info/METADATA +193 -0
- westpa-2022.12.dist-info/RECORD +149 -0
- westpa-2022.12.dist-info/WHEEL +6 -0
- westpa-2022.12.dist-info/entry_points.txt +29 -0
- 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()
|