Beispiel #1
0
 def beginScan(self):
     # since for every scan interval the underlying motor will be driven
     # to the starting point as described in `moveDevices` instead of the
     # originating motor it is necessary to replace the motor with the
     # underlying one in the dataset. Otherwise datasets will contain
     # ``None`` values because ``resdict`` in `PointDataset._reslist` will
     # contain just values for the underlying motor although values for
     # the originating/microstepping motor are requested.
     copydevices = list(self._devices)
     self._devices = underlying_motor(self._devices)
     Scan.beginScan(self)
     self._devices = copydevices
Beispiel #2
0
 def __init__(self,
              devices,
              startpositions,
              endpositions,
              speed=None,
              firstmoves=None,
              multistep=None,
              detlist=None,
              envlist=None,
              scaninfo=None,
              subscan=False):
     self._speed = speed if speed is not None else devices[0].speed
     preset = {'live': True}
     Scan.__init__(self, devices, startpositions, endpositions, firstmoves,
                   multistep, detlist, envlist, preset, scaninfo, subscan)
Beispiel #3
0
def cscan(dev, *args, **kwargs):
    """Scan around a center.

    This command is a specialisation of the `scan()` command to scan around a
    center a number of points left from the center and the same number right
    from the center with a certain step size.

    The command takes as parameters the center, a step size, and number of
    points on each side of the center:

    >>> cscan(dev, 0, 1, 5)   # scans around 0 from -5 to 5 in steps of 1.

    The total number of points is (2 * numperside) + 1.  The above commands
    counts at -5, -4, ..., 5.

    The equivalent `scan()` command would be:

    >>> scan(dev, -5, 1, 11)

    The device can also be a list of devices that should be moved for each
    step.  In this case, the center and step width also have to be lists:

    >>> cscan([dev1, dev2], [0, 0], [0.5, 1], 3)

    Resulting positions:

    ==== ==== ====
    Step dev1 dev2
    ==== ==== ====
    1    -1.5 -3.0
    2    -1.0 -2.0
    3    -0.5 -1.0
    4    0.0  0.0
    5    0.5  1.0
    6    1.0  2.0
    7    1.5  3.0
    ==== ==== ====
    """
    def mkpos(centers, steps, numperside):
        return [[
            center + (i - numperside) * step
            for (center, step) in zip(centers, steps)
        ] for i in range(2 * numperside + 1)]

    scanstr = _infostr('cscan', (dev, ) + args, kwargs)
    devs, values, restargs = _fixType(dev, args, mkpos)
    subscan = kwargs.pop(SUBSCAN, False)
    preset, scaninfo, detlist, envlist, move, multistep = \
        _handleScanArgs(restargs, kwargs, scanstr)
    Scan(devs,
         values,
         None,
         move,
         multistep,
         detlist,
         envlist,
         preset,
         scaninfo,
         subscan=subscan).run()
Beispiel #4
0
 def preparePoint(self, num, xvalues):
     if num > 0:  # skip starting point, because of range scan (0..1, ...)
         Scan.preparePoint(self, num, xvalues)
         # Open Shutters before movement of scan devices (e.g. motor).
         # Just for RScan because movement and counting should be done
         # simultaneous.
         where = []
         for det in self._detlist:
             if isinstance(det, BiodiffDetector):
                 det.prepare()
                 if det.ctrl_gammashutter:
                     where.append((det._attached_gammashutter, OPEN))
                 if det.ctrl_photoshutter:
                     where.append((det._attached_photoshutter, OPEN))
         if where:
             where = list(zip(*where))
             self.moveDevices(where[0], where[1])
Beispiel #5
0
 def doStart(self):
     positions = [[p] for p in self.positions]
     dataset = Scan([self._adevs['scandev']], positions, positions,
                    detlist=[self._adevs['detector']], preset=self._preset,
                    subscan=True).run()
     # process the values...
     yvalues = [subset.detvaluelist[0] for subset in dataset.subsets]
     self._last = [sum(yvalues) / float(len(yvalues)), dataset.filenames[0]]
Beispiel #6
0
 def doStart(self):
     positions = [[p] for p in self.positions]
     self.readresult = self._processDataset(
         Scan([self._attached_scandev],
              positions,
              None,
              detlist=[self._attached_detector],
              preset=self._preset,
              subscan=True).run())
Beispiel #7
0
 def __init__(self,
              positions,
              firstmoves=None,
              multistep=None,
              detlist=None,
              envlist=None,
              preset=None,
              scaninfo=None,
              subscan=False):
     inst = session.instrument
     if not isinstance(inst, SXTalBase):
         raise NicosError('cannot do a Q scan, your instrument device '
                          'is not a sxtal device')
     Scan.__init__(self, [inst], positions, [], firstmoves, multistep,
                   detlist, envlist, preset, scaninfo, subscan)
     self._envlist[0:0] = [
         inst._attached_gamma, inst._attached_omega, inst._attached_nu
     ]
     if inst in self._envlist:
         self._envlist.remove(inst)
Beispiel #8
0
def sscan(dev, *args, **kwargs):
    """Scan over device(s) and count detector(s).

    The general syntax is either to give start, step and end:

    >>> sscan(dev, 0, 1, 10)   # scans from 0 to 10 in steps of 1.

    or a list of positions to scan:

    >>> sscan(dev, [0, 1, 2, 3, 7, 8, 9, 10])  # scans at the given positions.

    For floating point arguments, the length of the result is
    ``int(round((end - start) / step + 1)``. Because of floating point
    overflow, this rule may result in the last element being greater than
    ``end``, e.g.

    >>> sscan(dev, 30, .1, 30.19)   # scans from 30 to 30.2 in steps of 0.1.

    """
    def mkpos(starts, steps, ends):
        def mk(starts, steps, numpoints):
            return [[start + i * step for (start, step) in zip(starts, steps)]
                    for i in range(numpoints)]

        # use round to handle floating point overflows
        numpoints = [
            int(round((end - start) / step + 1))
            for (start, step, end) in zip(starts, steps, ends)
        ]
        if all(n == numpoints[0] for n in numpoints):
            if numpoints[0] > 0:
                if numpoints[0] > 1:
                    return mk(starts, steps, numpoints[0])
                else:
                    raise UsageError("invalid number of points. At least two "
                                     "points are necessary to define a range "
                                     "scan. Please check parameters.")
            else:
                raise UsageError("negative number of points. Please check "
                                 "parameters. Maybe step parameter has wrong"
                                 "sign.")
        else:
            raise UsageError("all entries must generate the same number of "
                             "points")

    scanstr = _infostr("sscan", (dev, ) + args, kwargs)
    devs, values, restargs = _fixType(dev, args, mkpos)
    preset, scaninfo, detlist, envlist, move, multistep = \
        _handleScanArgs(restargs, kwargs, scanstr)
    Scan(devs, values, None, move, multistep, detlist, envlist, preset,
         scaninfo).run()
Beispiel #9
0
def amplscan(dev1, start1, step1, numpoints1, dev2, start2, step2, numpoints2,
             t):
    scandet = session.getDevice('scandet')
    scandet.scandev = str(dev2)
    scandet.positions = [start2 + i * step2 for i in range(numpoints2)]
    dev1pos = [[start1 + i * step1] for i in range(numpoints1)]
    ds = Scan([session.getDevice(dev1)],
              dev1pos,
              None,
              detlist=[scandet],
              preset={
                  't': t
              }).run()
    fit(CosineFit, 'A', dataset=ds)
Beispiel #10
0
def gridscan(dev, *args, **kwargs):
    """Scans over a grid of device positions and count detector(s).

    The orthogonal grid will spanned by the positions of each device.

    >>> gridscan([dev1, dev2], [-1, -2], [1, 1], [3, 5])

    which generates a measurement over a grid with positions:

    ==== ==== ====
    Step dev1 dev2
    ==== ==== ====
    1    -1.0 -2.0
    2     0.0 -2.0
    3     1.0 -2.0
    4    -1.0 -1.0
    5     0.0 -1.0
    6     1.0 -1.0
    7    -1.0  0.0
    8     0.0  0.0
    9     1.0  0.0
    10   -1.0  1.0
    11    0.0  1.0
    12    1.0  1.0
    13   -1.0  2.0
    14    0.0  2.0
    15    1.0  2.0
    ==== ==== ====
    """
    def mkpos(starts, steps, numpoints):
        if isinstance(numpoints, (list, tuple)):
            if len(starts) != len(numpoints):
                raise UsageError('start, steps, and numpoint arguments must '
                                 'have the same length')
            scanvals = [[
                start + j * step for j in range(numpoint)
            ] for start, step, numpoint in zip(starts, steps, numpoints)]
            values = meshgrid(*scanvals)
            for i, grid in enumerate(values):
                values[i] = list(grid.reshape(grid.size))
            return [tuple(v[i] for v in values) for i in range(len(values[0]))]
        raise UsageError('numpoints must be a list')

    scanstr = _infostr('gridscan', (dev, ) + args, kwargs)
    devs, values, restargs = _fixType(dev, args, mkpos)
    preset, scaninfo, detlist, envlist, move, multistep = \
        _handleScanArgs(restargs, kwargs, scanstr)
    Scan(devs, values, None, move, multistep, detlist, envlist, preset,
         scaninfo).run()
Beispiel #11
0
 def handleError(self, what, err):
     # consider all movement errors fatal
     if what in ('move', 'wait'):
         session.log.warning(
             'Positioning problem, stopping all moving '
             'motors and detectors',
             exc=1)
         try:
             for dev in self._devices:
                 if isinstance(dev, NicosMotor):
                     dev.stop()
             for det in self._detlist:
                 det.stop()
         finally:
             raise  # pylint: disable=misplaced-bare-raise
     return Scan.handleError(self, what, err)
Beispiel #12
0
 def moveDevices(self, devices, positions, wait=True):
     if wait:
         # stop running microstep sequence if wait is true because
         # in the following code the attached motor will be used which will
         # interference with the microstepping device.
         # (If there is a running sequence the microstepping device will be
         #  busy but the attached motor is just busy when it gets a move
         #  command from the sequence)
         # A general stop for microstepping motors avoids this interference.
         for dev in devices:
             if isinstance(dev, MicrostepMotor):
                 dev.stop()
                 waitForCompletion(dev, ignore_errors=True)
         # movement and counting separate
         # do not use software based micro stepping
         devices = underlying_motor(devices)
     return Scan.moveDevices(self, devices, positions, wait)
Beispiel #13
0
 def doStart(self):
     positions = [[p] for p in self.positions]
     ds = Scan([session.getDevice(self.scandev)],
               positions,
               None,
               detlist=[self._attached_detector],
               preset=self._preset,
               subscan=True).run()
     xs, ys, dys, _, ds = _getData()
     fit = self.fitcls()
     res = fit.run(xs, ys, dys)
     if res._failed:
         self.log.warning('Fit failed: %s.' % res._message)
         self.readresult = [0] * (self._nparams * 2)
     else:
         session.notifyFitCurve(ds, fit.fit_title, res.curve_x, res.curve_y)
         readres = []
         for par, err in zip(res._pars[1], res._pars[2]):
             readres.append(par)
             readres.append(err)
         self.readresult = readres
Beispiel #14
0
 def preparePoint(self, num, xvalues):
     if num > 1 and self._nsettings > 1 and (num -
                                             1) % self._nsettings == 0:
         for sink in self._sinks:
             sink.addBreak(self.dataset)
     Scan.preparePoint(self, num, xvalues)
Beispiel #15
0
 def finishPoint(self):
     self._data.finishPoint()
     Scan.finishPoint(self)
Beispiel #16
0
 def endScan(self):
     device = self._devices[0]
     device.speed = self._original_speed
     device.accel = self._original_accel
     device.decel = self._original_decel
     Scan.endScan(self)
Beispiel #17
0
def scan(dev, *args, **kwargs):
    """Scan over device(s) and count detector(s).

    A scan is used to collect data during the experiment depending on the
    position of one or more devices:

    - Move the devices to a new position, called a **point**, and wait until
      all devices have reached their position.
    - Start the detectors and wait until the requested time and/or monitor
      counts, called a **preset**, are reached.

    The output is a sequence of detector data corresponding to the device
    positions.

    The command has two basic modes:

    - Equidistant steps between the points

      A start value, the step size, and the number of points are given to the
      command:

      >>> scan(dev, 0, 1, 11)   # counts at positions from 0 to 10 in steps of 1

      For scans *around* a center, use the `cscan()` command.

    - A user defined list of points

      Here, the command expects a list of points:

      >>> scan(dev, [0, 1, 2, 3, 7, 8, 9])  # counts at the given positions

    Instead of one device, the command also handles a list of devices that
    should be moved for each step.  In this case, the start and step width
    also have to be lists:

    >>> scan([dev1, dev2], [0, 0], [0.5, 1], 4)

    The list of points will be:

    ==== ==== ====
    Step dev1 dev2
    ==== ==== ====
    1    0.0  0.0
    2    0.5  1.0
    3    1.0  2.0
    4    1.5  3.0
    ==== ==== ====

    This also works for the second operation mode:

    >>> scan([dev1, dev2], [[0, 1, 2, 3], [0, 1, 5, 7]])

    with positions:

    ==== ==== ====
    Step dev1 dev2
    ==== ==== ====
    1    0.0  0.0
    2    1.0  1.0
    3    2.0  5.0
    4    3.0  7.0
    ==== ==== ====

    """
    def mkpos(starts, steps, numpoints):
        return [[start + i * step for (start, step) in zip(starts, steps)]
                for i in range(numpoints)]

    scanstr = _infostr('scan', (dev, ) + args, kwargs)
    devs, values, restargs = _fixType(dev, args, mkpos)
    preset, scaninfo, detlist, envlist, move, multistep = \
        _handleScanArgs(restargs, kwargs, scanstr)
    Scan(devs, values, None, move, multistep, detlist, envlist, preset,
         scaninfo).run()
Beispiel #18
0
 def beginScan(self):
     if self._notherdevs == 0:
         self.dataset.xindex = 1  # plot against tau
     Scan.beginScan(self)
Beispiel #19
0
def appendscan(numpoints=5, stepsize=None):
    """Go on *numpoints* steps from the end of the last scan.

    *numpoints* can also be negative to prepend scan points.

    Examples:

    >>> appendscan(5)   # append 5 more points to last scan
    >>> appendscan(-5)  # append 5 more points to beginning of last scan

    If *stepsize* is given, the step size of the last scan will be overridden.

    Example:

    >>> scan(x, 10, 0.1, 10)  # original scan
    >>> appendscan(10, 0.5)  # continue the scan, but with other step size

    If the previous scan wasn't a scan with fixed step size and *stepsize* is
    not given, the new step size will be calculated as the averaged step size
    from the previous scan:

    >>> scan(x, [0, 0.1, 0.2, 0.5, 1])
    >>> appendscan(5)

    moves x to the following positions:

    ==== ====
    Step x
    ==== ====
    1/5  1.25
    2/5  1.50
    3/5  1.75
    4/5  2.00
    5/5  2.25
    ==== ====

    The scan data will be plotted into the same live plot, if possible, but
    will be saved into a separate data file.

    Scans with multiple devices are supported:

    >>> scan([x, y], [0, 1], [0.1, 0.2], 10)
    >>> appendscan(3, [0.05, 0.1])  # append 5 points with new stepsizes

    If the original scan was made over multiple devices, the *stepsize* must
    be a list with the same number of elements.
    """
    if numpoints == 0:
        raise UsageError('number of points must be either positive or '
                         'negative')
    direction = numpoints / abs(numpoints)
    dslist = session.experiment.data.getLastScans()
    if not dslist:
        raise NicosError('no last scan saved')
    contuids = []

    # Find the last scan that wasn't an appendscan.
    i = len(dslist) - 1
    while i >= 0:
        contuids.append(dslist[i].uid)
        if not dslist[i].continuation:
            break
        i -= 1

    # If the last scan was an appendscan in the same direction, append to it,
    # else append to the original scan.  This DWUMs for
    #   scan(...)
    #   appendscan(5)
    #   appendscan(2)
    #   appendscan(-3)
    if dslist[-1].cont_direction == direction:
        scan = dslist[-1]
        # to continue an appendscan in the negative direction, which has
        # the points reversed, we need to reverse the direction again
        if scan.cont_direction == -1:
            numpoints = -numpoints
    else:
        scan = dslist[i]

    n_devs = len(scan.devices)
    n_steps = len(scan.subsets)
    if n_steps < 2:
        raise NicosError('cannot append to scan with no positions')

    if stepsize is not None:
        if isinstance(stepsize, number_types):
            stepsize = [stepsize]
        if n_devs != len(stepsize):
            raise NicosError('the stepsize must have %d elements' % n_devs)
    else:
        stepsize = [None] * n_devs

    # create the new list of positions
    positions = [[None] * n_devs for _ in range(abs(numpoints))]

    # for each device involved in the scan
    for i in range(n_devs):
        # determine step size by first and last position
        pos1 = scan.startpositions[0][i]
        pos2 = scan.startpositions[n_steps - 1][i]

        if isinstance(pos1, (tuple, ndarray)):
            stepsizes = tuple(
                (b - a) / (n_steps - 1) for (a, b) in zip(pos1, pos2))
            if numpoints > 0:
                for j in range(1, numpoints + 1):
                    positions[j - 1][i] = tuple(
                        b + j * s for (b, s) in zip(pos2, stepsizes))
            else:
                for j in range(1, -numpoints + 1):
                    positions[j - 1][i] = tuple(
                        a - j * s for (a, s) in zip(pos1, stepsizes))

        elif isinstance(pos1, number_types):
            if stepsize[i] is None:
                stepsize[i] = (pos2 - pos1) / (n_steps - 1)
            if numpoints > 0:
                startpos = pos2 + stepsize[i]
            else:
                stepsize[i] = -stepsize[i]
                startpos = pos1 + stepsize[i]
            for j in range(abs(numpoints)):
                positions[j][i] = startpos + j * stepsize[i]

        else:
            # we can't produce new values for this device
            raise NicosError('cannot append to this scan; some devices '
                             'have nonnumeric values')

    numpoints = abs(numpoints)
    s = Scan(scan.devices, positions, [], None, None, scan.detectors,
             scan.environment, scan.preset,
             '%d more steps of last scan' % numpoints)
    s._xindex = scan.xindex
    s._continuation = contuids
    s._cont_direction = direction
    # envlist must be reset since Scan.__init__ messes with the ordering
    s._envlist[:] = scan.environment
    s.run()