restage 0.3.2__tar.gz → 0.4.1__tar.gz
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.
- {restage-0.3.2/src/restage.egg-info → restage-0.4.1}/PKG-INFO +12 -4
- {restage-0.3.2 → restage-0.4.1}/pyproject.toml +11 -4
- {restage-0.3.2 → restage-0.4.1}/src/restage/bifrost_choppers.py +6 -5
- {restage-0.3.2 → restage-0.4.1}/src/restage/cache.py +2 -1
- {restage-0.3.2 → restage-0.4.1}/src/restage/energy.py +11 -6
- {restage-0.3.2 → restage-0.4.1}/src/restage/instr.py +4 -2
- {restage-0.3.2 → restage-0.4.1}/src/restage/splitrun.py +50 -56
- {restage-0.3.2 → restage-0.4.1}/src/restage/tables.py +2 -2
- {restage-0.3.2 → restage-0.4.1/src/restage.egg-info}/PKG-INFO +12 -4
- {restage-0.3.2 → restage-0.4.1}/src/restage.egg-info/SOURCES.txt +0 -2
- restage-0.4.1/src/restage.egg-info/requires.txt +8 -0
- {restage-0.3.2 → restage-0.4.1}/test/test_energy.py +36 -28
- {restage-0.3.2 → restage-0.4.1}/test/test_single.py +71 -18
- restage-0.3.2/src/restage.egg-info/requires.txt +0 -11
- restage-0.3.2/test/splitRunTest_first.c +0 -12419
- restage-0.3.2/test/splitRunTest_second.c +0 -10944
- {restage-0.3.2 → restage-0.4.1}/.github/workflows/pip.yml +0 -0
- {restage-0.3.2 → restage-0.4.1}/.github/workflows/wheels.yml +0 -0
- {restage-0.3.2 → restage-0.4.1}/.gitignore +0 -0
- {restage-0.3.2 → restage-0.4.1}/README.md +0 -0
- {restage-0.3.2 → restage-0.4.1}/setup.cfg +0 -0
- {restage-0.3.2 → restage-0.4.1}/src/restage/__init__.py +0 -0
- {restage-0.3.2 → restage-0.4.1}/src/restage/cspec_choppers.py +0 -0
- {restage-0.3.2 → restage-0.4.1}/src/restage/database.py +0 -0
- {restage-0.3.2 → restage-0.4.1}/src/restage/emulate.py +0 -0
- {restage-0.3.2 → restage-0.4.1}/src/restage/mcpl.py +0 -0
- {restage-0.3.2 → restage-0.4.1}/src/restage/range.py +0 -0
- {restage-0.3.2 → restage-0.4.1}/src/restage/run.py +0 -0
- {restage-0.3.2 → restage-0.4.1}/src/restage/scan.py +0 -0
- {restage-0.3.2 → restage-0.4.1}/src/restage.egg-info/dependency_links.txt +0 -0
- {restage-0.3.2 → restage-0.4.1}/src/restage.egg-info/entry_points.txt +0 -0
- {restage-0.3.2 → restage-0.4.1}/src/restage.egg-info/top_level.txt +0 -0
- {restage-0.3.2 → restage-0.4.1}/test/test_cache.py +0 -0
- {restage-0.3.2 → restage-0.4.1}/test/test_database.py +0 -0
- {restage-0.3.2 → restage-0.4.1}/test/test_range.py +0 -0
- {restage-0.3.2 → restage-0.4.1}/test/test_scan.py +0 -0
|
@@ -1,14 +1,22 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: restage
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Author-email: Gregory Tucker <gregory.tucker@ess.eu>
|
|
5
|
+
License: BSD-3-Clause
|
|
5
6
|
Classifier: License :: OSI Approved :: BSD License
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Requires-Python: >=3.9
|
|
6
15
|
Description-Content-Type: text/markdown
|
|
7
16
|
Requires-Dist: zenlog>=1.1
|
|
8
17
|
Requires-Dist: platformdirs>=3.11
|
|
9
18
|
Requires-Dist: psutil>=5.9.6
|
|
10
|
-
Requires-Dist:
|
|
11
|
-
Requires-Dist: mccode-antlr[hdf5]>=0.7.1
|
|
19
|
+
Requires-Dist: mccode-antlr[hdf5]>=0.10.2
|
|
12
20
|
Provides-Extra: test
|
|
13
21
|
Requires-Dist: pytest; extra == "test"
|
|
14
22
|
Requires-Dist: chopcal; extra == "test"
|
|
@@ -8,15 +8,23 @@ dependencies = [
|
|
|
8
8
|
'zenlog>=1.1',
|
|
9
9
|
'platformdirs>=3.11',
|
|
10
10
|
'psutil>=5.9.6',
|
|
11
|
-
|
|
12
|
-
'mccode-antlr[hdf5]>=0.7.1',
|
|
11
|
+
'mccode-antlr[hdf5]>=0.10.2',
|
|
13
12
|
]
|
|
14
13
|
readme = "README.md"
|
|
14
|
+
license = {text = "BSD-3-Clause"}
|
|
15
|
+
requires-python = ">=3.9"
|
|
15
16
|
authors = [
|
|
16
17
|
{ name = "Gregory Tucker", email = "gregory.tucker@ess.eu" },
|
|
17
18
|
]
|
|
18
19
|
classifiers = [
|
|
19
20
|
"License :: OSI Approved :: BSD License",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
23
|
+
"Programming Language :: Python :: 3.9",
|
|
24
|
+
"Programming Language :: Python :: 3.10",
|
|
25
|
+
"Programming Language :: Python :: 3.11",
|
|
26
|
+
"Programming Language :: Python :: 3.12",
|
|
27
|
+
"Programming Language :: Python :: 3.13",
|
|
20
28
|
]
|
|
21
29
|
dynamic = ["version"]
|
|
22
30
|
|
|
@@ -35,10 +43,9 @@ legacy_tox_ini = """
|
|
|
35
43
|
[tox]
|
|
36
44
|
min_version = 4.0
|
|
37
45
|
env_list =
|
|
46
|
+
py313
|
|
38
47
|
py312
|
|
39
48
|
py311
|
|
40
|
-
py310
|
|
41
|
-
py39
|
|
42
49
|
type
|
|
43
50
|
|
|
44
51
|
[testenv]
|
|
@@ -82,9 +82,7 @@ def bandwidth_chopper_speeds_phases(energy_minimum: float):
|
|
|
82
82
|
return SOURCE_FREQUENCY, phase, -SOURCE_FREQUENCY, phase
|
|
83
83
|
|
|
84
84
|
|
|
85
|
-
def calculate(order: float, time: float, energy: float, names:
|
|
86
|
-
if names is None or len(names) != 6:
|
|
87
|
-
names = ['ps1', 'ps2', 'fo1', 'fo2', 'bw1', 'bw2']
|
|
85
|
+
def calculate(order: float, time: float, energy: float, names: tuple[str, ...]):
|
|
88
86
|
a, b, c, d, e, f = names
|
|
89
87
|
s, p = 'speed', 'phase'
|
|
90
88
|
r = dict()
|
|
@@ -94,9 +92,12 @@ def calculate(order: float, time: float, energy: float, names: list[str] | None
|
|
|
94
92
|
return r
|
|
95
93
|
|
|
96
94
|
|
|
97
|
-
def main(order: float, time: float, energy: float, names:
|
|
95
|
+
def main(order: float, time: float, energy: float, names: tuple[str, ...] | None = None):
|
|
98
96
|
if names is None or len(names) != 6:
|
|
99
|
-
names =
|
|
97
|
+
# names = ('ps1', 'ps2', 'fo1', 'fo2', 'bw1', 'bw2')
|
|
98
|
+
names = ('pulse_shaping_chopper_1', 'pulse_shaping_chopper_2',
|
|
99
|
+
'frame_overlap_chopper_1', 'frame_overlap_chopper_2',
|
|
100
|
+
'bandwidth_chopper_1', 'bandwidth_chopper_2')
|
|
100
101
|
rep = calculate(order, time, energy, names)
|
|
101
102
|
print(' '.join([f'{k}={v}' for k, v in rep.items()]))
|
|
102
103
|
|
|
@@ -2,7 +2,6 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from mccode_antlr.instr import Instr
|
|
4
4
|
from .tables import InstrEntry, SimulationTableEntry, SimulationEntry
|
|
5
|
-
from mccode_antlr.compiler.c import CBinaryTarget
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
def setup_database(named: str):
|
|
@@ -54,6 +53,8 @@ def _compile_instr(entry: InstrEntry, instr: Instr, config: dict | None = None,
|
|
|
54
53
|
generator = MCSTAS_GENERATOR
|
|
55
54
|
|
|
56
55
|
output = directory_under_module_data_path('bin')
|
|
56
|
+
# TODO consider adding `dump_source=True` _and_ putting the resulting file into
|
|
57
|
+
# the cache in order to make debugging future problems a tiny bit easier.
|
|
57
58
|
binary_path = compile_instrument(instr, target, output, generator=generator, config=config)
|
|
58
59
|
entry.mccode_version = __version__
|
|
59
60
|
entry.binary_path = str(binary_path)
|
|
@@ -10,13 +10,15 @@ def get_and_remove(d: dict, k: str, default=None):
|
|
|
10
10
|
return default
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def one_generic_energy_to_chopper_parameters(
|
|
13
|
+
def one_generic_energy_to_chopper_parameters(
|
|
14
|
+
calculate_choppers, chopper_names: tuple[str, ...],
|
|
15
|
+
time: float, order: int, parameters: dict):
|
|
14
16
|
if any(x in parameters for x in ('ei', 'wavelength', 'lambda', 'energy', 'e')):
|
|
15
17
|
ei = get_and_remove(parameters, 'ei', get_and_remove(parameters, 'energy', get_and_remove(parameters, 'e')))
|
|
16
18
|
if ei is None:
|
|
17
19
|
wavelength = get_and_remove(parameters, 'wavelength', get_and_remove(parameters, 'lambda'))
|
|
18
20
|
ei = _wavelength_angstrom_to_energy_mev(wavelength)
|
|
19
|
-
choppers = calculate_choppers(order, time, ei)
|
|
21
|
+
choppers = calculate_choppers(order, time, ei, names=chopper_names)
|
|
20
22
|
parameters.update(choppers)
|
|
21
23
|
return parameters
|
|
22
24
|
|
|
@@ -24,25 +26,28 @@ def one_generic_energy_to_chopper_parameters(calculate_choppers, time: float, or
|
|
|
24
26
|
def bifrost_translate_energy_to_chopper_parameters(parameters: dict):
|
|
25
27
|
from itertools import product
|
|
26
28
|
from .bifrost_choppers import calculate
|
|
27
|
-
|
|
29
|
+
choppers = tuple(f'{a}_chopper_{b}' for a, b in product(['pulse_shaping', 'frame_overlap', 'bandwidth'], [1, 2]))
|
|
30
|
+
# names = [a+b for a, b in product(('ps', 'fo', 'bw'), ('1', '2'))]
|
|
31
|
+
for name in product(choppers, ('speed', 'phase')):
|
|
28
32
|
name = ''.join(name)
|
|
29
33
|
if name not in parameters:
|
|
30
34
|
parameters[name] = 0
|
|
31
35
|
order = get_and_remove(parameters, 'order', 14)
|
|
32
36
|
time = get_and_remove(parameters, 'time', get_and_remove(parameters, 't', 170/180/(2 * 15 * 14)))
|
|
33
|
-
return one_generic_energy_to_chopper_parameters(calculate, time, order, parameters)
|
|
37
|
+
return one_generic_energy_to_chopper_parameters(calculate, choppers, time, order, parameters)
|
|
34
38
|
|
|
35
39
|
|
|
36
40
|
def cspec_translate_energy_to_chopper_parameters(parameters: dict):
|
|
37
41
|
from itertools import product
|
|
38
42
|
from .cspec_choppers import calculate
|
|
39
|
-
|
|
43
|
+
choppers = ('bw1', 'bw2', 'bw3', 's', 'p', 'm1', 'm2')
|
|
44
|
+
for name in product(choppers, ('speed', 'phase')):
|
|
40
45
|
name = ''.join(name)
|
|
41
46
|
if name not in parameters:
|
|
42
47
|
parameters[name] = 0
|
|
43
48
|
time = get_and_remove(parameters, 'time', 0.004)
|
|
44
49
|
order = get_and_remove(parameters, 'order', 16)
|
|
45
|
-
return one_generic_energy_to_chopper_parameters(calculate, time, order, parameters)
|
|
50
|
+
return one_generic_energy_to_chopper_parameters(calculate, choppers, time, order, parameters)
|
|
46
51
|
|
|
47
52
|
|
|
48
53
|
def no_op_translate_energy_to_chopper_parameters(parameters: dict):
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Utilities for interfacing with mccode_antlr.instr.Instr objects
|
|
3
3
|
"""
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
4
6
|
from pathlib import Path
|
|
5
7
|
from typing import Union
|
|
6
8
|
from mccode_antlr.instr import Instr
|
|
@@ -8,8 +10,8 @@ from mccode_antlr.instr import Instr
|
|
|
8
10
|
|
|
9
11
|
def load_instr(filepath: Union[str, Path]) -> Instr:
|
|
10
12
|
"""Loads an Instr object from a .instr file or a HDF5 file"""
|
|
11
|
-
from mccode_antlr.loader import load_mcstas_instr
|
|
12
13
|
from mccode_antlr.io import load_hdf5
|
|
14
|
+
from mccode_antlr.loader import load_mcstas_instr
|
|
13
15
|
|
|
14
16
|
if not isinstance(filepath, Path):
|
|
15
17
|
filepath = Path(filepath)
|
|
@@ -44,7 +46,7 @@ def collect_parameter_dict(instr: Instr, kwargs: dict, strict: bool = True) -> d
|
|
|
44
46
|
for k, v in kwargs.items():
|
|
45
47
|
if k not in parameters:
|
|
46
48
|
if strict:
|
|
47
|
-
raise ValueError(f"Parameter {k} is not a valid parameter name")
|
|
49
|
+
raise ValueError(f"Parameter {k} is not a valid parameter name. Valid names are: {', '.join(parameters)}")
|
|
48
50
|
continue
|
|
49
51
|
if not isinstance(v, Value):
|
|
50
52
|
expected_type = parameters[k].data_type
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import Union
|
|
4
3
|
from pathlib import Path
|
|
5
|
-
from .range import Singular, MRange
|
|
6
4
|
from .tables import SimulationEntry, InstrEntry
|
|
7
|
-
from mccode_antlr.compiler.c import CBinaryTarget
|
|
8
5
|
|
|
6
|
+
def mcpl_parameter_split(s: str) -> tuple[str, str]:
|
|
7
|
+
k, v = s.split(':', 1)
|
|
8
|
+
return k, v
|
|
9
9
|
|
|
10
10
|
def make_splitrun_parser():
|
|
11
11
|
from argparse import ArgumentParser
|
|
@@ -40,6 +40,12 @@ def make_splitrun_parser():
|
|
|
40
40
|
# splitrun controlling parameters
|
|
41
41
|
aa('--split-at', nargs=1, type=str, default=['mcpl_split'],
|
|
42
42
|
help='Component at which to split -- DEFAULT: mcpl_split')
|
|
43
|
+
aa('--mcpl-output-component', nargs=1, type=str, default=None,
|
|
44
|
+
help='Inserted MCPL file producing component, MCPL_output(.comp) if not provided')
|
|
45
|
+
aa('--mcpl-input-component', nargs=1, type=str, default=None,
|
|
46
|
+
help='Inserted MCPL file consuming component, MCPL_input(.comp) if not provided')
|
|
47
|
+
aa('--mcpl-input-parameters', nargs='+', type=mcpl_parameter_split, metavar='key:value')
|
|
48
|
+
aa('--mcpl-output-parameters', nargs='+', type=mcpl_parameter_split, metavar='key:value')
|
|
43
49
|
aa('-P', action='append', default=[], help='Cache parameter matching precision')
|
|
44
50
|
|
|
45
51
|
# Other McCode runtime arguments exist, but are likely not used during a scan:
|
|
@@ -78,31 +84,6 @@ def regular_mccode_runtime_dict(args: dict) -> dict:
|
|
|
78
84
|
return t
|
|
79
85
|
|
|
80
86
|
|
|
81
|
-
def mccode_runtime_dict_to_args_list(args: dict) -> list[str]:
|
|
82
|
-
"""Convert a dictionary of McCode runtime arguments to a string.
|
|
83
|
-
|
|
84
|
-
:parameter args: A dictionary of McCode runtime arguments.
|
|
85
|
-
:return: A list of arguments suitable for use in a command line call to a McCode compiled instrument.
|
|
86
|
-
"""
|
|
87
|
-
# convert to a standardized string:
|
|
88
|
-
out = []
|
|
89
|
-
if 'seed' in args and args['seed'] is not None:
|
|
90
|
-
out.append(f'--seed={args["seed"]}')
|
|
91
|
-
if 'ncount' in args and args['ncount'] is not None:
|
|
92
|
-
out.append(f'--ncount={args["ncount"]}')
|
|
93
|
-
if 'dir' in args and args['dir'] is not None:
|
|
94
|
-
out.append(f'--dir={args["dir"]}')
|
|
95
|
-
if 'trace' in args and args['trace']:
|
|
96
|
-
out.append('--trace')
|
|
97
|
-
if 'gravitation' in args and args['gravitation']:
|
|
98
|
-
out.append('--gravitation')
|
|
99
|
-
if 'bufsiz' in args and args['bufsiz'] is not None:
|
|
100
|
-
out.append(f'--bufsiz={args["bufsiz"]}')
|
|
101
|
-
if 'format' in args and args['format'] is not None:
|
|
102
|
-
out.append(f'--format={args["format"]}')
|
|
103
|
-
return out
|
|
104
|
-
|
|
105
|
-
|
|
106
87
|
def parse_splitrun_precision(unparsed: list[str]) -> dict[str, float]:
|
|
107
88
|
precision = {}
|
|
108
89
|
for p in unparsed:
|
|
@@ -113,43 +94,34 @@ def parse_splitrun_precision(unparsed: list[str]) -> dict[str, float]:
|
|
|
113
94
|
return precision
|
|
114
95
|
|
|
115
96
|
|
|
116
|
-
def
|
|
117
|
-
"""Take the list of arguments and sort them into the correct order for splitrun"""
|
|
118
|
-
# TODO this is a bit of a hack, but it works for now
|
|
119
|
-
first, last = [], []
|
|
120
|
-
k = 0
|
|
121
|
-
while k < len(args):
|
|
122
|
-
if args[k].startswith('-'):
|
|
123
|
-
first.append(args[k])
|
|
124
|
-
k += 1
|
|
125
|
-
if '=' not in first[-1] and k < len(args) and not args[k].startswith('-') and '=' not in args[k]:
|
|
126
|
-
first.append(args[k])
|
|
127
|
-
k += 1
|
|
128
|
-
else:
|
|
129
|
-
last.append(args[k])
|
|
130
|
-
k += 1
|
|
131
|
-
return first + last
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
def parse_splitrun():
|
|
97
|
+
def parse_splitrun(parser):
|
|
135
98
|
from .range import parse_scan_parameters
|
|
99
|
+
from mccode_antlr.run.runner import sort_args
|
|
136
100
|
import sys
|
|
137
101
|
sys.argv[1:] = sort_args(sys.argv[1:])
|
|
138
102
|
|
|
139
|
-
args =
|
|
103
|
+
args = parser.parse_args()
|
|
104
|
+
if args.mcpl_input_parameters is not None:
|
|
105
|
+
args.mcpl_input_parameters = dict(args.mcpl_input_parameters)
|
|
106
|
+
if args.mcpl_output_parameters is not None:
|
|
107
|
+
args.mcpl_output_parameters = dict(args.mcpl_output_parameters)
|
|
140
108
|
parameters = parse_scan_parameters(args.parameters)
|
|
141
109
|
precision = parse_splitrun_precision(args.P)
|
|
142
110
|
return args, parameters, precision
|
|
143
111
|
|
|
144
112
|
|
|
145
113
|
def entrypoint():
|
|
146
|
-
args, parameters, precision = parse_splitrun()
|
|
114
|
+
args, parameters, precision = parse_splitrun(make_splitrun_parser())
|
|
147
115
|
splitrun_from_file(args, parameters, precision)
|
|
148
116
|
|
|
149
117
|
|
|
150
118
|
def splitrun_from_file(args, parameters, precision):
|
|
151
119
|
from .instr import load_instr
|
|
152
120
|
instr = load_instr(args.instrument[0])
|
|
121
|
+
splitrun_args(instr, parameters, precision, args)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def splitrun_args(instr, parameters, precision, args, **kwargs):
|
|
153
125
|
splitrun(instr, parameters, precision, split_at=args.split_at[0], grid=args.mesh,
|
|
154
126
|
seed=args.seed[0] if args.seed is not None else None,
|
|
155
127
|
ncount=args.ncount[0] if args.ncount is not None else None,
|
|
@@ -164,6 +136,11 @@ def splitrun_from_file(args, parameters, precision):
|
|
|
164
136
|
parallel=args.parallel,
|
|
165
137
|
gpu=args.gpu,
|
|
166
138
|
process_count=args.process_count,
|
|
139
|
+
mcpl_output_component=args.mcpl_output_component[0] if args.mcpl_output_component is not None else None,
|
|
140
|
+
mcpl_output_parameters=args.mcpl_output_parameters,
|
|
141
|
+
mcpl_input_component=args.mcpl_input_component[0] if args.mcpl_input_component is not None else None,
|
|
142
|
+
mcpl_input_parameters=args.mcpl_input_parameters,
|
|
143
|
+
**kwargs
|
|
167
144
|
)
|
|
168
145
|
|
|
169
146
|
|
|
@@ -174,8 +151,11 @@ def splitrun(instr, parameters, precision: dict[str, float], split_at=None, grid
|
|
|
174
151
|
parallel=False, gpu=False, process_count=0,
|
|
175
152
|
callback=None, callback_arguments: dict[str, str] | None = None,
|
|
176
153
|
output_split_instrs=True,
|
|
154
|
+
mcpl_output_component=None, mcpl_output_parameters: dict[str, str] | None = None,
|
|
155
|
+
mcpl_input_component=None, mcpl_input_parameters: dict[str, str] | None = None,
|
|
177
156
|
**runtime_arguments):
|
|
178
157
|
from zenlog import log
|
|
158
|
+
from mccode_antlr.common import ComponentParameter, Expr
|
|
179
159
|
from .energy import get_energy_parameter_names
|
|
180
160
|
if split_at is None:
|
|
181
161
|
split_at = 'mcpl_split'
|
|
@@ -183,7 +163,17 @@ def splitrun(instr, parameters, precision: dict[str, float], split_at=None, grid
|
|
|
183
163
|
if not instr.has_component_named(split_at):
|
|
184
164
|
log.error(f'The specified split-at component, {split_at}, does not exist in the instrument file')
|
|
185
165
|
# splitting defines an instrument parameter in both returned instrument, 'mcpl_filename'.
|
|
186
|
-
|
|
166
|
+
if mcpl_output_parameters is not None:
|
|
167
|
+
mcpl_output_parameters = tuple(ComponentParameter(k, Expr.parse(v)) for k, v in mcpl_output_parameters.items())
|
|
168
|
+
if mcpl_input_parameters is not None:
|
|
169
|
+
mcpl_input_parameters = tuple(ComponentParameter(k, Expr.parse(v)) for k, v in mcpl_input_parameters.items())
|
|
170
|
+
pre, post = instr.mcpl_split(split_at,
|
|
171
|
+
output_component=mcpl_output_component,
|
|
172
|
+
output_parameters=mcpl_output_parameters,
|
|
173
|
+
input_component=mcpl_input_component,
|
|
174
|
+
input_parameters=mcpl_input_parameters,
|
|
175
|
+
remove_unused_parameters=True
|
|
176
|
+
)
|
|
187
177
|
if output_split_instrs:
|
|
188
178
|
for p in (pre, post):
|
|
189
179
|
with open(f'{p.name}.instr', 'w') as f:
|
|
@@ -204,7 +194,8 @@ def splitrun(instr, parameters, precision: dict[str, float], split_at=None, grid
|
|
|
204
194
|
dry_run=dry_run, parallel=parallel, gpu=gpu, process_count=process_count)
|
|
205
195
|
|
|
206
196
|
splitrun_combined(pre_entry, pre, post, pre_parameters, post_parameters, grid, precision,
|
|
207
|
-
dry_run=dry_run,
|
|
197
|
+
dry_run=dry_run, parallel=parallel, gpu=gpu, process_count=process_count,
|
|
198
|
+
callback=callback, callback_arguments=callback_arguments, **runtime_arguments)
|
|
208
199
|
|
|
209
200
|
|
|
210
201
|
def splitrun_pre(instr, parameters, grid, precision: dict[str, float],
|
|
@@ -259,6 +250,7 @@ def _pre_step(instr, entry, names, precision, translate, kw, min_pc, max_pc, dry
|
|
|
259
250
|
|
|
260
251
|
def splitrun_combined(pre_entry, pre, post, pre_parameters, post_parameters, grid, precision: dict[str, float],
|
|
261
252
|
summary=True, dry_run=False, callback=None, callback_arguments: dict[str, str] | None = None,
|
|
253
|
+
parallel=False, gpu=False, process_count=0,
|
|
262
254
|
**runtime_arguments):
|
|
263
255
|
from pathlib import Path
|
|
264
256
|
from .cache import cache_instr, cache_get_simulation
|
|
@@ -267,7 +259,7 @@ def splitrun_combined(pre_entry, pre, post, pre_parameters, post_parameters, gri
|
|
|
267
259
|
from .instr import collect_parameter_dict
|
|
268
260
|
from .tables import best_simulation_entry_match
|
|
269
261
|
from .emulate import mccode_sim_io, mccode_dat_io, mccode_dat_line
|
|
270
|
-
instr_entry = cache_instr(post, mpi=
|
|
262
|
+
instr_entry = cache_instr(post, mpi=parallel, acc=gpu)
|
|
271
263
|
args = regular_mccode_runtime_dict(runtime_arguments)
|
|
272
264
|
sit_kw = {'seed': args.get('seed'), 'ncount': args.get('ncount'), 'gravitation': args.get('gravitation', False)}
|
|
273
265
|
# recombine the parameters to ensure the 'correct' scan is performed
|
|
@@ -308,7 +300,7 @@ def splitrun_combined(pre_entry, pre, post, pre_parameters, post_parameters, gri
|
|
|
308
300
|
# TODO Use the following line instead of the one after it when McCode is fixed to use zero-padded folder names
|
|
309
301
|
# # runtime_arguments['dir'] = args["dir"].joinpath(str(number).zfill(n_zeros))
|
|
310
302
|
runtime_arguments['dir'] = args['dir'].joinpath(str(number))
|
|
311
|
-
do_secondary_simulation(sim_entry, instr_entry, secondary_pars, runtime_arguments, dry_run=dry_run)
|
|
303
|
+
do_secondary_simulation(sim_entry, instr_entry, secondary_pars, runtime_arguments, dry_run=dry_run, process_count=process_count)
|
|
312
304
|
if summary and not dry_run:
|
|
313
305
|
# the data file has *all* **scanned** parameters recorded for each step:
|
|
314
306
|
detectors, line = mccode_dat_line(runtime_arguments['dir'], {k: v for k,v in zip(names, values)})
|
|
@@ -332,7 +324,8 @@ def splitrun_combined(pre_entry, pre, post, pre_parameters, post_parameters, gri
|
|
|
332
324
|
|
|
333
325
|
|
|
334
326
|
def _args_pars_mcpl(args: dict, params: dict, mcpl_filename) -> str:
|
|
335
|
-
|
|
327
|
+
"""Combine the arguments, parameters, and mcpl filename into a single command-arguments string:"""
|
|
328
|
+
from mccode_antlr.run.runner import mccode_runtime_dict_to_args_list
|
|
336
329
|
first = ' '.join(mccode_runtime_dict_to_args_list(args))
|
|
337
330
|
second = ' '.join([f'{k}={v}' for k, v in params.items()])
|
|
338
331
|
third = f'mcpl_filename={mcpl_filename}'
|
|
@@ -457,7 +450,8 @@ def repeat_simulation_until(count, runner, args: dict, parameters, work_dir: Pat
|
|
|
457
450
|
combine_mccode_sims_in_directories(outputs, work_dir)
|
|
458
451
|
|
|
459
452
|
|
|
460
|
-
def do_secondary_simulation(p_sit: SimulationEntry, entry: InstrEntry, pars: dict, args: dict, dry_run: bool = False
|
|
453
|
+
def do_secondary_simulation(p_sit: SimulationEntry, entry: InstrEntry, pars: dict, args: dict, dry_run: bool = False,
|
|
454
|
+
process_count: int = 0):
|
|
461
455
|
from zenlog import log
|
|
462
456
|
from pathlib import Path
|
|
463
457
|
from shutil import copy
|
|
@@ -475,7 +469,7 @@ def do_secondary_simulation(p_sit: SimulationEntry, entry: InstrEntry, pars: dic
|
|
|
475
469
|
|
|
476
470
|
mcpl_path = mcpl_real_filename(Path(p_sit.output_path).joinpath(mcpl_filename))
|
|
477
471
|
executable = Path(entry.binary_path)
|
|
478
|
-
target = CBinaryTarget(mpi=entry.mpi, acc=entry.acc, count=
|
|
472
|
+
target = CBinaryTarget(mpi=entry.mpi, acc=entry.acc, count=process_count, nexus=False)
|
|
479
473
|
run_compiled_instrument(executable, target, _args_pars_mcpl(args, pars, mcpl_path), capture=False, dry_run=dry_run)
|
|
480
474
|
|
|
481
475
|
if not dry_run:
|
|
@@ -10,8 +10,8 @@ def uuid():
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def utc_timestamp() -> float:
|
|
13
|
-
from datetime import datetime
|
|
14
|
-
return datetime.
|
|
13
|
+
from datetime import datetime, timezone
|
|
14
|
+
return datetime.now(timezone.utc).timestamp()
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
COMMON_COLUMNS = ['seed', 'ncount', 'output_path', 'gravitation', 'creation', 'last_access']
|
|
@@ -1,14 +1,22 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: restage
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Author-email: Gregory Tucker <gregory.tucker@ess.eu>
|
|
5
|
+
License: BSD-3-Clause
|
|
5
6
|
Classifier: License :: OSI Approved :: BSD License
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Requires-Python: >=3.9
|
|
6
15
|
Description-Content-Type: text/markdown
|
|
7
16
|
Requires-Dist: zenlog>=1.1
|
|
8
17
|
Requires-Dist: platformdirs>=3.11
|
|
9
18
|
Requires-Dist: psutil>=5.9.6
|
|
10
|
-
Requires-Dist:
|
|
11
|
-
Requires-Dist: mccode-antlr[hdf5]>=0.7.1
|
|
19
|
+
Requires-Dist: mccode-antlr[hdf5]>=0.10.2
|
|
12
20
|
Provides-Extra: test
|
|
13
21
|
Requires-Dist: pytest; extra == "test"
|
|
14
22
|
Requires-Dist: chopcal; extra == "test"
|
|
@@ -23,8 +23,6 @@ src/restage.egg-info/dependency_links.txt
|
|
|
23
23
|
src/restage.egg-info/entry_points.txt
|
|
24
24
|
src/restage.egg-info/requires.txt
|
|
25
25
|
src/restage.egg-info/top_level.txt
|
|
26
|
-
test/splitRunTest_first.c
|
|
27
|
-
test/splitRunTest_second.c
|
|
28
26
|
test/test_cache.py
|
|
29
27
|
test/test_database.py
|
|
30
28
|
test/test_energy.py
|
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
import unittest
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
def parameters(names: tuple[str, ...]):
|
|
5
|
+
from itertools import product
|
|
6
|
+
return tuple(x + y for x, y in product(names, ('speed', 'phase')))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
CHOPPER_NAMES = ('pulse_shaping', 'frame_overlap', 'bandwidth')
|
|
10
|
+
CHOPPERS = tuple(f'{name}_chopper_{no}' for name in CHOPPER_NAMES for no in (1, 2))
|
|
11
|
+
OLD_CHOPPERS = tuple(f'{name}{no}' for name in ('ps', 'fo', 'bw') for no in (1, 2))
|
|
12
|
+
|
|
13
|
+
|
|
3
14
|
class BIFROSTEnergyTestCase(unittest.TestCase):
|
|
4
15
|
def setUp(self):
|
|
5
16
|
from mccode_antlr.loader import parse_mcstas_instr
|
|
6
17
|
instr = f"""DEFINE INSTRUMENT this_IS_NOT_BIFROST(
|
|
7
|
-
|
|
18
|
+
pulse_shaping_chopper_1speed, pulse_shaping_chopper_1phase, pulse_shaping_chopper_2speed, pulse_shaping_chopper_2phase, frame_overlap_chopper_1speed, frame_overlap_chopper_1phase, bandwidth_chopper_1speed, bandwidth_chopper_1phase, bandwidth_chopper_2speed, bandwidth_chopper_2phase
|
|
8
19
|
)
|
|
9
20
|
TRACE
|
|
10
21
|
COMPONENT origin = Arm() AT (0, 0, 0) ABSOLUTE
|
|
11
|
-
COMPONENT
|
|
12
|
-
COMPONENT
|
|
13
|
-
COMPONENT
|
|
14
|
-
COMPONENT
|
|
15
|
-
COMPONENT
|
|
16
|
-
COMPONENT
|
|
17
|
-
COMPONENT sample = Arm() AT (0, 0, 80) RELATIVE
|
|
22
|
+
COMPONENT pulse_shaping_chopper_1 = DiskChopper(theta_0=170, radius=0.35, nu=pulse_shaping_chopper_1speed, phase=pulse_shaping_chopper_1phase) AT (0, 0, 1) RELATIVE PREVIOUS
|
|
23
|
+
COMPONENT pulse_shaping_chopper_2 = DiskChopper(theta_0=170, radius=0.35, nu=pulse_shaping_chopper_2speed, phase=pulse_shaping_chopper_2phase) AT (0, 0, 0.02) RELATIVE pulse_shaping_chopper_1
|
|
24
|
+
COMPONENT frame_overlap_chopper_1 = DiskChopper(theta_0=110, radius=0.35, nu=frame_overlap_chopper_1speed, phase=frame_overlap_chopper_1phase) AT (0, 0, 12) RELATIVE pulse_shaping_chopper_2
|
|
25
|
+
COMPONENT frame_overlap_chopper_2 = DiskChopper(theta_0=115, radius=0.35, nu=frame_overlap_chopper_1speed, phase=frame_overlap_chopper_1phase) AT (0, 0, 4) RELATIVE frame_overlap_chopper_1
|
|
26
|
+
COMPONENT bandwidth_chopper_1 = DiskChopper(theta_0=110, radius=0.35, nu=bandwidth_chopper_1speed, phase=bandwidth_chopper_1phase) AT (0, 0, 80) RELATIVE frame_overlap_chopper_2
|
|
27
|
+
COMPONENT bandwidth_chopper_2 = DiskChopper(theta_0=115, radius=0.35, nu=bandwidth_chopper_2speed, phase=bandwidth_chopper_2phase) AT (0, 0, 0.02) RELATIVE bandwidth_chopper_1
|
|
28
|
+
COMPONENT sample = Arm() AT (0, 0, 80) RELATIVE bandwidth_chopper_2
|
|
18
29
|
END
|
|
19
30
|
"""
|
|
20
31
|
self.instr = parse_mcstas_instr(instr)
|
|
@@ -46,8 +57,8 @@ class BIFROSTEnergyTestCase(unittest.TestCase):
|
|
|
46
57
|
e = y * 0.5 + 1.7
|
|
47
58
|
self.assertAlmostEqual(x, e)
|
|
48
59
|
|
|
49
|
-
|
|
50
|
-
npts, names, points = parameters_to_scan(
|
|
60
|
+
scan_parameters = dict(order=order, time=time, ei=ei)
|
|
61
|
+
npts, names, points = parameters_to_scan(scan_parameters, grid=True)
|
|
51
62
|
self.assertEqual(npts, 47*11)
|
|
52
63
|
self.assertEqual(names, ['order', 'time', 'ei'])
|
|
53
64
|
all_points = list(points)
|
|
@@ -68,7 +79,7 @@ class BIFROSTEnergyTestCase(unittest.TestCase):
|
|
|
68
79
|
from restage.energy import energy_to_chopper_translator
|
|
69
80
|
from restage.energy import bifrost_translate_energy_to_chopper_parameters
|
|
70
81
|
from restage.range import MRange, Singular, parameters_to_scan
|
|
71
|
-
|
|
82
|
+
|
|
72
83
|
|
|
73
84
|
translator = energy_to_chopper_translator(self.instr.name)
|
|
74
85
|
self.assertEqual(translator, bifrost_translate_energy_to_chopper_parameters)
|
|
@@ -76,36 +87,33 @@ class BIFROSTEnergyTestCase(unittest.TestCase):
|
|
|
76
87
|
order = Singular(14, 1)
|
|
77
88
|
time = MRange(0.0001, 0.002248, 0.0002)
|
|
78
89
|
ei = MRange(1.7, 24.7, 0.5)
|
|
79
|
-
|
|
90
|
+
scan_parameters = dict(order=order, time=time, ei=ei)
|
|
80
91
|
|
|
81
|
-
spts, names, points = parameters_to_scan(
|
|
92
|
+
spts, names, points = parameters_to_scan(scan_parameters, grid=True)
|
|
82
93
|
|
|
83
94
|
self.assertEqual(47*11, spts)
|
|
84
95
|
self.assertEqual(names, ['order', 'time', 'ei'])
|
|
85
96
|
|
|
86
|
-
|
|
87
|
-
|
|
97
|
+
chopper_parameters = parameters(CHOPPERS)
|
|
88
98
|
for point in points:
|
|
89
99
|
kv = {k: v for k, v in zip(names, point)}
|
|
90
100
|
translated = translator(kv)
|
|
91
|
-
for x in
|
|
92
|
-
self.assertTrue(
|
|
101
|
+
for x in chopper_parameters:
|
|
102
|
+
self.assertTrue(x in translated)
|
|
93
103
|
|
|
94
|
-
self.assertEqual(len(translated), len(
|
|
95
|
-
self.assertAlmostEqual(translated['
|
|
96
|
-
self.assertAlmostEqual(translated['
|
|
97
|
-
self.assertAlmostEqual(translated['
|
|
98
|
-
self.assertAlmostEqual(translated['
|
|
99
|
-
self.assertAlmostEqual(translated['
|
|
100
|
-
self.assertAlmostEqual(translated['
|
|
104
|
+
self.assertEqual(len(translated), len(chopper_parameters))
|
|
105
|
+
self.assertAlmostEqual(translated['bandwidth_chopper_1speed'], 14.0)
|
|
106
|
+
self.assertAlmostEqual(translated['bandwidth_chopper_2speed'], -14.0)
|
|
107
|
+
self.assertAlmostEqual(translated['frame_overlap_chopper_1speed'], 14.0)
|
|
108
|
+
self.assertAlmostEqual(translated['frame_overlap_chopper_1speed'], 14.0)
|
|
109
|
+
self.assertAlmostEqual(translated['pulse_shaping_chopper_1speed'], 14*14.0)
|
|
110
|
+
self.assertAlmostEqual(translated['pulse_shaping_chopper_2speed'], 14*14.0)
|
|
101
111
|
|
|
102
112
|
def test_calculations(self):
|
|
103
113
|
from itertools import product
|
|
104
114
|
from chopcal import bifrost as mcstas_bifrost_calculation
|
|
105
115
|
from restage.energy import bifrost_translate_energy_to_chopper_parameters
|
|
106
116
|
|
|
107
|
-
pars = [x+y for x, y in product(('ps1', 'ps2', 'fo1', 'fo2', 'bw1', 'bw2'), ('speed', 'phase'))]
|
|
108
|
-
|
|
109
117
|
shortest_time = 0.0001 # this is approximately twice the opening time of the pulse shaping choppers at 15*14 Hz
|
|
110
118
|
# Normal operation Shortest full-height pulse Shorter pulses reduce height
|
|
111
119
|
# /-----\ /\
|
|
@@ -129,8 +137,8 @@ class BIFROSTEnergyTestCase(unittest.TestCase):
|
|
|
129
137
|
kv = {'order': order, 'time': time, 'ei': energy}
|
|
130
138
|
translated = bifrost_translate_energy_to_chopper_parameters(kv)
|
|
131
139
|
from_mcstas = mcstas_bifrost_calculation(energy, 0., time)
|
|
132
|
-
for x in
|
|
133
|
-
self.assertAlmostEqual(from_mcstas[
|
|
140
|
+
for o, x in zip(parameters(OLD_CHOPPERS), parameters(CHOPPERS)):
|
|
141
|
+
self.assertAlmostEqual(from_mcstas[o], translated[x])
|
|
134
142
|
|
|
135
143
|
|
|
136
144
|
if __name__ == '__main__':
|