How to Iterate a Spec¶
A Spec is only the specification for a scan. To execute the scan we need the positions. We can do this in a few ways.
If you only need the positions¶
If you are conducting a step scan, you only need the central positions of each
scan point. You can get these by using the Spec.positions()
method to produce an
SpecPositions
iterator of scan positions:
>>> from scanspec.specs import Line
>>> spec = Line("x", 1, 2, 3)
>>> for d in spec.positions():
... print(d)
...
{'x': 1.0}
{'x': 1.5}
{'x': 2.0}
This is simple, but not particularly performant, as the numpy arrays of positions are unpacked point by point into position dictionaries
If you need to do a fly scan¶
If you are conducting a fly scan then you need the Path that the motor moves through. You can get that from the lower and upper bounds of each point. It is more efficient to consume this Path in numpy array chunks that can be processed into a trajectory:
>>> path = spec.path()
>>> len(path)
3
>>> chunk = path.consume()
>>> chunk.lower
{'x': array([0.75, 1.25, 1.75])}
>>> chunk.positions
{'x': array([1. , 1.5, 2. ])}
>>> chunk.upper
{'x': array([1.25, 1.75, 2.25])}
>>> len(path)
0
If upper[i] == lower[i+1]
then we say that two scan points are joined, and
will be blended together in a motion trajectory, otherwise the scanning system
should insert a gap where the motors move between segments
If you need to do multiple runs of the same scan¶
A Path
instance is a one-shot consumable view of the list of Dimension
instances created by Spec.create_dimensions()
. Once you have consumed it you
should create a new instance of it. For performance reasons, you can keep the
intermediate Dimensions and create as many Path
wrappers to them as you need.
You can also give a maximum size to Path.consume()
>>> from scanspec.core import Path
>>> dims = spec.create_dimensions()
>>> path = Path(dims)
>>> len(path)
3
>>> chunk = path.consume(2)
>>> len(chunk)
2
>>> len(path)
1
>>> chunk = path.consume(2)
>>> len(chunk)
1
>>> len(path)
0
You can also use this method to only run a subset of the scan:
>>> path = Path(dims, start=1, num=1)
>>> len(path)
1
>>> chunk = path.consume()
>>> len(chunk)
1
>>> len(path)
0