Skip to content

Commit 5f0ca19

Browse files
SoftwareDevice: Define deserialised functions in a namespace with __file__ set to the name
of the device, so that a lyse.Run will use this as the results group name. Requires lyse pull request #72
1 parent ea548c0 commit 5f0ca19

File tree

4 files changed

+47
-14
lines changed

4 files changed

+47
-14
lines changed

SoftwareDevice/blacs_workers.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,20 @@
2626
GREEN = '#A6E22E'
2727
GREY = '#75715E'
2828

29-
def deserialise_function_table(function_table):
29+
def deserialise_function_table(function_table, device_name):
3030
table = []
3131
for t, name, source, args, kwargs in function_table:
3232
if t == -np.inf:
3333
t = 'start'
3434
elif t == np.inf:
3535
t = 'stop'
36-
function, args, kwargs = deserialise_function(name, source, args, kwargs)
36+
# We deserialise the functions in a namespace with the given __name__ and
37+
# __file__ so that if the user instantiates a lyse.Run object, that the results
38+
# will automatically be saved to a results group with the name of this
39+
# SoftwareDevice, since lyse.Run inspects the filename to determine this.
40+
function, args, kwargs = deserialise_function(
41+
name, source, args, kwargs, __name__=device_name, __file__=device_name
42+
)
3743
table.append((t, name, function, args, kwargs))
3844
return table
3945

@@ -59,7 +65,9 @@ def transition_to_buffered(self, device_name, h5_file, initial_values, fresh):
5965
return {}
6066
function_table = group['FUNCTION_TABLE'][:]
6167

62-
self.function_table = deserialise_function_table(function_table)
68+
self.function_table = deserialise_function_table(
69+
function_table, self.device_name
70+
)
6371
self.shot_context = ShotContext(h5_file, self.device_name)
6472
if self.function_table[0][0] != 'start':
6573
rich_print("no start functions", color=GREY)
@@ -70,7 +78,7 @@ def transition_to_buffered(self, device_name, h5_file, initial_values, fresh):
7078
if t != 'start':
7179
break
7280
del self.function_table[0]
73-
rich_print(f" t={t}: {name}()",color=BLUE)
81+
rich_print(f" t={t}: {name}()", color=BLUE)
7482
function(self.shot_context, t, *args, **kwargs)
7583
rich_print("[finished start functions]", color=PURPLE)
7684
return {}
@@ -96,3 +104,6 @@ def shutdown(self):
96104

97105
def abort_buffered(self):
98106
return self.transition_to_manual()
107+
108+
def abort_transition_to_buffered(self):
109+
return True

SoftwareDevice/labscript_devices.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,13 @@ def add_function(self, t, function, *args, **kwargs):
2121
instantiating this device to control the relative order that its 'start' and
2222
'stop' functions run compared to the transition_to_manual and
2323
transition_to_buffered functions of other devices. Multiple functions added to
24-
run at the same time will be run in the order added.
24+
run at the same time will be run in the order added. Running functions mid-shot
25+
in software time is yet to be implemented.
2526
2627
The function must have a call signature like the following:
2728
28-
def func(shot_context, t, ...):
29-
...
29+
def func(shot_context, t, ...):
30+
...
3031
3132
When it is called, a ShotContext instance will be passed in as the first
3233
argument, and the time at which the function was requested to run as the second
@@ -45,12 +46,25 @@ def func(shot_context, t, ...):
4546
- self.h5_file: the filepath to the shot's HDF5 file
4647
- self.device_name: the name of this SoftwareDevice
4748
48-
If you want to save data to the HDF5 file at the end of a shot, the recommended
49-
place to do it is within the group 'data/<device_name>', for example:
49+
If you want to save raw data to the HDF5 file at the end of a shot, the
50+
recommended place to do it is within the group 'data/<device_name>', for
51+
example:
5052
51-
with h5py.File(self.h5_file) as f:
52-
data_group = f['data'].create_group(self.device_name)
53-
# save datasets/attributes within this group
53+
with h5py.File(self.h5_file) as f:
54+
data_group = f['data'].create_group(self.device_name)
55+
# save datasets/attributes within this group
56+
57+
Or, if you are doing analysis and want to save results that will be accessible
58+
to lyse analysis routines in the usual way, you can instantiate a lyse.Run
59+
object and call Run.save_result() etc:
60+
61+
import lyse
62+
run = lyse.Run(shot_context.h5_file)
63+
run.save_result('x', 7)
64+
65+
The group that the results will be saved to, which is usually the filename of
66+
the lyse analysis routine, will instead be the device name of the
67+
SoftwareDevice.
5468
5569
The use case for which this device was implemented was to update runmanager's
5670
globals immediately after a shot, based on measurement data, such that

SoftwareDevice/testing/test.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
def foo(shot_context, t, arg):
1212
print(f"hello, {arg}!")
13+
import lyse
14+
run = lyse.Run(shot_context.h5_file)
15+
run.save_result('x', 7)
1316

1417

1518
software_device.add_function('start', foo, 'world')

SoftwareDevice/utils.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,15 @@ def serialise_function(function, *args, **kwargs):
4545
return function.__name__, source, args, kwargs
4646

4747

48-
def deserialise_function(name, source, args, kwargs):
48+
def deserialise_function(
49+
name, source, args, kwargs, __name__=None, __file__='<string>'
50+
):
51+
"""Deserialise a function that was serialised by serialise_function. Optional
52+
__name__ and __file__ arguments set those attributes in the namespace that the
53+
function will be defined."""
4954
args = deserialise(args)
5055
kwargs = deserialise(kwargs)
5156
code = compile(source, '<string>', 'exec', dont_inherit=True,)
52-
namespace = {'__name__': None, '__file__': '<string>'}
57+
namespace = {'__name__': __name__, '__file__': __file__}
5358
exec(code, namespace)
5459
return namespace[name], args, kwargs

0 commit comments

Comments
 (0)