Example #1
0
def Q(*args, **kwds):  # pylint: disable=E0102
    """A Q-E vector object that can be used for calculations.

    Use as follows:

    To create a Q vector (1, 0, 0) with energy transfer 0 or 5:

    >>> q = Q(1)
    >>> q = Q(1, 0, 0)
    >>> q = Q(1, 0, 0, 5)
    >>> q = Q(h=1, E=5)

    To create a Q vector from another Q vector, adjusting one or more entries:

    >>> q2 = Q(q, h=2, k=1)
    >>> q2 = Q(q, E=0)

    You can then use the Q-E vectors in scanning commands:

    >>> qscan(q, q2, 5, t=10)
    """
    q = _Q(4)
    q[:] = 0.
    if not args and not kwds:
        return q
    if len(args) == 1:
        try:
            nlen = len(args[0])
        except TypeError:
            q[0] = args[0]
        else:
            for i in range(nlen):
                q[i] = args[0][i]
    elif len(args) > 4:
        raise UsageError('1 to 4 Q/E components are allowed')
    else:
        for i in range(len(args)):
            q[i] = args[i]
    if 'h' in kwds:
        q[0] = kwds['h']
    elif 'H' in kwds:
        q[0] = kwds['H']
    if 'k' in kwds:
        q[1] = kwds['k']
    elif 'K' in kwds:
        q[1] = kwds['K']
    if 'l' in kwds:
        q[2] = kwds['l']
    if 'L' in kwds:
        q[2] = kwds['L']
    if 'E' in kwds:
        q[3] = kwds['E']
    elif 'e' in kwds:
        q[3] = kwds['e']
    return q
Example #2
0
def findpeaks(*columns, **kwds):
    """Find peaks the data of the last scan.

    Peaks are determined by the property that a data point is bigger than some
    neighbors (by default 2) on every side.  Then a parabola is fitted to these
    points, which gives a good approximation to the peak center position.

    The return value is a list of possible X values of peaks.

    The following keyword arguments are accepted:

    * *npoints* -- number of neighbors (default 2) per side of peak to be
      considered: if the scan is very fine, this must be increased
    """

    # parabola model
    def model(x, b, s, c):
        return b + s * (x - c)**2

    xs, ys, dys = _getData(columns)[:3]
    np = kwds.get('npoints', 2)
    peaks = []
    # peak has to be different from background
    minpeakheight = (ys.max() - ys.min()) * 0.1 + ys.min()
    for i in range(len(xs) - 2 * np):
        subys = ys[i:i + 2 * np + 1]
        subdys = dys[i:i + 2 * np + 1]
        # need a peak of at least minpeakheight
        if subys.max() < minpeakheight:
            continue
        # peak must be bigger than sides - including errors!
        miny = subys[np] - subdys[np]
        if (subys[0] + subdys[0] > miny) or \
           (subys[2*np] + subdys[2*np] > miny):
            continue
        # values must rise to peak and fall down
        for v in range(np):
            if subys[v] > subys[v + 1] or subys[v + np] < subys[v + np + 1]:
                break
        else:
            # we (probably) have a peak
            subxs = xs[i:i + 2 * np + 1]
            b = subys[np]
            s = (subys[0] - subys[np]) / (subxs[0] - subxs[np])**2
            c = subxs[np]
            fit = Fit('parabola', model, ['b', 's', 'c'], [b, s, c])
            res = fit.run(subxs, subys, subdys)
            if not res._failed:
                peaks.append(res._pars[1][2])

    return peaks
Example #3
0
 def doInit(self, mode):
     phases = [0, 0]
     self._dev = self._attached_io
     try:
         if mode == SIMULATION:
             raise NicosError('not possible in dry-run/simulation mode')
         wavelength = self._read(WAVE_LENGTH) / 1000.0
         if wavelength == 0.0:
             wavelength = 4.5
         self._setROParam('wavelength', wavelength)
         self._setROParam('speed', round(self._read(SPEED) / 1118.4735))
         self._setROParam('ratio', abs(self._read(RATIO)))
         slittype = self._read(SLIT_TYPE)
         if slittype == 2:  # XXX this looks strange
             self._setROParam('slittype', 1)
         else:
             self._setROParam('slittype', 0)
         crc = self._read(CRM)
         if crc == 1:
             self._setROParam('crc', 0)
         else:
             self._setROParam('crc', 1)
         for ch in range(2, 8):
             phases.append(
                 int(round(self._read(PHASE_SET + ch * 100) / 466.0378)))
         self._setROParam('phases', phases)
     except NicosError:
         self._setROParam('wavelength', 4.5)
         self._setROParam('speed', 0)
         self._setROParam('ratio', 1)
         self._setROParam('slittype', 0)
         self._setROParam('crc', 1)
         self._setROParam('phases', [0] * 8)
         self.log.warning('could not read initial data from PMAC chopper '
                          'controller', exc=1)
Example #4
0
 def stepHistoryUntil(self, prefix, direction):
     if direction == 'up':
         lookrange = range(self._current - 1, -1, -1)
     else:
         lookrange = range(self._current + 1, len(self.history))
     for i in lookrange:
         if self.history[i].startswith(prefix):
             self._current = i
             self.setText(self.history[i])
             self.setCursorPosition(len(prefix))
             return
     if direction == 'down':
         # nothing found: go back to start
         self._current = -1
         self.setText(self._start_text)
         self.setCursorPosition(len(prefix))
Example #5
0
def twodscan(dev1, start1, step1, numpoints1, dev2, start2, step2, numpoints2,
             *args, **kwargs):
    """Two-dimensional scan of two devices.

    This is a convenience function that runs a number of scans over *dev2*
    with *dev1* at a different position for each.

    Example:

    >>> twodscan(phi, 0, 1, 10, psi, 0, 2, 10, t=1)
    """
    for j in range(numpoints1):
        dev1value = start1 + j * step1
        try:
            dev1.maw(dev1value)
        except NicosError as err:
            if isinstance(err, CONTINUE_EXCEPTIONS):
                session.log.warning(
                    'Positioning problem of %s at %s, '
                    'scanning %s anyway',
                    dev1,
                    dev1.format(dev1value, unit=True),
                    dev2,
                    exc=1)
            elif isinstance(err, SKIP_EXCEPTIONS):
                session.log.warning('Skipping scan at %s = %s',
                                    dev1,
                                    dev1.format(dev1value, unit=True),
                                    exc=1)
                continue
            else:
                raise
        scan(dev2, start2, step2, numpoints2, dev1, *args, **kwargs)
Example #6
0
 def setCommand(self, command):
     if self.getCommand() == command:
         return
     self.moveCursor(QTextCursor.End)
     self.moveCursor(QTextCursor.StartOfLine, QTextCursor.KeepAnchor)
     for _ in range(len(self.ps1)):
         self.moveCursor(QTextCursor.Right, QTextCursor.KeepAnchor)
     self.textCursor().removeSelectedText()
     self.textCursor().insertText(command)
     self.moveCursor(QTextCursor.End)
Example #7
0
 def adjust(self, angle=0.0):
     while angle > 180.0:
         angle -= 360
     while angle < -180.0:
         angle += 360
     self._setROParam('phases', [0, -26, 1, 19, 13, 1, -13, 62])
     self._setROParam('speed', 0)
     for ch in range(1, 8):
         self._writevalues(ch, 0, self.speed, self.phases[ch] + angle)
     self._setROParam('changetime', currenttime())
Example #8
0
 def clearAlmostEverything(self):
     # Clears all messages, except the last input command with its output.
     # This is used for clearing output on NewExperiment, because the event
     # that clears the messages arrives *after* the command has run.
     msgs = self._messages[:]
     self.clear()
     i = 0
     for i in range(len(msgs) - 1, -1, -1):
         if msgs[i][2] == INPUT:
             break
     self.addMessages(msgs[i:])
Example #9
0
 def adjust(self, angle=0.0):
     while angle > 180.0:
         angle -= 360
     while angle < -180.0:
         angle += 360
     self._setROParam('phases', [0, -26, 1, 19, 13, 1, -13, 62])
     self._setROParam('speed', 0)
     for ch in range(1, 8):
         self._attached_discs[ch].move(self.speed)
         self._attached_discs[ch].phase = self._attached_discs[ch] + angle
     self._setROParam('changetime', currenttime())
Example #10
0
 def getLatest(self, n=5):
     # Return latest n commands together with warning/error output.
     inputcount = 0
     retmsgs = []
     for i in range(len(self._messages) - 1, -1, -1):
         if self._messages[i][2] == INPUT:
             retmsgs.append(self._messages[i])
             inputcount += 1
             if inputcount == n:
                 break
         elif self._messages[i][2] >= WARNING:
             retmsgs.append(self._messages[i])
     return retmsgs[::-1]
Example #11
0
 def _change(self, name, value):
     """Internal interface to change a chopper value."""
     if not self._is_cal():
         raise NicosError(self, 'chopper system not yet calibrated')
     if name == 'wavelength':
         self._setROParam('wavelength', round(value * 1000.0) / 1000.0)
     elif name == 'speed':
         assert 150 <= value <= 22000
         self._setROParam('speed', value)
     elif name == 'ratio':
         assert value in range(1, 11)
         self._setROParam('ratio', value)
     elif name == 'crc':
         assert value in [0, 1]
         self._setROParam('crc', value)
     elif name == 'slittype':
         assert value in [0, 1, 2]
         self._setROParam('slittype', value)
     # calculate new phases
     phases = [0]
     for ch in range(1, 8):
         phi = calc.phi(ch, self.speed, self.wavelength, self.crc,
                        self.slittype, self.ratio, self.ch5_90deg_offset)
         assert -180. <= phi <= 180.
         phases.append(int(round(100.0 * phi)))
     r1, r2 = (2, -1.0) if self.crc == 0 else (1, 1.0)
     rr = self.ratio + 1
     self._writevalues(1, 0, self.speed, phases[1],
                       int(round(self.wavelength * 1000.0)))
     self._writevalues(2, r1, r2 * self.speed, phases[2],
                       int(self.slittype + 1))
     self._writevalues(3, 1, self.speed, phases[3], int(self.crc + 1))
     self._writevalues(4, 1, self.speed, phases[4])
     self._writevalues(5, rr, -1 * self.speed, phases[5])
     self._writevalues(6, 1, self.speed, phases[6])
     self._writevalues(7, r1, r2 * self.speed, phases[7])
     self._setROParam('phases', phases)
     self._setROParam('changetime', currenttime())
Example #12
0
def qscan(Q, dQ, numpoints, *args, **kwargs):
    """Perform a single-sided Q scan.

    The *Q* and *dQ* arguments can be lists of 3 or 4 components, or a `Q`
    object.

    Example:

    >>> qscan((1, 0, 0, 0), (0, 0, 0, 0.1), 11, kf=1.55, mon1=100000)

    will perform an energy scan at (100) from 0 to 1 meV (or THz, depending on
    the instrument setting) with the given constant kf and the given monitor
    counts per point.

    The special "plot" parameter can be given to plot the scan instead of
    running it:

    * plot='res'  -- plot resolution ellipsoid along scan
    * plot='hkl'  -- plot position of scan points in scattering plane
    """
    Q, dQ = _getQ(Q, 'Q'), _getQ(dQ, 'dQ')
    scanstr = _infostr('qscan', (Q, dQ, numpoints) + args, kwargs)
    plotval = kwargs.pop('plot', None)
    preset, scaninfo, detlist, envlist, move, multistep, Q, dQ = \
        _handleQScanArgs(args, kwargs, Q, dQ, scanstr)
    if all(v == 0 for v in dQ) and numpoints > 1:
        raise UsageError('scanning with zero step width')
    values = [[(Q[0] + i * dQ[0], Q[1] + i * dQ[1], Q[2] + i * dQ[2],
                Q[3] + i * dQ[3])] for i in range(numpoints)]
    if plotval == 'res':
        resscan(*(p[0] for p in values),
                kf=kwargs.get('kf'),
                ki=kwargs.get('ki'))
    elif plotval == 'hkl':
        hklplot(scan=[p[0] for p in values],
                kf=kwargs.get('kf'),
                ki=kwargs.get('ki'))
    else:
        scan = QScan(values, move, multistep, detlist, envlist, preset,
                     scaninfo)
        scan.run()
Example #13
0
def qcscan(Q, dQ, numperside, *args, **kwargs):
    """Perform a centered Q scan.

    The *Q* and *dQ* arguments can be lists of 3 or 4 components, or a `Q`
    object.

    Example:

    >>> qcscan((1, 0, 0, 1), (0.001, 0, 0, 0), 20, mon1=1000)

    will perform a longitudinal scan around (100) with the given monitor counts
    per point.

    The special "plot" parameter can be given to plot the scan instead of
    running it:

    * plot='res'  -- plot resolution ellipsoid along scan
    * plot='hkl'  -- plot position of scan points in scattering plane
    """
    Q, dQ = _getQ(Q, 'Q'), _getQ(dQ, 'dQ')
    scanstr = _infostr('qcscan', (Q, dQ, numperside) + args, kwargs)
    plotval = kwargs.pop('plot', None)
    preset, scaninfo, detlist, envlist, move, multistep, Q, dQ = \
        _handleQScanArgs(args, kwargs, Q, dQ, scanstr)
    if all(v == 0 for v in dQ) and numperside > 0:
        raise UsageError('scanning with zero step width')
    values = [[(Q[0] + i * dQ[0], Q[1] + i * dQ[1], Q[2] + i * dQ[2],
                Q[3] + i * dQ[3])] for i in range(-numperside, numperside + 1)]
    if plotval == 'res':
        resscan(*(p[0] for p in values),
                kf=kwargs.get('kf'),
                ki=kwargs.get('ki'))
    elif plotval == 'hkl':
        hklplot(scan=[p[0] for p in values],
                kf=kwargs.get('kf'),
                ki=kwargs.get('ki'))
    else:
        scan = QScan(values, move, multistep, detlist, envlist, preset,
                     scaninfo)
        scan.run()
Example #14
0
 def mkpos(starts, steps, numpoints):
     return [[start + i * step for (start, step) in zip(starts, steps)]
             for i in range(numpoints)]
Example #15
0
 def setCursorPosition(self, position):
     self.moveCursor(QTextCursor.StartOfLine)
     for _ in range(len(self.ps1) + position):
         self.moveCursor(QTextCursor.Right)
Example #16
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)]
Example #17
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()
Example #18
0
 def doStatus(self, maxage=0):
     errstates = {  # 0: 'inactive',
                  1: 'cal',
                  2: 'com',
                  8: 'estop',
     }
     ret = []
     stval = status.OK
     # read status values
     for ch in range(1, 8):
         state = self._read(STATUS + ch)
         if state in errstates:
             stval = status.ERROR
             ret.append('ch %d: state is %s' % (ch, errstates[state]))
     # read speeds
     for ch in range(1, 8):
         if (self.crc == 0 and ch in [2, 7]) or ch == 5:
             r2 = -1.0
         else:
             r2 = 1.0
         speed = self._read(ACT_SPEED + ch) * r2
         rat = 1.0
         if ch == 5:
             if self.ratio > 1 and self.ratio <= 8:
                 rat = self.ratio / (self.ratio - 1.0)
             elif self.ratio > 8:
                 rat = self.ratio / 7.0
         nominal = self.speed / rat
         maxdelta = self.speed_accuracy / rat
         if abs(speed - nominal) > maxdelta:
             msg = 'ch %d: speed %.2f != nominal %.2f' % (ch, speed,
                                                          nominal)
             ret.append(msg)
             if self.isTimedOut():
                 stval = status.OK  # NOTREACHED
                 self.log.warning(msg)
             else:
                 stval = status.BUSY
     # read phases
     for ch in range(2, 8):
         phase = self._readphase(ch)
         phase_diff = abs(phase - self.phases[ch] / 100.)
         if phase_diff > self.phase_accuracy:
             if self.isTimedOut():
                 # Due to some problems with the electronics the phase of
                 # the chopper disc 5 may have a phase differs from real
                 # value in the range of 360 or 270 degrees
                 if ch == 5:
                     msg = 'cd 5 phase %.2f != %.2f' % (
                         phase, self.phases[ch] / 100.)
                     if phase_diff >= 360:
                         if phase_diff % 360 <= self.phase_accuracy:
                             self.log.warning(msg)
                             continue
                     elif phase_diff > 180:
                         if phase_diff >= (360. - self.phase_accuracy) or \
                            abs(phase_diff - 270) <= self.phase_accuracy:
                             self.log.warning(msg)
                             continue
                     stval = status.ERROR
                 else:
                     stval = status.ERROR
             else:
                 stval = status.BUSY
             msg = 'ch %d: phase %s != nominal %s' % (
                 ch, phase, self.phases[ch] / 100.)
             ret.append(msg)
             if self.isTimedOut():
                 stval = status.OK  # NOTREACHED
                 self.log.warning(msg)
             else:
                 stval = status.BUSY
     return stval, ', '.join(ret) or 'normal'
Example #19
0
 def _readspeeds_actual(self):
     return [abs(self._read(CURRENT_SPEED + ch * 100))
             for ch in range(1, 8)]
Example #20
0
 def _readspeeds(self):
     return [abs(self._read(ACT_SPEED + ch)) for ch in range(1, 8)]
Example #21
0
 def _stop(self):
     self._phases = [0] + [4500] * 7
     self._setROParam('speed', 0)
     for ch in range(1, 8):
         self._writevalues(ch, 0, self.speed, self._phases[ch])
     self._setROParam('changetime', currenttime())
Example #22
0
    def _change(self, name, value):
        """Internal interface to change a chopper value."""
        if name == 'wavelength':
            self._setROParam('wavelength', round(value * 1000.0) / 1000.0)
        elif name == 'speed':
            assert 150 <= value <= 22000
            self._setROParam('speed', value)
        elif name == 'ratio':
            assert value in range(1, 11)
            self._setROParam('ratio', value)
        elif name == 'crc':
            assert value in [0, 1]
            self._setROParam('crc', value)
        elif name == 'slittype':
            assert value in [0, 1, 2]
            self._setROParam('slittype', value)
        # calculate new phases
        phases = [0]
        for ch in range(1, 8):
            phi = calc.phi(ch, self.speed, self.wavelength, self.crc,
                           self.slittype, self.ratio, self.ch5_90deg_offset)
            assert -180. <= phi <= 180.
            phases.append(phi)
        r1, r2 = (2, -1.0) if self.crc == 0 else (1, 1.0)

        self._attached_discs[0].move(self.speed)
        self._attached_discs[0].phase = phases[1]

        self._attached_discs[1].move(r2 * self.speed)
        self._attached_discs[1].phase = phases[2]
        self._attached_discs[1].gear = r1
        self._attached_discs[1].slittype = self.slittype + 1

        self._attached_discs[2].move(self.speed)
        self._attached_discs[2].gear = 1
        self._attached_discs[2].phase = phases[3]
        self._attached_discs[2].crc = self.crc + 1

        self._attached_discs[3].move(self.speed)
        self._attached_discs[3].phase = phases[4]
        self._attached_discs[3].gear = 1

        # XXX if ratio == 1 then speed = 0 ?
        if self.ratio > 1:
            if self.ratio < 9:
                self._attached_discs[4].move(-self.speed * (self.ratio - 1) /
                                             self.ratio)
            else:
                self._attached_discs[4].move(-self.speed * 7. / self.ratio)
        else:
            self._attached_discs[4].move(-self.speed)
        self._attached_discs[4].phase = phases[5]
        self._attached_discs[4].gear = self.ratio + 1

        self._attached_discs[5].move(self.speed)
        self._attached_discs[5].phase = phases[6]
        self._attached_discs[5].gear = 1

        self._attached_discs[6].move(r2 * self.speed)
        self._attached_discs[6].phase = phases[7]
        self._attached_discs[6].gear = r1

        self._setROParam('phases', phases)
        self._setROParam('changetime', currenttime())
Example #23
0
 def _is_cal(self):
     for ch in range(1, 8):
         ret = self._read(STATUS + ch)
         if ret in [ST_INACTIVE, ST_CALIB1, ST_CALIB2, ST_IDLE, ST_ESTOP]:
             return False
     return True