qcodes_loop.loops¶
Data acquisition loops.
The general scheme is:
1. create a (potentially nested) Loop, which defines the sweep setpoints and delays
activate the loop (which changes it to an ActiveLoop object),
3. run it with the .run method, which creates a DataSet to hold the data, and defines how and where to save the data.
Some examples:
1D sweep, using the default measurement set
>>> Loop(sweep_values, delay).run()
2D sweep, using the default measurement set sv1 is the outer loop, sv2 is the inner.
>>> Loop(sv1, delay1).loop(sv2, delay2).run()
1D sweep with specific measurements to take at each point
>>> Loop(sv, delay).each(param4, param5).run()
Multidimensional sweep: 1D measurement of param6 on the outer loop, and another measurement in an inner loop.
>>> Loop(sv1, delay).each(param6, Loop(sv2, delay).each(sv3, delay)).run()
Supported commands to .each are:
Parameter: anything with a .get method and .name or .names see parameter.py for options
ActiveLoop
Task: any callable that does not generate data
Wait: a delay
- class qcodes_loop.loops.ActiveLoop(sweep_values, delay, *actions, then_actions=(), station=None, progress_interval=None, bg_task=None, bg_final_task=None, bg_min_delay=None)¶
Created by attaching
actions
to aLoop
, this is the object that actually runs a measurement loop. AnActiveLoop
can no longer be nested, only run, or used as an action inside anotherLoop
which will run the whole thing.The
ActiveLoop
determines whatDataArrays
it will need to hold the data it collects, and it creates aDataSet
holding theseDataArrays
- containers()¶
Finds the data arrays that will be created by the actions in this loop, and nests them inside this level of the loop.
Recursively calls .containers on any enclosed actions.
- get_data_set(*args, **kwargs)¶
Return the data set for this loop.
If no data set has been created yet, a new one will be created and returned. Note that all arguments can only be provided when the DataSet is first created; giving these during run when get_data_set has already been called on its own is an error.
- Parameters:
data_manager – a DataManager instance (omit to use default, False to store locally)
kwargs are passed along to data_set.new_data. The key ones are:
- Parameters:
location – the location of the DataSet, a string whose meaning depends on formatter and io, or False to only keep in memory. May be a callable to provide automatic locations. If omitted, will use the default DataSet.location_provider
name – if location is default or another provider function, name is a string to add to location to make it more readable/meaningful to users
formatter – knows how to read and write the file format default can be set in DataSet.default_formatter
io – knows how to connect to the storage (disk vs cloud etc)
write_period – how often to save to storage during the loop. default 5 sec, use None to write only at the end
- Returns:
a DataSet object that we can use to plot
- run(use_threads=False, quiet=False, station=None, progress_interval=False, set_active=True, *args, **kwargs)¶
Execute this loop.
- Parameters:
use_threads – (default False): whenever there are multiple get calls back-to-back, execute them in separate threads so they run in parallel (as long as they don’t block each other)
quiet – (default False): set True to not print anything except errors
station – a Station instance for snapshots (omit to use a previously provided Station, or the default Station)
progress_interval (int, float) – show progress of the loop every x seconds. If provided here, will override any interval provided with the Loop definition. Defaults to None
kwargs are passed along to data_set.new_data. These can only be provided when the DataSet is first created; giving these during run when get_data_set has already been called on its own is an error. The key ones are:
- Parameters:
location – the location of the DataSet, a string whose meaning depends on formatter and io, or False to only keep in memory. May be a callable to provide automatic locations. If omitted, will use the default DataSet.location_provider
name – if location is default or another provider function, name is a string to add to location to make it more readable/meaningful to users
formatter – knows how to read and write the file format default can be set in DataSet.default_formatter
io – knows how to connect to the storage (disk vs cloud etc) write_period: how often to save to storage during the loop. default 5 sec, use None to write only at the end
- Returns:
a DataSet object that we can use to plot
- run_temp(**kwargs)¶
wrapper to run this loop in the foreground as a temporary data set, especially for use in composite parameters that need to run a Loop as part of their get method
- set_common_attrs(data_set, use_threads)¶
set a couple of common attributes that the main and nested loops all need to have: - the DataSet collecting all our measurements - a queue for communicating with the main process
- snapshot_base(update=False, params_to_skip_update: Sequence[str] | None = None)¶
Snapshot of this ActiveLoop’s definition.
- then(*actions, overwrite=False)¶
Attach actions to be performed after the loop completes.
These can only be
Task
andWait
actions, as they may not generate any data.returns a new ActiveLoop object - the original is untouched
- Parameters:
*actions –
Task
andWait
objects to execute in orderoverwrite – (default False) whether subsequent .then() calls (including calls in an ActiveLoop after .then() has already been called on the Loop) will add to each other or overwrite the earlier ones.
- with_bg_task(task, bg_final_task=None, min_delay=0.01)¶
Attaches a background task to this loop.
- Parameters:
task – A callable object with no parameters. This object will be invoked periodically during the measurement loop.
bg_final_task – A callable object with no parameters. This object will be invoked to clean up after or otherwise finish the background task work.
min_delay (int, float) – The minimum number of seconds to wait between task invocations. Note that the actual time between task invocations may be much longer than this, as the task is only run between passes through the loop. Defaults to 0.01 s.
- class qcodes_loop.loops.Loop(sweep_values, delay=0, station=None, progress_interval=None)¶
The entry point for creating measurement loops
- Parameters:
sweep_values – a SweepValues or compatible object describing what parameter to set in the loop and over what values
delay – a number of seconds to wait after setting a value before continuing. 0 (default) means no waiting and no warnings. > 0 means to wait, potentially filling the delay time with monitoring, and give an error if you wait longer than expected.
progress_interval – should progress of the loop every x seconds. Default is None (no output)
After creating a Loop, you attach one or more
actions
to it, making anActiveLoop
actions
is a sequence of things to do at eachLoop
step: that can be aParameter
to measure, aTask
to do (any callable that does not yield data),Wait
times, or anotherActiveLoop
orLoop
to nest inside this one.- each(*actions)¶
Perform a set of actions at each setting of this loop. TODO(setting vs setpoints) ? better be verbose.
- Parameters:
*actions (Any) – actions to perform at each setting of the loop
Each action can be:
a Parameter to measure
a Task to execute
a Wait
another Loop or ActiveLoop
- loop(sweep_values, delay=0)¶
Nest another loop inside this one.
- Parameters:
sweep_values
delay (int)
Examples
>>> Loop(sv1, d1).loop(sv2, d2).each(*a)
is equivalent to:
>>> Loop(sv1, d1).each(Loop(sv2, d2).each(*a))
Returns: a new Loop object - the original is untouched
- snapshot_base(update: bool | None = False, params_to_skip_update: Sequence[str] | None = None)¶
State of the loop as a JSON-compatible dict (everything that the custom JSON encoder class :class:’.NumpyJSONEncoder’ supports).
- Parameters:
update – If True, update the state by querying the underlying sweep_values and actions. If None only update state if known to be invalid. If False, just use the latest values in memory.
params_to_skip_update – Unused in this implementation.
- Returns:
base snapshot
- Return type:
dict
- then(*actions, overwrite=False)¶
Attach actions to be performed after the loop completes.
These can only be
Task
andWait
actions, as they may not generate any data.returns a new Loop object - the original is untouched
This is more naturally done to an ActiveLoop (ie after .each()) and can also be done there, but it’s allowed at this stage too so that you can define final actions and share them among several
Loops
that have different loop actions, or attach final actions to a Loop run- Parameters:
*actions –
Task
andWait
objects to execute in orderoverwrite – (default False) whether subsequent .then() calls (including calls in an ActiveLoop after .then() has already been called on the Loop) will add to each other or overwrite the earlier ones.
- Returns:
a new Loop object - the original is untouched
- static validate_actions(*actions)¶
Whitelist acceptable actions, so we can give nice error messages if an action is not recognized
- with_bg_task(task, bg_final_task=None, min_delay=0.01)¶
Attaches a background task to this loop.
- Parameters:
task – A callable object with no parameters. This object will be invoked periodically during the measurement loop.
bg_final_task – A callable object with no parameters. This object will be invoked to clean up after or otherwise finish the background task work.
min_delay (int, float) – The minimum number of seconds to wait between task invocations. Defaults to 0.01 s. Note that if a task is doing a lot of processing it is recommended to increase min_delay. Note that the actual time between task invocations may be much longer than this, as the task is only run between passes through the loop.
- qcodes_loop.loops.tprint(string: str, dt: int = 1, tag: str = 'default') None ¶
Print progress of a loop every
dt
seconds.
- qcodes_loop.loops.wait_secs(finish_clock: float) float ¶
Calculate the number of seconds until a given clock time. The clock time should be the result of
time.perf_counter()
. Does NOT wait for this time.