westpa 2022.13__cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.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.
Files changed (162) 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 +749 -0
  5. westpa/analysis/statistics.py +27 -0
  6. westpa/analysis/trajectories.py +369 -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 +597 -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 +557 -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 +832 -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_timings.py +113 -0
  38. westpa/cli/tools/w_trace.py +599 -0
  39. westpa/core/__init__.py +0 -0
  40. westpa/core/_rc.py +673 -0
  41. westpa/core/binning/__init__.py +55 -0
  42. westpa/core/binning/_assign.c +36018 -0
  43. westpa/core/binning/_assign.cpython-312-aarch64-linux-gnu.so +0 -0
  44. westpa/core/binning/_assign.pyx +370 -0
  45. westpa/core/binning/assign.py +454 -0
  46. westpa/core/binning/binless.py +96 -0
  47. westpa/core/binning/binless_driver.py +54 -0
  48. westpa/core/binning/binless_manager.py +189 -0
  49. westpa/core/binning/bins.py +47 -0
  50. westpa/core/binning/mab.py +506 -0
  51. westpa/core/binning/mab_driver.py +54 -0
  52. westpa/core/binning/mab_manager.py +197 -0
  53. westpa/core/data_manager.py +1761 -0
  54. westpa/core/extloader.py +74 -0
  55. westpa/core/h5io.py +1079 -0
  56. westpa/core/kinetics/__init__.py +24 -0
  57. westpa/core/kinetics/_kinetics.c +45174 -0
  58. westpa/core/kinetics/_kinetics.cpython-312-aarch64-linux-gnu.so +0 -0
  59. westpa/core/kinetics/_kinetics.pyx +815 -0
  60. westpa/core/kinetics/events.py +147 -0
  61. westpa/core/kinetics/matrates.py +156 -0
  62. westpa/core/kinetics/rate_averaging.py +266 -0
  63. westpa/core/progress.py +218 -0
  64. westpa/core/propagators/__init__.py +54 -0
  65. westpa/core/propagators/executable.py +592 -0
  66. westpa/core/propagators/loaders.py +196 -0
  67. westpa/core/reweight/__init__.py +14 -0
  68. westpa/core/reweight/_reweight.c +36899 -0
  69. westpa/core/reweight/_reweight.cpython-312-aarch64-linux-gnu.so +0 -0
  70. westpa/core/reweight/_reweight.pyx +439 -0
  71. westpa/core/reweight/matrix.py +126 -0
  72. westpa/core/segment.py +119 -0
  73. westpa/core/sim_manager.py +839 -0
  74. westpa/core/states.py +359 -0
  75. westpa/core/systems.py +93 -0
  76. westpa/core/textio.py +74 -0
  77. westpa/core/trajectory.py +603 -0
  78. westpa/core/we_driver.py +910 -0
  79. westpa/core/wm_ops.py +43 -0
  80. westpa/core/yamlcfg.py +298 -0
  81. westpa/fasthist/__init__.py +34 -0
  82. westpa/fasthist/_fasthist.c +38755 -0
  83. westpa/fasthist/_fasthist.cpython-312-aarch64-linux-gnu.so +0 -0
  84. westpa/fasthist/_fasthist.pyx +222 -0
  85. westpa/mclib/__init__.py +271 -0
  86. westpa/mclib/__main__.py +28 -0
  87. westpa/mclib/_mclib.c +34610 -0
  88. westpa/mclib/_mclib.cpython-312-aarch64-linux-gnu.so +0 -0
  89. westpa/mclib/_mclib.pyx +226 -0
  90. westpa/oldtools/__init__.py +4 -0
  91. westpa/oldtools/aframe/__init__.py +35 -0
  92. westpa/oldtools/aframe/atool.py +75 -0
  93. westpa/oldtools/aframe/base_mixin.py +26 -0
  94. westpa/oldtools/aframe/binning.py +178 -0
  95. westpa/oldtools/aframe/data_reader.py +560 -0
  96. westpa/oldtools/aframe/iter_range.py +200 -0
  97. westpa/oldtools/aframe/kinetics.py +117 -0
  98. westpa/oldtools/aframe/mcbs.py +153 -0
  99. westpa/oldtools/aframe/output.py +39 -0
  100. westpa/oldtools/aframe/plotting.py +88 -0
  101. westpa/oldtools/aframe/trajwalker.py +126 -0
  102. westpa/oldtools/aframe/transitions.py +469 -0
  103. westpa/oldtools/cmds/__init__.py +0 -0
  104. westpa/oldtools/cmds/w_ttimes.py +361 -0
  105. westpa/oldtools/files.py +34 -0
  106. westpa/oldtools/miscfn.py +23 -0
  107. westpa/oldtools/stats/__init__.py +4 -0
  108. westpa/oldtools/stats/accumulator.py +35 -0
  109. westpa/oldtools/stats/edfs.py +129 -0
  110. westpa/oldtools/stats/mcbs.py +96 -0
  111. westpa/tools/__init__.py +33 -0
  112. westpa/tools/binning.py +472 -0
  113. westpa/tools/core.py +340 -0
  114. westpa/tools/data_reader.py +159 -0
  115. westpa/tools/dtypes.py +31 -0
  116. westpa/tools/iter_range.py +198 -0
  117. westpa/tools/kinetics_tool.py +343 -0
  118. westpa/tools/plot.py +283 -0
  119. westpa/tools/progress.py +17 -0
  120. westpa/tools/selected_segs.py +154 -0
  121. westpa/tools/wipi.py +751 -0
  122. westpa/trajtree/__init__.py +4 -0
  123. westpa/trajtree/_trajtree.c +17829 -0
  124. westpa/trajtree/_trajtree.cpython-312-aarch64-linux-gnu.so +0 -0
  125. westpa/trajtree/_trajtree.pyx +130 -0
  126. westpa/trajtree/trajtree.py +117 -0
  127. westpa/westext/__init__.py +0 -0
  128. westpa/westext/adaptvoronoi/__init__.py +3 -0
  129. westpa/westext/adaptvoronoi/adaptVor_driver.py +214 -0
  130. westpa/westext/hamsm_restarting/__init__.py +3 -0
  131. westpa/westext/hamsm_restarting/example_overrides.py +35 -0
  132. westpa/westext/hamsm_restarting/restart_driver.py +1165 -0
  133. westpa/westext/stringmethod/__init__.py +11 -0
  134. westpa/westext/stringmethod/fourier_fitting.py +69 -0
  135. westpa/westext/stringmethod/string_driver.py +253 -0
  136. westpa/westext/stringmethod/string_method.py +306 -0
  137. westpa/westext/weed/BinCluster.py +180 -0
  138. westpa/westext/weed/ProbAdjustEquil.py +100 -0
  139. westpa/westext/weed/UncertMath.py +247 -0
  140. westpa/westext/weed/__init__.py +10 -0
  141. westpa/westext/weed/weed_driver.py +192 -0
  142. westpa/westext/wess/ProbAdjust.py +101 -0
  143. westpa/westext/wess/__init__.py +6 -0
  144. westpa/westext/wess/wess_driver.py +217 -0
  145. westpa/work_managers/__init__.py +57 -0
  146. westpa/work_managers/core.py +396 -0
  147. westpa/work_managers/environment.py +134 -0
  148. westpa/work_managers/mpi.py +318 -0
  149. westpa/work_managers/processes.py +201 -0
  150. westpa/work_managers/serial.py +28 -0
  151. westpa/work_managers/threads.py +79 -0
  152. westpa/work_managers/zeromq/__init__.py +20 -0
  153. westpa/work_managers/zeromq/core.py +635 -0
  154. westpa/work_managers/zeromq/node.py +131 -0
  155. westpa/work_managers/zeromq/work_manager.py +526 -0
  156. westpa/work_managers/zeromq/worker.py +320 -0
  157. westpa-2022.13.dist-info/METADATA +179 -0
  158. westpa-2022.13.dist-info/RECORD +162 -0
  159. westpa-2022.13.dist-info/WHEEL +7 -0
  160. westpa-2022.13.dist-info/entry_points.txt +30 -0
  161. westpa-2022.13.dist-info/licenses/LICENSE +21 -0
  162. westpa-2022.13.dist-info/top_level.txt +1 -0
@@ -0,0 +1,226 @@
1
+ from westpa.tools import WESTParallelTool, WESTDataReader, IterRangeSelection, ProgressIndicatorComponent
2
+
3
+ import numpy as np
4
+
5
+ from westpa.core import h5io
6
+ from westpa.core.data_manager import seg_id_dtype, n_iter_dtype, weight_dtype
7
+ from westpa.core.extloader import get_object
8
+
9
+
10
+ def _find_matching_segments(west_datafile_name, n_iter, predicate, invert=False):
11
+ '''Find all segments in iteration ``n_iter`` that match (or do not match, if
12
+ ``invert`` is true) the given ``predicate``. Returns a sequence of matching
13
+ seg_ids.'''
14
+
15
+ with h5io.WESTPAH5File(west_datafile_name, 'r') as west_datafile:
16
+ iter_group = west_datafile.get_iter_group(n_iter)
17
+ nsegs = iter_group['seg_index'].shape[0]
18
+ matching_ids = set(map(int, predicate(n_iter, iter_group)))
19
+
20
+ if invert:
21
+ matching_ids = set(range(nsegs)) - matching_ids
22
+
23
+ matchvec = sorted(np.fromiter(matching_ids, dtype=seg_id_dtype, count=len(matching_ids)))
24
+ return n_iter, matchvec
25
+
26
+
27
+ class WSelectTool(WESTParallelTool):
28
+ prog = 'w_select'
29
+ description = '''\
30
+ Select dynamics segments matching various criteria. This requires a
31
+ user-provided prediate function. By default, only matching segments are
32
+ stored. If the -a/--include-ancestors option is given, then matching segments
33
+ and their ancestors will be stored.
34
+
35
+
36
+ -----------------------------------------------------------------------------
37
+ Predicate function
38
+ -----------------------------------------------------------------------------
39
+
40
+ Segments are selected based on a predicate function, which must be callable
41
+ as ``predicate(n_iter, iter_group)`` and return a collection of segment IDs
42
+ matching the predicate in that iteration.
43
+
44
+ The predicate may be inverted by specifying the -v/--invert command-line
45
+ argument.
46
+
47
+
48
+ -----------------------------------------------------------------------------
49
+ Output format
50
+ -----------------------------------------------------------------------------
51
+
52
+ The output file (-o/--output, by default "select.h5") contains the following
53
+ datasets:
54
+
55
+ ``/n_iter`` [iteration]
56
+ *(Integer)* Iteration numbers for each entry in other datasets.
57
+
58
+ ``/n_segs`` [iteration]
59
+ *(Integer)* Number of segment IDs matching the predicate (or inverted
60
+ predicate, if -v/--invert is specified) in the given iteration.
61
+
62
+ ``/seg_ids`` [iteration][segment]
63
+ *(Integer)* Matching segments in each iteration. For an iteration
64
+ ``n_iter``, only the first ``n_iter`` entries are valid. For example,
65
+ the full list of matching seg_ids in the first stored iteration is
66
+ ``seg_ids[0][:n_segs[0]]``.
67
+
68
+ ``/weights`` [iteration][segment]
69
+ *(Floating-point)* Weights for each matching segment in ``/seg_ids``.
70
+
71
+
72
+ -----------------------------------------------------------------------------
73
+ Command-line arguments
74
+ -----------------------------------------------------------------------------
75
+ '''
76
+
77
+ def __init__(self):
78
+ super().__init__()
79
+
80
+ self.data_reader = WESTDataReader()
81
+ self.iter_range = IterRangeSelection()
82
+ self.progress = ProgressIndicatorComponent()
83
+ self.output_file = None
84
+ self.output_filename = None
85
+ self.predicate = None
86
+ self.invert = False
87
+ self.include_ancestors = False
88
+
89
+ def add_args(self, parser):
90
+ self.data_reader.add_args(parser)
91
+ self.iter_range.add_args(parser)
92
+
93
+ sgroup = parser.add_argument_group('selection options')
94
+ sgroup.add_argument(
95
+ '-p',
96
+ '--predicate-function',
97
+ metavar='MODULE.FUNCTION',
98
+ help='''Use the given predicate function to match segments. This function
99
+ should take an iteration number and the HDF5 group corresponding to that
100
+ iteration and return a sequence of seg_ids matching the predicate, as in
101
+ ``match_predicate(n_iter, iter_group)``.''',
102
+ )
103
+ sgroup.add_argument('-v', '--invert', dest='invert', action='store_true', help='''Invert the match predicate.''')
104
+ sgroup.add_argument(
105
+ '-a', '--include-ancestors', action='store_true', help='''Include ancestors of matched segments in output.'''
106
+ )
107
+
108
+ ogroup = parser.add_argument_group('output options')
109
+ ogroup.add_argument('-o', '--output', default='select.h5', help='''Write output to OUTPUT (default: %(default)s).''')
110
+ self.progress.add_args(parser)
111
+
112
+ def process_args(self, args):
113
+ self.progress.process_args(args)
114
+ self.data_reader.process_args(args)
115
+ with self.data_reader:
116
+ self.iter_range.process_args(args)
117
+
118
+ predicate = get_object(args.predicate_function, path=['.'])
119
+ if not callable(predicate):
120
+ raise TypeError('predicate object {!r} is not callable'.format(predicate))
121
+ self.predicate = predicate
122
+ self.invert = bool(args.invert)
123
+ self.include_ancestors = bool(args.include_ancestors)
124
+ self.output_filename = args.output
125
+
126
+ def go(self):
127
+ self.data_reader.open('r')
128
+ output_file = h5io.WESTPAH5File(self.output_filename, mode='w')
129
+ pi = self.progress.indicator
130
+
131
+ iter_start, iter_stop = self.iter_range.iter_start, self.iter_range.iter_stop
132
+ iter_count = iter_stop - iter_start
133
+
134
+ output_file.create_dataset('n_iter', dtype=n_iter_dtype, data=list(range(iter_start, iter_stop)))
135
+ current_seg_count = 0
136
+ seg_count_ds = output_file.create_dataset('n_segs', dtype=np.uint, shape=(iter_count,))
137
+ matching_segs_ds = output_file.create_dataset(
138
+ 'seg_ids',
139
+ shape=(iter_count, 0),
140
+ maxshape=(iter_count, None),
141
+ dtype=seg_id_dtype,
142
+ chunks=h5io.calc_chunksize((iter_count, 1000000), seg_id_dtype),
143
+ shuffle=True,
144
+ compression=9,
145
+ )
146
+ weights_ds = output_file.create_dataset(
147
+ 'weights',
148
+ shape=(iter_count, 0),
149
+ maxshape=(iter_count, None),
150
+ dtype=weight_dtype,
151
+ chunks=h5io.calc_chunksize((iter_count, 1000000), weight_dtype),
152
+ shuffle=True,
153
+ compression=9,
154
+ )
155
+
156
+ with pi:
157
+ pi.new_operation('Finding matching segments', extent=iter_count)
158
+ # futures = set()
159
+ # for n_iter in xrange(iter_start,iter_stop):
160
+ # futures.add(self.work_manager.submit(_find_matching_segments,
161
+ # args=(self.data_reader.we_h5filename,n_iter,self.predicate,self.invert)))
162
+
163
+ # for future in self.work_manager.as_completed(futures):
164
+ for future in self.work_manager.submit_as_completed(
165
+ (
166
+ (_find_matching_segments, (self.data_reader.we_h5filename, n_iter, self.predicate, self.invert), {})
167
+ for n_iter in range(iter_start, iter_stop)
168
+ ),
169
+ self.max_queue_len,
170
+ ):
171
+ n_iter, matching_ids = future.get_result()
172
+ n_matches = len(matching_ids)
173
+
174
+ if n_matches:
175
+ if n_matches > current_seg_count:
176
+ current_seg_count = len(matching_ids)
177
+ matching_segs_ds.resize((iter_count, n_matches))
178
+ weights_ds.resize((iter_count, n_matches))
179
+ current_seg_count = n_matches
180
+
181
+ seg_count_ds[n_iter - iter_start] = n_matches
182
+ matching_segs_ds[n_iter - iter_start, :n_matches] = matching_ids
183
+ weights_ds[n_iter - iter_start, :n_matches] = self.data_reader.get_iter_group(n_iter)['seg_index']['weight'][
184
+ sorted(matching_ids)
185
+ ]
186
+ del matching_ids
187
+ pi.progress += 1
188
+
189
+ if self.include_ancestors:
190
+ pi.new_operation('Tracing ancestors of matching segments', extent=iter_count)
191
+ from_previous = set()
192
+ current_seg_count = matching_segs_ds.shape[1]
193
+ for n_iter in range(iter_stop - 1, iter_start - 1, -1):
194
+ iiter = n_iter - iter_start
195
+ n_matches = seg_count_ds[iiter]
196
+ matching_ids = set(from_previous)
197
+ if n_matches:
198
+ matching_ids.update(matching_segs_ds[iiter, : seg_count_ds[iiter]])
199
+ from_previous.clear()
200
+
201
+ n_matches = len(matching_ids)
202
+ if n_matches > current_seg_count:
203
+ matching_segs_ds.resize((iter_count, n_matches))
204
+ weights_ds.resize((iter_count, n_matches))
205
+ current_seg_count = n_matches
206
+
207
+ if n_matches > 0:
208
+ seg_count_ds[iiter] = n_matches
209
+ matching_ids = sorted(matching_ids)
210
+ matching_segs_ds[iiter, :n_matches] = matching_ids
211
+ weights_ds[iiter, :n_matches] = self.data_reader.get_iter_group(n_iter)['seg_index']['weight'][
212
+ sorted(matching_ids)
213
+ ]
214
+ parent_ids = self.data_reader.get_iter_group(n_iter)['seg_index']['parent_id'][sorted(matching_ids)]
215
+ from_previous.update(parent_id for parent_id in parent_ids if parent_id >= 0) # filter initial states
216
+ del parent_ids
217
+ del matching_ids
218
+ pi.progress += 1
219
+
220
+
221
+ def entry_point():
222
+ WSelectTool().main()
223
+
224
+
225
+ if __name__ == '__main__':
226
+ entry_point()
@@ -0,0 +1,111 @@
1
+ from westpa.tools import WESTMasterCommand, WESTParallelTool
2
+ from warnings import warn
3
+
4
+ from westpa.cli.tools.w_direct import DStateProbs
5
+
6
+ # Just a shim to make sure everything works and is backwards compatible.
7
+ # We're making sure it has the appropriate functions so that it can be called
8
+ # as a regular tool, and not a subcommand.
9
+
10
+
11
+ class WStateProbs(DStateProbs):
12
+ subcommand = 'trace'
13
+ help_text = 'averages and CIs for path-tracing kinetics analysis'
14
+ default_output_file = 'stateprobs.h5'
15
+ # This isn't strictly necessary, but for the moment, here it is.
16
+ # We really need to modify the underlying class so that we don't pull this sort of stuff if it isn't necessary.
17
+ # That'll take some case handling, which is fine.
18
+ default_kinetics_file = 'assign.h5'
19
+
20
+
21
+ class WDirect(WESTMasterCommand, WESTParallelTool):
22
+ prog = 'w_stateprobs'
23
+ subcommands = [WStateProbs]
24
+ subparsers_title = 'calculate state-to-state kinetics by tracing trajectories'
25
+ description = '''\
26
+ Calculate average populations and associated errors in state populations from
27
+ weighted ensemble data. Bin assignments, including macrostate definitions,
28
+ are required. (See "w_assign --help" for more information).
29
+
30
+ -----------------------------------------------------------------------------
31
+ Output format
32
+ -----------------------------------------------------------------------------
33
+
34
+ The output file (-o/--output, usually "stateprobs.h5") contains the following
35
+ dataset:
36
+
37
+ /avg_state_pops [state]
38
+ (Structured -- see below) Population of each state across entire
39
+ range specified.
40
+
41
+ If --evolution-mode is specified, then the following additional dataset is
42
+ available:
43
+
44
+ /state_pop_evolution [window][state]
45
+ (Structured -- see below). State populations based on windows of
46
+ iterations of varying width. If --evolution-mode=cumulative, then
47
+ these windows all begin at the iteration specified with
48
+ --start-iter and grow in length by --step-iter for each successive
49
+ element. If --evolution-mode=blocked, then these windows are all of
50
+ width --step-iter (excluding the last, which may be shorter), the first
51
+ of which begins at iteration --start-iter.
52
+
53
+ The structure of these datasets is as follows:
54
+
55
+ iter_start
56
+ (Integer) Iteration at which the averaging window begins (inclusive).
57
+
58
+ iter_stop
59
+ (Integer) Iteration at which the averaging window ends (exclusive).
60
+
61
+ expected
62
+ (Floating-point) Expected (mean) value of the rate as evaluated within
63
+ this window, in units of inverse tau.
64
+
65
+ ci_lbound
66
+ (Floating-point) Lower bound of the confidence interval on the rate
67
+ within this window, in units of inverse tau.
68
+
69
+ ci_ubound
70
+ (Floating-point) Upper bound of the confidence interval on the rate
71
+ within this window, in units of inverse tau.
72
+
73
+ corr_len
74
+ (Integer) Correlation length of the rate within this window, in units
75
+ of tau.
76
+
77
+ Each of these datasets is also stamped with a number of attributes:
78
+
79
+ mcbs_alpha
80
+ (Floating-point) Alpha value of confidence intervals. (For example,
81
+ *alpha=0.05* corresponds to a 95% confidence interval.)
82
+
83
+ mcbs_nsets
84
+ (Integer) Number of bootstrap data sets used in generating confidence
85
+ intervals.
86
+
87
+ mcbs_acalpha
88
+ (Floating-point) Alpha value for determining correlation lengths.
89
+
90
+
91
+ -----------------------------------------------------------------------------
92
+ Command-line options
93
+ -----------------------------------------------------------------------------
94
+ '''
95
+
96
+
97
+ def entry_point():
98
+ warn('{} is being deprecated. Please use w_direct instead.'.format(WDirect.prog))
99
+ # If we're not really supporting subcommands...
100
+ import sys
101
+
102
+ try:
103
+ if sys.argv[1] != 'trace':
104
+ sys.argv.insert(1, 'trace')
105
+ except Exception:
106
+ sys.argv.insert(1, 'trace')
107
+ WDirect().main()
108
+
109
+
110
+ if __name__ == '__main__':
111
+ entry_point()
@@ -0,0 +1,113 @@
1
+ from datetime import timedelta
2
+
3
+ import numpy as np
4
+
5
+ from westpa.tools import (
6
+ WESTTool,
7
+ WESTDataReader,
8
+ IterRangeSelection,
9
+ )
10
+
11
+
12
+ # NumPy fixed time units (excludes nonlinear units 'Y and 'M')
13
+ TIME_UNITS = ('W', 'D', 'h', 'm', 's', 'ms', 'us', 'ns', 'ps', 'fs', 'as')
14
+
15
+
16
+ def _unit(delta):
17
+ # Return the unit of a NumPy timedelta.
18
+ words = str(delta.dtype).split('[')
19
+ if len(words) == 1:
20
+ return None
21
+ return words[1][:-1]
22
+
23
+
24
+ def _str(delta):
25
+ # Return a string representation of a NumPy timedelta.
26
+ # Example: timedelta64(5380000, 'ps') -> '5.38 us'
27
+ if _unit(delta) is None:
28
+ return str(delta)
29
+ for unit in TIME_UNITS:
30
+ unit_delta = np.timedelta64(1, unit)
31
+ try:
32
+ if delta >= unit_delta:
33
+ break
34
+ except OverflowError:
35
+ continue
36
+ return f'{delta / unit_delta} {unit}'
37
+
38
+
39
+ def _delta(arg):
40
+ # Construct a NumPy timedelta from an argument string.
41
+ # Example: '100_ps' -> timedelta64(100, 'ps')
42
+ try:
43
+ value, unit = arg.split('_')
44
+ except ValueError:
45
+ raise ValueError('must be formatted as <value>_<unit>')
46
+ if unit not in TIME_UNITS + ('μs',): # accept either μs or us for microsecond
47
+ raise ValueError(f'{unit!r} is not a recognized time unit')
48
+ return np.timedelta64(int(value), unit)
49
+
50
+
51
+ class WTimings(WESTTool):
52
+ prog = 'w_timings'
53
+ description = 'Print timing information for a WESTPA simulation.'
54
+
55
+ def __init__(self):
56
+ super().__init__()
57
+ self.data_reader = WESTDataReader()
58
+ self.iter_range = IterRangeSelection(self.data_reader)
59
+ self.tau = None
60
+
61
+ def go(self):
62
+ start = self.iter_range.iter_start - 1
63
+ stop = self.iter_range.iter_stop - 1
64
+ with self.data_reader:
65
+ iter_summaries = self.data_reader.we_h5file['summary'][start:stop]
66
+
67
+ walltime = iter_summaries['walltime'].sum()
68
+ cputime = iter_summaries['cputime'].sum()
69
+ n_particles = iter_summaries['n_particles'].sum()
70
+ n_iters = len(iter_summaries)
71
+
72
+ width = 26
73
+ print('Iterations:'.ljust(width), n_iters)
74
+ print('Total segments:'.ljust(width), n_particles)
75
+ print('Wall-clock time:'.ljust(width), timedelta(seconds=walltime))
76
+ if not np.isclose(cputime, 0): # only print CPU time if it was recorded
77
+ print('Total CPU time:'.ljust(width), timedelta(seconds=cputime))
78
+ if self.tau is not None:
79
+ print('Maximum trajectory length:', _str(n_iters * self.tau))
80
+ print('Aggregate simulation time:', _str(n_particles * self.tau))
81
+
82
+ def add_args(self, parser):
83
+ self.data_reader.add_args(parser)
84
+ self.iter_range.add_args(parser)
85
+
86
+ unit_list = ', '.join(map(repr, TIME_UNITS[-1:0:-1])) + f', or {TIME_UNITS[0]!r}'
87
+ parser.add_argument(
88
+ '-t',
89
+ '--tau',
90
+ help=(
91
+ 'WE resampling interval (format: <value>_<unit>, where <value> '
92
+ f'is a positive integer and <unit> is {unit_list}).'
93
+ ),
94
+ )
95
+
96
+ def process_args(self, args):
97
+ self.data_reader.process_args(args)
98
+ with self.data_reader:
99
+ self.iter_range.process_args(args)
100
+
101
+ if args.tau is not None:
102
+ try:
103
+ self.tau = _delta(args.tau)
104
+ except (TypeError, ValueError) as e:
105
+ self.parser.error(f'argument -t/--tau: {e}')
106
+
107
+
108
+ def entry_point():
109
+ WTimings().main()
110
+
111
+
112
+ if __name__ == "__main__":
113
+ entry_point()