moreniius 0.1.10__py3-none-any.whl → 0.2.1__py3-none-any.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.
- moreniius/additions.py +153 -21
- moreniius/mccode/comp.py +15 -11
- moreniius/mccode/instance.py +7 -5
- moreniius/mccode/instr.py +8 -0
- moreniius/mccode/mccode.py +5 -2
- moreniius/moreniius.py +1 -1
- moreniius/nexus_structure.py +1 -1
- moreniius/utils.py +19 -0
- {moreniius-0.1.10.dist-info → moreniius-0.2.1.dist-info}/METADATA +3 -3
- moreniius-0.2.1.dist-info/RECORD +18 -0
- {moreniius-0.1.10.dist-info → moreniius-0.2.1.dist-info}/WHEEL +1 -1
- moreniius-0.1.10.dist-info/RECORD +0 -18
- {moreniius-0.1.10.dist-info → moreniius-0.2.1.dist-info}/entry_points.txt +0 -0
- {moreniius-0.1.10.dist-info → moreniius-0.2.1.dist-info}/top_level.txt +0 -0
moreniius/additions.py
CHANGED
|
@@ -8,15 +8,71 @@ log.debug('Extending moreniius.mccode.NXInstance translators')
|
|
|
8
8
|
COMPONENT_TYPE_NAME_TO_NEXUS['ESS_butterfly'] = 'NXmoderator'
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
# BIFROST has 45 triplet detector modules. Each has its own position and orientation, and defines the positions
|
|
12
|
+
# and orientations of its cylindrical pixels in its own coordinate system.
|
|
13
|
+
# This module-level dictionary is used to dynamically populate their information, to be used when constructing the
|
|
14
|
+
# full detector during the readout-construction.
|
|
15
|
+
BIFROST_DETECTOR_MODULES = {}
|
|
16
|
+
|
|
17
|
+
BIFROST_DETECTOR_TOPIC = 'bifrost_detector'
|
|
18
|
+
|
|
19
|
+
|
|
11
20
|
def readout_translator(instance):
|
|
12
21
|
"""BIFROST specific Readout Master, should be deprecated in favour of ReadoutCAEN"""
|
|
13
|
-
from
|
|
22
|
+
from numpy import einsum, ndarray, array
|
|
23
|
+
from nexusformat.nexus import NXdetector, NXcylindrical_geometry
|
|
14
24
|
from .utils import ev44_event_data_group
|
|
15
|
-
stream = ev44_event_data_group(source='caen', topic=
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
25
|
+
stream = ev44_event_data_group(source='caen', topic=BIFROST_DETECTOR_TOPIC)
|
|
26
|
+
|
|
27
|
+
readout_pos, readout_rot = instance.obj.orientation.position_parts(), instance.obj.orientation.rotation_parts()
|
|
28
|
+
|
|
29
|
+
counts = [geometry.detector_number.size for _, _, geometry in BIFROST_DETECTOR_MODULES.values()]
|
|
30
|
+
total = sum(counts)
|
|
31
|
+
points = [geometry.vertices.shape[0] for _, _, geometry in BIFROST_DETECTOR_MODULES.values()]
|
|
32
|
+
total_points = sum(points)
|
|
33
|
+
all_cylinders = ndarray((total, 3), dtype='int32')
|
|
34
|
+
all_vertices = ndarray((total_points, 3), dtype='float32')
|
|
35
|
+
detector_number = ndarray((total,), dtype='int32')
|
|
36
|
+
|
|
37
|
+
offset = 0
|
|
38
|
+
|
|
39
|
+
for module_pos, module_rot, geometry in BIFROST_DETECTOR_MODULES.values():
|
|
40
|
+
# Find the vector and rotation matrix linking the two coordinate systems
|
|
41
|
+
#
|
|
42
|
+
# - The geometry is defined in the module coordinate system, where any point is p' = (x', y', z').
|
|
43
|
+
# - There is a rotation matrix rot1 that relates a vector in _a_ global coordinate system to the module
|
|
44
|
+
# Such that
|
|
45
|
+
# x' = rot1 x_global
|
|
46
|
+
# Or
|
|
47
|
+
# x_global = rot1.inv() x'
|
|
48
|
+
# - Similarly, there is a rotation matrix rot2 that relates a vector in the same global coordinate system to
|
|
49
|
+
# the readout's coordinate system.
|
|
50
|
+
# x = rot2 x_global
|
|
51
|
+
# - In this global coordinate system, the module position and readout positions have a vector connecting them
|
|
52
|
+
# v = p_module - p_readout
|
|
53
|
+
#
|
|
54
|
+
# - So, to express the geometry in the readout's coordinate system, we convert p' to the global coordinate
|
|
55
|
+
# system, add the difference vector between the two coordinate systems, then convert the result to the
|
|
56
|
+
# readout coordinate system:
|
|
57
|
+
# p = rot2 (v + rot1.inv() p')
|
|
58
|
+
#
|
|
59
|
+
v = instance.instr.expr2nx(tuple((module_pos - readout_pos).position())) # this is a mccode-antlr Vector
|
|
60
|
+
rot1 = array(instance.instr.expr2nx(tuple(module_rot.inverse().rotation()))).reshape((3, 3))
|
|
61
|
+
rot2 = array(instance.instr.expr2nx(tuple(readout_rot.rotation()))).reshape((3, 3))
|
|
62
|
+
#
|
|
63
|
+
vertices = einsum('ij,kj->ki', rot1, geometry.vertices)
|
|
64
|
+
vertices = vertices + v
|
|
65
|
+
vertices = einsum('ij,kj->ki', rot2, vertices)
|
|
66
|
+
#
|
|
67
|
+
cylinders = offset + geometry.cylinders
|
|
68
|
+
all_vertices[offset:(offset + vertices.shape[0])] = vertices
|
|
69
|
+
all_cylinders[geometry.detector_number - 1, :] = cylinders
|
|
70
|
+
detector_number[geometry.detector_number - 1] = geometry.detector_number
|
|
71
|
+
offset += vertices.shape[0]
|
|
72
|
+
|
|
73
|
+
geometry = NXcylindrical_geometry(vertices=all_vertices, cylinders=all_cylinders, detector_number=detector_number)
|
|
74
|
+
|
|
75
|
+
return NXdetector(data=stream, geometry=geometry)
|
|
20
76
|
|
|
21
77
|
|
|
22
78
|
def monochromator_rowland_translator(nxinstance):
|
|
@@ -122,22 +178,25 @@ def detector_tubes_offsets_and_one_cylinder(self):
|
|
|
122
178
|
|
|
123
179
|
halfi = (width - 2 * radius) / 2
|
|
124
180
|
di = np.linspace(-halfi, halfi, ni)
|
|
125
|
-
|
|
181
|
+
|
|
182
|
+
half_pixel = height / (nj + 1) / 2 # half the size of one pixel along the tube
|
|
183
|
+
dj = -np.linspace(-height / 2 + half_pixel, height / 2 - half_pixel, nj)
|
|
126
184
|
Dj, Di = np.meshgrid(dj, di)
|
|
127
185
|
|
|
128
186
|
arc, triplet = analyzer - 1, cassette - 1 # naming from ICD 01 v6 indexing of triplets
|
|
129
187
|
|
|
130
188
|
diameter = f'2 * {radius}' if isinstance(radius, str) else 2 * radius
|
|
131
189
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
pars['
|
|
190
|
+
detector_number = [[pixel_fun(nj, arc, triplet, tube, position) for position in range(nj)] for tube in range(ni)]
|
|
191
|
+
|
|
192
|
+
pars['detector_number'] = np.array(detector_number).astype('int32')
|
|
193
|
+
pars['data'] = ev44_event_data_group(bifrost_source_20230704(arc, triplet), BIFROST_DETECTOR_TOPIC)
|
|
135
194
|
pars['x_pixel_offset'] = NXfield(Di, units='m')
|
|
136
195
|
pars['y_pixel_offset'] = NXfield(Dj, units='m')
|
|
137
196
|
pars['x_pixel_size'] = NXfield(diameter, units='m')
|
|
138
197
|
pars['y_pixel_size'] = NXfield(height / nj, units='m')
|
|
139
198
|
pars['diameter'] = NXfield(diameter, units='m')
|
|
140
|
-
pars['type'] = f'{ni} He3 tubes in series' if self.nx_parameter('wires_in_series') else f'{ni} He3 tubes'
|
|
199
|
+
pars['type'] = f'{ni} He3 tubes in series' if self.nx_parameter('wires_in_series', True) else f'{ni} He3 tubes'
|
|
141
200
|
|
|
142
201
|
# use NXcylindrical_geometry to define the detectors, which requires:
|
|
143
202
|
# vertices - (i, 3) -- points relative to the detector position defining each cylinder in the detector
|
|
@@ -151,13 +210,65 @@ def detector_tubes_offsets_and_one_cylinder(self):
|
|
|
151
210
|
# detector_number: (k,) -- maps the cylinders in cylinder by index with a detector id
|
|
152
211
|
#
|
|
153
212
|
# We're allowed to specify a single cylinder then le the x/y/z_offset position that pixel repeatedly:
|
|
154
|
-
|
|
155
|
-
vertices = NXfield([[0, -dy, 0], [radius, -dy, 0], [0, dy, 0]], units='m')
|
|
213
|
+
vertices = NXfield([[0, -half_pixel, 0], [radius, -half_pixel, 0], [0, half_pixel, 0]], units='m')
|
|
156
214
|
cylinders = [[0, 1, 2]]
|
|
157
215
|
geometry = NXcylindrical_geometry(vertices=vertices, cylinders=cylinders)
|
|
158
216
|
|
|
159
217
|
return NXdetector(**pars, geometry=geometry)
|
|
160
218
|
|
|
219
|
+
#
|
|
220
|
+
# def detector_tubes_only_cylinder(self):
|
|
221
|
+
# """This results in only the first cylinder being plotted by Nexus constructor"""
|
|
222
|
+
# import numpy as np
|
|
223
|
+
# from nexusformat.nexus import NXdetector, NXfield, NXcylindrical_geometry
|
|
224
|
+
# from .utils import ev44_event_data_group
|
|
225
|
+
# # parameters for NXdetector, to be filled-in
|
|
226
|
+
# pars = {}
|
|
227
|
+
# pixel_fun, wre = bifrost_pixel_regex_20230911()
|
|
228
|
+
#
|
|
229
|
+
# if wre.match(str(self.obj.when)):
|
|
230
|
+
# m = wre.match(str(self.obj.when))
|
|
231
|
+
# cassette = int(m.group('cassette'))
|
|
232
|
+
# analyzer = int(m.group('analyzer'))
|
|
233
|
+
# else:
|
|
234
|
+
# cassette = 1
|
|
235
|
+
# analyzer = 1
|
|
236
|
+
# # cassette in (1, 9), analyzer in (1, 5):
|
|
237
|
+
#
|
|
238
|
+
# # i is the 'slow' direction, j is the 'fast' direction
|
|
239
|
+
# # --> i between tubes, j along tubes
|
|
240
|
+
# ni = self.nx_parameter('N') # corresponds to 'width' and McStas 'x' axis
|
|
241
|
+
# nj = self.nx_parameter('no') # corresponds to 'height' and McStas 'y' axis
|
|
242
|
+
# width, height, radius = [self.nx_parameter(n) for n in ('width', 'height', 'radius')]
|
|
243
|
+
# halfi = (width - 2 * radius) / 2
|
|
244
|
+
# di = np.linspace(-halfi, halfi, ni)
|
|
245
|
+
# dj = np.linspace(-height / 2, height / 2, nj+1)
|
|
246
|
+
#
|
|
247
|
+
# # use NXcylindrical_geometry to define the detectors, which requires:
|
|
248
|
+
# # vertices - (i, 3) -- points relative to the detector position defining each cylinder in the detector
|
|
249
|
+
# # cylinders - (j, 3) -- indexes of the vertices, to define a cylinder by its face-center, face-edge, and
|
|
250
|
+
# # opposite face center:
|
|
251
|
+
# # |---------------|---------------|
|
|
252
|
+
# # | | |
|
|
253
|
+
# # 0 + + 2 + 4
|
|
254
|
+
# # | | |
|
|
255
|
+
# # |---------------|---------------|
|
|
256
|
+
# # 1 3 5
|
|
257
|
+
# # detector_number: (k,) -- maps the cylinders in cylinder by index with a detector id
|
|
258
|
+
#
|
|
259
|
+
# arc, triplet = analyzer - 1, cassette - 1 # naming from ICD 01 v6 indexing of triplets
|
|
260
|
+
#
|
|
261
|
+
# vertices = NXfield([v for x in di for y in dj for v in [[x, y, 0], [x, y, radius]]], units='m')
|
|
262
|
+
# cylinders = [[k, k+1, k+2] for k in [tube * 2 * (nj + 1) + 2 * j for tube in range(ni) for j in range(nj)]]
|
|
263
|
+
# detector_number = [pixel_fun(nj, arc, triplet, tube, j) for tube in range(ni) for j in range(nj)]
|
|
264
|
+
#
|
|
265
|
+
# pars['data'] = ev44_event_data_group(bifrost_source_20230704(arc, triplet), BIFROST_DETECTOR_TOPIC)
|
|
266
|
+
# pars['type'] = f'{ni} He3 tubes in series' if self.nx_parameter('wires_in_series') else f'{ni} He3 tubes'
|
|
267
|
+
#
|
|
268
|
+
# geometry = NXcylindrical_geometry(vertices=vertices, cylinders=cylinders, detector_number=detector_number)
|
|
269
|
+
#
|
|
270
|
+
# return NXdetector(**pars, geometry=geometry)
|
|
271
|
+
|
|
161
272
|
|
|
162
273
|
def detector_tubes_only_cylinder(self):
|
|
163
274
|
"""This results in only the first cylinder being plotted by Nexus constructor"""
|
|
@@ -183,8 +294,9 @@ def detector_tubes_only_cylinder(self):
|
|
|
183
294
|
nj = self.nx_parameter('no') # corresponds to 'height' and McStas 'y' axis
|
|
184
295
|
width, height, radius = [self.nx_parameter(n) for n in ('width', 'height', 'radius')]
|
|
185
296
|
halfi = (width - 2 * radius) / 2
|
|
297
|
+
# signs of di and dj verified by examining plots of detector positions
|
|
186
298
|
di = np.linspace(-halfi, halfi, ni)
|
|
187
|
-
dj = np.linspace(-height / 2, height / 2, nj+1)
|
|
299
|
+
dj = -np.linspace(-height / 2, height / 2, nj+1)
|
|
188
300
|
|
|
189
301
|
# use NXcylindrical_geometry to define the detectors, which requires:
|
|
190
302
|
# vertices - (i, 3) -- points relative to the detector position defining each cylinder in the detector
|
|
@@ -201,17 +313,36 @@ def detector_tubes_only_cylinder(self):
|
|
|
201
313
|
arc, triplet = analyzer - 1, cassette - 1 # naming from ICD 01 v6 indexing of triplets
|
|
202
314
|
|
|
203
315
|
vertices = NXfield([v for x in di for y in dj for v in [[x, y, 0], [x, y, radius]]], units='m')
|
|
204
|
-
cylinders = [[k, k+1, k+2] for k in [tube * 2 * (nj + 1) + 2 * j for tube in range(ni) for j in range(nj)]]
|
|
205
|
-
detector_number = [pixel_fun(nj, arc, triplet, tube, j) for tube in range(ni) for j in range(nj)]
|
|
316
|
+
cylinders = np.array([[k, k+1, k+2] for k in [tube * 2 * (nj + 1) + 2 * j for tube in range(ni) for j in range(nj)]]).astype('int32')
|
|
317
|
+
detector_number = np.array([pixel_fun(nj, arc, triplet, tube, j) for tube in range(ni) for j in range(nj)]).astype('int32')
|
|
206
318
|
|
|
207
|
-
pars['data'] = ev44_event_data_group(bifrost_source_20230704(arc, triplet),
|
|
208
|
-
pars['type'] = f'{ni} He3 tubes in series' if self.nx_parameter('wires_in_series') else f'{ni} He3 tubes'
|
|
319
|
+
pars['data'] = ev44_event_data_group(bifrost_source_20230704(arc, triplet), BIFROST_DETECTOR_TOPIC)
|
|
320
|
+
pars['type'] = f'{ni} He3 tubes in series' if self.nx_parameter('wires_in_series', True) else f'{ni} He3 tubes'
|
|
209
321
|
|
|
210
322
|
geometry = NXcylindrical_geometry(vertices=vertices, cylinders=cylinders, detector_number=detector_number)
|
|
211
323
|
|
|
324
|
+
for md in self.obj.metadata:
|
|
325
|
+
if md.mimetype == 'application/json' and md.name == 'nexus_structure_stream_data':
|
|
326
|
+
from nexusformat.nexus import NXdata
|
|
327
|
+
from moreniius.utils import NotNXdict
|
|
328
|
+
from json import loads
|
|
329
|
+
stream = loads(md.value)
|
|
330
|
+
name = stream.get('module', 'metadata')
|
|
331
|
+
pars[name] = NXdata(data=NotNXdict(stream))
|
|
332
|
+
|
|
212
333
|
return NXdetector(**pars, geometry=geometry)
|
|
213
334
|
|
|
214
335
|
|
|
336
|
+
def bifrost_detector_collector(self):
|
|
337
|
+
# nx_obj = detector_tubes_only_cylinder(self) # each pixel is a cylinder
|
|
338
|
+
nx_obj = detector_tubes_offsets_and_one_cylinder(self) # all pixels share one cylinder
|
|
339
|
+
# stash the object parts
|
|
340
|
+
pos, rot = self.obj.orientation.position_parts(), self.obj.orientation.rotation_parts()
|
|
341
|
+
BIFROST_DETECTOR_MODULES[str(self.obj.when)] = pos, rot, nx_obj.geometry
|
|
342
|
+
# and return it
|
|
343
|
+
return nx_obj
|
|
344
|
+
|
|
345
|
+
|
|
215
346
|
# def histogram_monitor(obj):
|
|
216
347
|
# from nexusformat.nexus import NXmonitor
|
|
217
348
|
# from .nxoff import NXoff
|
|
@@ -222,16 +353,17 @@ def detector_tubes_only_cylinder(self):
|
|
|
222
353
|
#
|
|
223
354
|
# # parameters to be filled-in
|
|
224
355
|
# pars = {}
|
|
225
|
-
# # pars['data'] = ev44_event_data_group(bifrost_source_20230704(arc, triplet),
|
|
356
|
+
# # pars['data'] = ev44_event_data_group(bifrost_source_20230704(arc, triplet), BIFROST_DETECTOR_TOPIC)
|
|
226
357
|
# # pars['type'] = f'{ni} He3 tubes in series' if self.nx_parameter('wires_in_series') else f'{ni} He3 tubes'
|
|
227
358
|
# pars['geometry'] = geometry.to_nexus()
|
|
228
359
|
# return NXmonitor(**pars)
|
|
229
360
|
|
|
230
361
|
|
|
231
362
|
# Patch-in the new methods
|
|
232
|
-
register_translator('Readout', readout_translator)
|
|
363
|
+
# register_translator('Readout', readout_translator)
|
|
233
364
|
register_translator('Monochromator_Rowland', monochromator_rowland_translator)
|
|
234
|
-
register_translator('Detector_tubes',
|
|
365
|
+
register_translator('Detector_tubes', bifrost_detector_collector)
|
|
366
|
+
register_translator('Detector_time_tubes', bifrost_detector_collector)
|
|
235
367
|
register_translator('Frame_monitor', monitor_translator)
|
|
236
368
|
|
|
237
369
|
log.debug('moreniius.mccode.NXInstance translators extended')
|
moreniius/mccode/comp.py
CHANGED
|
@@ -33,6 +33,7 @@ of the NXInstance class; then it can be used 'transparently' without needing to
|
|
|
33
33
|
"""
|
|
34
34
|
from zenlog import log
|
|
35
35
|
from mccode_antlr.common import Expr
|
|
36
|
+
from moreniius.utils import resolve_parameter_links
|
|
36
37
|
|
|
37
38
|
|
|
38
39
|
def slit_translator(nxinstance):
|
|
@@ -55,7 +56,8 @@ def slit_translator(nxinstance):
|
|
|
55
56
|
log.warn(f'{nxinstance.obj.name} has a non-constant x or y zero, which requires special handling for NeXus')
|
|
56
57
|
elif abs(x_zero) or abs(y_zero):
|
|
57
58
|
log.warn(f'{nxinstance.obj.name} should be translated by [{x_zero}, {y_zero}, 0] via eniius_data METADATA')
|
|
58
|
-
|
|
59
|
+
params = resolve_parameter_links(dict(x_gap=x_gap, y_gap=y_gap))
|
|
60
|
+
return nxinstance.make_nx(NXslit, **params)
|
|
59
61
|
|
|
60
62
|
|
|
61
63
|
def guide_translator(nxinstance):
|
|
@@ -64,18 +66,18 @@ def guide_translator(nxinstance):
|
|
|
64
66
|
off_pars = {k: nxinstance.nx_parameter(k) for k in ('l', 'w1', 'h1', 'w2', 'h2')}
|
|
65
67
|
for k in ('w', 'h'):
|
|
66
68
|
off_pars[f'{k}2'] = off_pars[f'{k}1'] if off_pars[f'{k}2'] == 0 else off_pars[f'{k}2']
|
|
67
|
-
|
|
69
|
+
guide_pars = {'m_value': nxinstance.parameter('m')}
|
|
68
70
|
geometry = NXoff.from_wedge(**off_pars).to_nexus()
|
|
69
|
-
return nxinstance.make_nx(NXguide,
|
|
71
|
+
return nxinstance.make_nx(NXguide, OFF_GEOMETRY=geometry, **resolve_parameter_links(guide_pars))
|
|
70
72
|
|
|
71
73
|
|
|
72
74
|
def collimator_linear_translator(nxinstance):
|
|
73
75
|
from nexusformat.nexus import NXcollimator
|
|
74
76
|
from moreniius.nxoff import NXoff
|
|
75
77
|
pars = {k: nxinstance.nx_parameter(v) for k, v in (('l', 'length'), ('w1', 'xwidth'), ('h1', 'yheight'))}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
78
|
+
col_pars = dict(divergence_x=nxinstance.parameter('divergence'), divergence_y=nxinstance.parameter('divergenceV'))
|
|
79
|
+
return nxinstance.make_nx(NXcollimator, OFF_GEOMETRY=NXoff.from_wedge(**pars).to_nexus(),
|
|
80
|
+
**resolve_parameter_links(col_pars))
|
|
79
81
|
|
|
80
82
|
|
|
81
83
|
def diskchopper_translator(nxinstance):
|
|
@@ -90,7 +92,7 @@ def diskchopper_translator(nxinstance):
|
|
|
90
92
|
nslit, delta = mpars['nslit'], mpars['theta_0'] / 2.0
|
|
91
93
|
slit_edges = [y * 360.0 / nslit + x for y in range(int(nslit)) for x in (-delta, delta)]
|
|
92
94
|
nx_slit_edges = [nxinstance.expr2nx(se) for se in slit_edges]
|
|
93
|
-
return nxinstance.make_nx(NXdisk_chopper, slit_edges=NXfield(nx_slit_edges, units='degrees'), **pars)
|
|
95
|
+
return nxinstance.make_nx(NXdisk_chopper, slit_edges=NXfield(nx_slit_edges, units='degrees'), **resolve_parameter_links(pars))
|
|
94
96
|
|
|
95
97
|
|
|
96
98
|
def elliptic_guide_gravity_translator(nxinstance):
|
|
@@ -116,6 +118,8 @@ def elliptic_guide_gravity_translator(nxinstance):
|
|
|
116
118
|
z = x * p['l']
|
|
117
119
|
vertices.extend([[-w, -h, z], [-w, h, z], [w, h, z], [w, -h, z]])
|
|
118
120
|
|
|
121
|
+
# These are only the guide faces (that is, the inner faces of the sides of the guide housing)
|
|
122
|
+
# The entry and exit are not guide faces and therefore are NOT represented here!
|
|
119
123
|
for i in range(n):
|
|
120
124
|
j0, j1, j2, j3, j4, j5, j6, j7 = [4 * i + k for k in range(8)]
|
|
121
125
|
faces.extend([[j0, j1, j5, j4], [j1, j2, j6, j5], [j2, j3, j7, j6], [j3, j0, j4, j7]])
|
|
@@ -123,22 +127,22 @@ def elliptic_guide_gravity_translator(nxinstance):
|
|
|
123
127
|
nx_vertices = [[nxinstance.expr2nx(expr) for expr in vector] for vector in vertices]
|
|
124
128
|
nx_faces = [[nxinstance.expr2nx(expr) for expr in face] for face in faces]
|
|
125
129
|
|
|
126
|
-
return NXguide(
|
|
130
|
+
return NXguide(OFF_GEOMETRY=NXoff(nx_vertices, nx_faces).to_nexus())
|
|
127
131
|
|
|
128
132
|
|
|
129
133
|
def monitor_translator(nxinstance):
|
|
130
|
-
from nexusformat.nexus import NXmonitor
|
|
134
|
+
from nexusformat.nexus import NXmonitor, NXdata
|
|
131
135
|
from moreniius.nxoff import NXoff
|
|
132
136
|
from moreniius.utils import NotNXdict
|
|
133
137
|
from json import loads
|
|
134
138
|
width = nxinstance.nx_parameter('xwidth')
|
|
135
139
|
height = nxinstance.nx_parameter('yheight')
|
|
136
140
|
geometry = NXoff.from_wedge(l=0.005, w1=width, h1=height)
|
|
137
|
-
nx_monitor = NXmonitor(
|
|
141
|
+
nx_monitor = NXmonitor(OFF_GEOMETRY=geometry.to_nexus())
|
|
138
142
|
if len(nxinstance.obj.metadata):
|
|
139
143
|
# look for mimetype 'application/json' and check if it is NeXus Structure data stream:
|
|
140
144
|
for md in nxinstance.obj.metadata:
|
|
141
145
|
if md.mimetype == 'application/json' and md.name == 'nexus_structure_stream_data':
|
|
142
|
-
nx_monitor['data'] = NotNXdict(loads(md.value))
|
|
146
|
+
nx_monitor['data'] = NXdata(data=NotNXdict(loads(md.value)))
|
|
143
147
|
|
|
144
148
|
return nx_monitor
|
moreniius/mccode/instance.py
CHANGED
|
@@ -69,8 +69,9 @@ class NXInstance:
|
|
|
69
69
|
transforms: dict[str, NXfield]
|
|
70
70
|
only_nx: bool
|
|
71
71
|
nx: Union[None, dict, NXfield] = None
|
|
72
|
+
dump_mcstas: bool = False
|
|
72
73
|
|
|
73
|
-
def parameter(self, name):
|
|
74
|
+
def parameter(self, name, default=None):
|
|
74
75
|
"""
|
|
75
76
|
Pull out a named instance parameter -- if it's value is not a constant, attempt to evaluate it
|
|
76
77
|
using the Instr declare and initialize sections
|
|
@@ -78,7 +79,7 @@ class NXInstance:
|
|
|
78
79
|
par = self.obj.get_parameter(name)
|
|
79
80
|
if par is None:
|
|
80
81
|
log.warn(f'It appears that {self.obj.type.name} does not define the parameter {name}')
|
|
81
|
-
return
|
|
82
|
+
return default
|
|
82
83
|
|
|
83
84
|
expr = par.value
|
|
84
85
|
# log.info(f'get parameter {name} which is {par} and expr {repr(expr)}')
|
|
@@ -99,9 +100,9 @@ class NXInstance:
|
|
|
99
100
|
def expr2nx(self, expr: Expr):
|
|
100
101
|
return self.instr.expr2nx(expr)
|
|
101
102
|
|
|
102
|
-
def nx_parameter(self, name):
|
|
103
|
+
def nx_parameter(self, name, default=None):
|
|
103
104
|
"""Retrieve the named instance parameter and convert to a NeXus compatible value"""
|
|
104
|
-
return self.expr2nx(self.parameter(name))
|
|
105
|
+
return self.expr2nx(self.parameter(name, default))
|
|
105
106
|
|
|
106
107
|
def make_nx(self, nx_class, *args, **kwargs):
|
|
107
108
|
return self.instr.make_nx(nx_class, *args, **kwargs)
|
|
@@ -111,7 +112,8 @@ class NXInstance:
|
|
|
111
112
|
from nexusformat.nexus import NXtransformations
|
|
112
113
|
from moreniius.utils import outer_transform_dependency, mccode_component_eniius_data
|
|
113
114
|
self.nx = getattr(self, self.obj.type.name, self.default_translation)()
|
|
114
|
-
|
|
115
|
+
if self.dump_mcstas:
|
|
116
|
+
self.nx['mcstas'] = dumps({'instance': str(self.obj), 'order': self.index})
|
|
115
117
|
if self.transforms:
|
|
116
118
|
self.nx['transformations'] = NXtransformations(**self.transforms)
|
|
117
119
|
most_dependent = outer_transform_dependency(self.nx['transformations'])
|
moreniius/mccode/instr.py
CHANGED
|
@@ -78,4 +78,12 @@ class NXInstr:
|
|
|
78
78
|
def make_nx(self, nx_class, *args, **kwargs):
|
|
79
79
|
nx_args = [self.expr2nx(expr) for expr in args]
|
|
80
80
|
nx_kwargs = {name: self.expr2nx(expr) for name, expr in kwargs.items()}
|
|
81
|
+
# logged parameters are sometimes requested as NXfield objects, but should be links to the real NXlog
|
|
82
|
+
if nx_class == NXfield and len(nx_args) == 1 and isinstance(nx_args[0], NXcollection) and \
|
|
83
|
+
'expression' in nx_args[0]:
|
|
84
|
+
not_expr = [x for x in nx_args[0] if x != 'expression']
|
|
85
|
+
if len(not_expr) == 1:
|
|
86
|
+
return nx_args[0][not_expr[0]]
|
|
87
|
+
else:
|
|
88
|
+
raise RuntimeError('Not sure what I should do here')
|
|
81
89
|
return nx_class(*nx_args, **nx_kwargs)
|
moreniius/mccode/mccode.py
CHANGED
|
@@ -57,7 +57,10 @@ class NXMcCode:
|
|
|
57
57
|
from nexusformat.nexus import NXinstrument
|
|
58
58
|
nx = NXinstrument() # this is a NeXus class
|
|
59
59
|
nx['mcstas'] = self.nx_instr.to_nx()
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
# hack the McCode component index into the name of the NeXus group
|
|
61
|
+
width = len(str(max(self.indexes.values())))
|
|
62
|
+
for name, index in self.indexes.items():
|
|
63
|
+
nx_name = f'{index:0{width}d}_{name}'
|
|
64
|
+
nx[nx_name] = self.component(name, only_nx=only_nx).nx
|
|
62
65
|
|
|
63
66
|
return nx
|
moreniius/moreniius.py
CHANGED
|
@@ -17,7 +17,7 @@ class MorEniius:
|
|
|
17
17
|
):
|
|
18
18
|
from nexusformat.nexus import NXfield
|
|
19
19
|
from .mccode import NXMcCode, NXInstr
|
|
20
|
-
nxlog_root = nxlog_root or ''
|
|
20
|
+
nxlog_root = nxlog_root or '/entry/parameters'
|
|
21
21
|
nx_mccode = NXMcCode(NXInstr(instr, nxlog_root=nxlog_root), origin_name=origin)
|
|
22
22
|
nxs_obj = nx_mccode.instrument(only_nx=only_nx)
|
|
23
23
|
nxs_obj['name'] = NXfield(value=instr.name)
|
moreniius/nexus_structure.py
CHANGED
|
@@ -34,7 +34,7 @@ def convert():
|
|
|
34
34
|
import argparse
|
|
35
35
|
parser = argparse.ArgumentParser(description='Convert an Instr (HDF5) or .instr (text) file to an equivalent NeXus Structure JSON string')
|
|
36
36
|
parser.add_argument('filename', type=str, help='the file to convert')
|
|
37
|
-
parser.add_argument('--format', type=str, default='json', help='the output format,
|
|
37
|
+
parser.add_argument('--format', type=str, default='json', help='the output format, currently only json')
|
|
38
38
|
args = parser.parse_args()
|
|
39
39
|
instr = load_instr(args.filename)
|
|
40
40
|
structure = to_nexus_structure(instr)
|
moreniius/utils.py
CHANGED
|
@@ -161,6 +161,9 @@ def link_specifier(name: str, source: str) -> NotNXdict:
|
|
|
161
161
|
source: str
|
|
162
162
|
the target of the link, the location in the eventual NeXus file where the source of data resides
|
|
163
163
|
|
|
164
|
+
Reference:
|
|
165
|
+
https://gitlab.esss.lu.se/ecdc/ess-dmsc/kafka-to-nexus/-/blob/main/documentation/commands.md?ref_type=heads#links
|
|
166
|
+
|
|
164
167
|
Examples:
|
|
165
168
|
To produce the link in the following NeXus JSON structure, one would use this function
|
|
166
169
|
{
|
|
@@ -189,3 +192,19 @@ def link_specifier(name: str, source: str) -> NotNXdict:
|
|
|
189
192
|
>>> link_specifier('detector0_event_data', '/entry/instrument/detector_panel_0/event_data')
|
|
190
193
|
"""
|
|
191
194
|
return ess_flatbuffer_specifier('link', {'name': name, 'source': source})
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def resolve_parameter_links(instance_parameters: dict):
|
|
198
|
+
"""Component instances have NeXus base class equivalents that require specifying any number of parameters.
|
|
199
|
+
Sometimes the McCode parameters are instrument-parameters, which may only be specified at runtime.
|
|
200
|
+
These component parameters are detectable and should already be replaced by NXfield objects holding NotNXdict
|
|
201
|
+
objects, in turn specifying the file-writer link module that points to their real NXlog dataset.
|
|
202
|
+
If the link is singular, it should have its name replaced by the NeXus class parameter so that NeXus programs
|
|
203
|
+
recognize it correctly.
|
|
204
|
+
"""
|
|
205
|
+
from nexusformat.nexus import NXfield
|
|
206
|
+
for name, par in instance_parameters.items():
|
|
207
|
+
if isinstance(par, NXfield) and isinstance(par.nxdata, NotNXdict) and 'link' == par.nxdata.value['module']:
|
|
208
|
+
par.nxdata.value['config']['name'] = name
|
|
209
|
+
|
|
210
|
+
return instance_parameters
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: moreniius
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Author-email: Gregory Tucker <gregory.tucker@ess.eu>
|
|
5
5
|
Classifier: License :: OSI Approved :: BSD License
|
|
6
6
|
Classifier: Development Status :: 2 - Pre-Alpha
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
Requires-Dist: zenlog ==1.1
|
|
9
9
|
Requires-Dist: platformdirs ==3.11
|
|
10
|
-
Requires-Dist: mccode-antlr[hdf5] ==0.
|
|
11
|
-
Requires-Dist: nexusformat ==1.0.
|
|
10
|
+
Requires-Dist: mccode-antlr[hdf5] ==0.7.0
|
|
11
|
+
Requires-Dist: nexusformat ==1.0.6
|
|
12
12
|
Requires-Dist: importlib-metadata ; python_version < "3.8"
|
|
13
13
|
|
|
14
14
|
# moreniius
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
moreniius/__init__.py,sha256=33SUBkXWhH5rog5oaGJr1Kwqjhwz97w4E0Da7rArYi4,154
|
|
2
|
+
moreniius/additions.py,sha256=6Hhhc4LDUsnBj27Iil-EFFzQm1xd2M45hfcVQYEjxiI,17615
|
|
3
|
+
moreniius/moreniius.py,sha256=cU3CrfMC1kOnHO77yq5sZfDqRuA38G5kA3RUXFNGP2U,1455
|
|
4
|
+
moreniius/nexus_structure.py,sha256=i9CxYwJl4eKP9IIYR80MI3f54Yh0RPDFviZaulE5IOc,1709
|
|
5
|
+
moreniius/nxoff.py,sha256=WHp9wYNn_4Hcx8Nzi9rpX1p8_iwI-AdgTQouSAEG8N4,3288
|
|
6
|
+
moreniius/utils.py,sha256=3REIM3nJ3L0PVpIWqu0Kh-znK1ggNNYTCjXatoaAA34,8075
|
|
7
|
+
moreniius/writer.py,sha256=DOwzpDqoXiDXdtV-hRZVtF5lNBBoYy0UO5_bq89d1lc,6325
|
|
8
|
+
moreniius/mccode/__init__.py,sha256=1QiZdh90G3gp_WlVpdJB_ZGauoW0GJEQ13Nelaqa5JE,151
|
|
9
|
+
moreniius/mccode/comp.py,sha256=uR1L5nLfYPHhMKd3XnDbqf5xhkfwfPLRnttREc3jqBg,7382
|
|
10
|
+
moreniius/mccode/instance.py,sha256=4nqJ3ne6yXCEvsa3FIKUcGDYP_z7cAr46JhakDTB6qs,8055
|
|
11
|
+
moreniius/mccode/instr.py,sha256=3BdfYzZnHhCokFQIwp7XUEy9nt6CclqAWunHXfGW228,4363
|
|
12
|
+
moreniius/mccode/mccode.py,sha256=6NEXovuG-6itzlPgPklNOiZQ-MlldKF20p4TxV8n4BA,3228
|
|
13
|
+
moreniius/mccode/orientation.py,sha256=_jyTtabo3ZHujuXead0elZzcCck_v8UwX5tIMp4dXwI,3199
|
|
14
|
+
moreniius-0.2.1.dist-info/METADATA,sha256=IDriQtt4mIeEtG6mTYHH-i860X52N4IGuaO2Y04kGX0,625
|
|
15
|
+
moreniius-0.2.1.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
|
|
16
|
+
moreniius-0.2.1.dist-info/entry_points.txt,sha256=Ga3k4P4fyBt5_dJ03Oapic2Qlgqv9jufQGdxWiz_j2A,63
|
|
17
|
+
moreniius-0.2.1.dist-info/top_level.txt,sha256=RzMo23UfVhgQeuOYeS5P9I0qVbxx4Gbe6Roc29Mr02c,10
|
|
18
|
+
moreniius-0.2.1.dist-info/RECORD,,
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
moreniius/__init__.py,sha256=33SUBkXWhH5rog5oaGJr1Kwqjhwz97w4E0Da7rArYi4,154
|
|
2
|
-
moreniius/additions.py,sha256=maJXirPwtcETy5nE99dUVlngRZQdq7ynXOwb8MoOPvs,10507
|
|
3
|
-
moreniius/moreniius.py,sha256=tT5JGdhnR19tZ8VPnjNLjcJAQDoapGdfDHvARvAvNTE,1438
|
|
4
|
-
moreniius/nexus_structure.py,sha256=62QckSfg8m8PN0FMN5JNdOotunZzOmbj2rujIr0lUIo,1711
|
|
5
|
-
moreniius/nxoff.py,sha256=WHp9wYNn_4Hcx8Nzi9rpX1p8_iwI-AdgTQouSAEG8N4,3288
|
|
6
|
-
moreniius/utils.py,sha256=mI8SQ0JTqWKKC0RTmiD6z5O0R4t79riACVrMxjx9at0,7010
|
|
7
|
-
moreniius/writer.py,sha256=DOwzpDqoXiDXdtV-hRZVtF5lNBBoYy0UO5_bq89d1lc,6325
|
|
8
|
-
moreniius/mccode/__init__.py,sha256=1QiZdh90G3gp_WlVpdJB_ZGauoW0GJEQ13Nelaqa5JE,151
|
|
9
|
-
moreniius/mccode/comp.py,sha256=7lev6_5P83YHQP9uat5x75m1XuoIRulxUXAg_RG5094,6955
|
|
10
|
-
moreniius/mccode/instance.py,sha256=4jlVliEcGgG81SAJPffThXGKo-8wsbziq6jKbr0fjiQ,7952
|
|
11
|
-
moreniius/mccode/instr.py,sha256=wixWLvOWPOq4pcwVL9olo1-tteJaPkUDFR9GRZLTtrM,3872
|
|
12
|
-
moreniius/mccode/mccode.py,sha256=KQopQNiOi18bP_MQEYkAAd2AIhIFiVUx3gqVl0peWk8,3032
|
|
13
|
-
moreniius/mccode/orientation.py,sha256=_jyTtabo3ZHujuXead0elZzcCck_v8UwX5tIMp4dXwI,3199
|
|
14
|
-
moreniius-0.1.10.dist-info/METADATA,sha256=zjeEO883fEH9vALPsdC-9I6sJiRdEFJ6wFnW0tNnb1A,626
|
|
15
|
-
moreniius-0.1.10.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
16
|
-
moreniius-0.1.10.dist-info/entry_points.txt,sha256=Ga3k4P4fyBt5_dJ03Oapic2Qlgqv9jufQGdxWiz_j2A,63
|
|
17
|
-
moreniius-0.1.10.dist-info/top_level.txt,sha256=RzMo23UfVhgQeuOYeS5P9I0qVbxx4Gbe6Roc29Mr02c,10
|
|
18
|
-
moreniius-0.1.10.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|