qcodes_loop.loops

Data acquisition loops.

The general scheme is:

1. create a (potentially nested) Loop, which defines the sweep setpoints and delays

  1. 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 a Loop, this is the object that actually runs a measurement loop. An ActiveLoop can no longer be nested, only run, or used as an action inside another Loop which will run the whole thing.

The ActiveLoop determines what DataArrays it will need to hold the data it collects, and it creates a DataSet holding these DataArrays

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 and Wait actions, as they may not generate any data.

returns a new ActiveLoop object - the original is untouched

Parameters:
  • *actionsTask and Wait objects to execute in order

  • overwrite – (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 an ActiveLoop

actions is a sequence of things to do at each Loop step: that can be a Parameter to measure, a Task to do (any callable that does not yield data), Wait times, or another ActiveLoop or Loop 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 and Wait 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:
  • *actionsTask and Wait objects to execute in order

  • overwrite – (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.