Executing a sequence
The function run_sequence() is the entry point for running a sequence.
Initialization
When the sequence is being prepared, a DeviceCompiler is created for each instrument in use.
It is in charge of converting shot parameters into instrument-specific instructions.
To do so, it can use the DeviceConfiguration entered by the user.
The result of the compiler compile_initialization_parameters() method is used to instantiate an associated Device object.
This device object is in charge of managing the connection to the instrument.
Each device is then initialized by entering its context manager (i.e. its method __enter__() is called).
Run
The shot parameters are iterated over according to the sequence IterationConfiguration.
For each shot, its parameters are passed to the device compilers compile_shot_parameters() method.
The resulting instructions are then passed to the method run_shot() of the DeviceController object associated with the device.
The controller manages the device during the shot. Unlike the devices, controllers can interact with each other for synchronization or data exchange.
The controller first sends the instructions for the shot to the device and waits for all devices to be ready. The shot is then triggered and the controllers can react to data generated by the devices while waiting for the shot to finish.
Shutdown
If no error occurs either during shot compilation or execution, the sequence terminates successfully.
If an error occurs while compiling a shot, the currently running shot will finish properly, but no shot will be scheduled after it.
If an error occurs inside the run_shot() method of a controller, the shot is aborted in the middle of its execution.
It is unfortunately not possible to let the other devices go to the end of the shot, since there are not guarantee to be able to terminate if they are waiting for the device that crashed.
Because of this, the run_shot() method of the other controllers are cancelled as soon as possible.
In the end of the sequence, whether it is successful or not, each device is closed by exiting its context manager (i.e. its method __exit__() is called).