Enrique,
Thanks for the great, detailed example! Sorry to keep inserting myself in the conversation, but you have piqued my interest. I'm always curious about clever ways to use labscript to do more complicated things than just straight procedural shots and you have certainly found an important use case!
What I might reiterate is that labscript already has a system for passing globals between components (namely runmanager globals). Now it is certainly limited relative to general python, as you've found, but I am pretty sure only minor modification of your script would allow for its use. That said, what I'm about to suggest is definitely not easier to write than what you have (at least up front), and that may be a compelling enough argument for adding some sort of decorator to the runmanager compiler that saves variables at the end of script compilation to the other runmanager globals. I'm just not all that sure how easy that is to do, particularly in a general and robust enough way necessary for the mainline. That done, let's give it a go.
The general principle is that any global you want to keep needs to be defined in runmanager, and then you write your script to modify itself to match those definitions (ideally) or at least the runmanager globals mirror that functionality.
Taking your example 1.
In Runmanager
# All the constants, obviously
measure_cav_freq = True
measure_cav_freq_start = 0 #in seconds
measure_cav_freq_duration = 1e-3
spin_loops = 3
loop_scan_types = ['up','down']
lnum = len(loop_scan_types)
loop_start = 1
loop_dt = 0.5
loop_scan_times = [0,0.2]
loop_scan_durations = np.full(len(loop_scan_types),1e-3)
scan_types = np.tile(loop_scan_types,spin_loops)
scan_times = np.array([loop_scan_times+(i*loop_dt) for i in range(spin_loops)]).flatten() + loop_start
scan_durations = np.tile(loop_scan_durations,spin_loops)
You now how arrays that give the scan types, start times, and durations. If you insist on putting them into a single dict, that's fine (but doesn't work in this example since the labels would overwrite each other anyway). Note that runmanager tries to auto-expand any sequence type into a set of shots. This can be manually disabled by clearing the "Expansion" column. The entire array will then be passed in for the variable. I'll note that this auto expansion can cause trouble since it is the default behavior when runmanager is first loaded. If you have a lot of arrays that get cross-producted together, you can end up in a situation where runmanager stalls trying to calculate how many shots it would take before it lets you clear out the expansions. Like I said, this is certainly not a perfect solution to your need. Modifying runmanager to not do expansions automatically is also possible, but maybe not any easier than implementing your desired solution.
In the script
def cavity_scan(t,duration,label)
sweep_light(t,duration)
pass
if measure_cav_freq:
cavity_scan(measure_cav_freq_start,measure_cav_freq_duration,'measure_cavity_frequency')
for i in range(spin_loops):
cavity_scan(scan_times[lnum*i],scan_durations[lnum*i],scan_types[lnum*i])
rotate_atoms(t+0.1)
cavity_scan(scan_times[lnum*i+1],scan_durations[lnum*i+1],scan_types[lnum*i+1])
t += loop_dt
In analysis
from lyse import *
seq = data(path)
for typ,start,dur in zip(scan_types,scan_times,scan_durations):
dat = extract_photon_numbes(hdf, start,dur)
save_result(photon_label=typ,dat)
if measure_cav_freq:
# do stuff
The other example is similar in construction. I don't claim this is the only, or even best, way to handle this using current runmanager. Again, I recognize this is not as simple to work with as your desired solution. It requires writing a lot of python one-liners, making sure runmanager doesn't die on loadup with so many lists, and front-loading a lot of the script structuring logic to runmanager itself. But it is something that works today and doesn't need any monkeying around under the hood.
Hopefully that helps,
-David
P.S. If you decide to do this, a couple further tips. First, don't hesitate to use different scripts for different tasks and switch between them instead of trying to code a master script that can do literally anything. Switching scripts is basically painless. Second, make sure to divide up your globals groups so they can be disabled when not in use. Even if there is some naming overlap, this helps cut down unexpected behavior and keeps the number of globals (and therefore list expansions to disable) to a minimum. When doing this, note that lyse can get a bit funny about shots with different globals. Lyse does well generally, but there are definitely edge cases that can be annoying. Avoid by clearing the lyse analysis dataframe of shots when making script/globals changes.