Writing new scan point generators¶
Let’s walk through the simplest generator, LineGenerator
, and see how
it is written.
###
# Copyright (c) 2016, 2017 Diamond Light Source Ltd.
We import the baseclass Generator
and the compatibility wrappers
around the Python range()
function and the numpy
module
# Charles Mita - initial API and implementation and/or initial documentation
#
###
Our new subclass includes a docstring giving a short explanation of what it does and registers itself as a subclass of Generator for deserialization purposes.
def __init__(self, axes, units, start, stop, size, alternate=False):
"""
Args:
axes (str/list(str)): The scannable axes E.g. "x" or ["x", "y"]
units (str/list(str)): The scannable units. E.g. "mm" or ["mm", "mm"]
start (float/list(float)): The first position to be generated.
e.g. 1.0 or [1.0, 2.0]
stop (float or list(float)): The final position to be generated.
e.g. 5.0 or [5.0, 10.0]
size (int): The number of points to generate. E.g. 5
alternate(bool): Specifier to reverse direction if
generator is nested
"""
self.axes = to_list(axes)
self.start = to_list(start)
self.stop = to_list(stop)
self.alternate = alternate
self.units = {d:u for (d, u) in zip(self.axes, to_list(units))}
if len(self.axes) != len(set(self.axes)):
raise ValueError("Axis names cannot be duplicated; given %s" %
axes)
if len(self.axes) != len(self.start) or \
len(self.axes) != len(self.stop):
raise ValueError(
"Dimensions of axes, start and stop do not match")
self.size = size
self.step = []
if self.size < 2:
self.step = [0]*len(self.start)
else:
for axis in range_(len(self.start)):
self.step.append(
(self.stop[axis] - self.start[axis])/(self.size - 1))
The initializer performs some basic validation on the parameters and stores them. The units get stored as a dictionary attribute of axis->unit:
def prepare_arrays(self, index_array):
arrays = {}
for axis, start, stop in zip(self.axes, self.start, self.stop):
d = stop - start
step = float(d)
# if self.size == 1 then single point case
if self.size > 1:
step /= (self.size - 1)
f = lambda t: (t * step) + start
arrays[axis] = f(index_array)
return arrays
This is used by CompoundGenerator to create the points for this generator. This method should create, for each axis the generator defines, an array of positions by transforming the input index array. The index array will be the numpy array [0, 1, 2, …, n-1, n] for normal positions, and [-0.5, 0.5, 1.5, …, n-0.5, n+0.5] when used to calculate boundary positions.
The arrays are returned as a dictionary of {axis_name : numpy float array}