コード例 #1
0
def _scanFC(dev, center, step, numpoints, sname, *args, **kwargs):
    """
    The scan is performed around *center* with the given parameters.

    This supports all arguments and keyword arguments that `cscan()` supports,
    and additionally:

    * a keyword "fit", that specifies the fit function to use. Defaults to
      gaussian if not specified.

      Use `ListFitters()` to see possible values.

    * a keyword "ycol" that gives the Y column of the dataset to use for the
      fit.
    """
    ycol = kwargs.pop('ycol', -1)
    fitname = kwargs.pop('fit', 'gauss')
    fitclass = FitterRegistry.getFitterCls(fitname)
    if fitclass.center_index is None:
        raise UsageError('Fit class is not suitable for centering.')
    cscan(dev, center, step, numpoints, sname, *args, **kwargs)
    params, _ = fit(fitclass, ycol)
    newcenter = params[fitclass.center_index] if params is not None else None
    minvalue = center - step * numpoints
    maxvalue = center + step * numpoints
    return minvalue, newcenter, maxvalue
コード例 #2
0
ファイル: tas.py プロジェクト: ess-dmsc/nicos
def checkalign(hkl, step, numpoints, *args, **kwargs):
    """Readjust sample psi0 by scanning a peak.

    The psi0 is adjusted to the fitted center of a sample rocking scan around
    the (h, k, l) position.  After the scan, moves back to (h, k, l).

    An additional a keyword "ycol" gives the Y column of the dataset to use for
    the Gaussian fit (see the help for `gauss()` for the meaning of this
    parameter).

    Examples:

    >>> checkalign((1, 1, 0), 0.05, 20)
    >>> checkalign((1, 1, 0), 0.05, 20, ycol='ctr2')

    You can also give a keyword argument "accuracy", which defines how much
    the old and new value have to differ in order to make an adjustment.  It
    defaults to 1/10 of the fitted FWHM.
    """
    tas = session.instrument
    ycol = kwargs.pop('ycol', -1)
    accuracy = kwargs.pop('accuracy', None)
    target = tuple(hkl) + (0, )
    tas.maw(target)
    psi = tas._attached_psi
    center = tas._calpos(target + (None, None), printout=False)[3]
    cscan(psi, center, step, numpoints, 'align check', *args, **kwargs)
    params, _ = gauss(ycol)
    # do not allow moving outside of the scanned region
    minvalue = center - step * numpoints
    maxvalue = center + step * numpoints
    if params is None:
        session.log.warning('Gaussian fit failed, psi0 unchanged')
    elif not minvalue <= params[0] <= maxvalue:
        session.log.warning('Gaussian fit resulted in center outside scanning '
                            'area, offset unchanged')
    else:
        # NOTE: this is the other way around compared to checkoffset
        diff = center - params[0]
        session.log.info('center of Gaussian fit at %s',
                         psi.format(params[0], True))
        if accuracy is None:
            accuracy = min(params[2] * 0.05, 0.1)
        if abs(diff) < accuracy:
            session.log.info(
                'alignment ok within %.3f degrees, not '
                'changing psi0', accuracy)
        else:
            sample = tas._attached_cell
            session.log.warning('adjusting %s.psi0 by %s', sample,
                                psi.format(diff, True))
            sample.psi0 += diff
    tas.maw(target)
コード例 #3
0
def ScanOmega(hkl, preset=1., subscan=False):
    instr = session.instrument
    if not isinstance(instr, SXTalBase):
        raise NicosError('your instrument device is not a SXTAL device')
    width = instr.getScanWidthFor(hkl)
    sps = instr.scansteps
    sw = width / sps
    op = instr._attached_omega.read(0)
    cscan(instr._attached_omega,
          op,
          sw,
          sps // 2,
          instr,
          preset,
          subscan=subscan)
コード例 #4
0
def ScanT2T(hkl, preset=1., subscan=False):
    instr = session.instrument
    if not isinstance(instr, SXTalBase):
        raise NicosError('your instrument device is not a SXTAL device')
    width = instr.getScanWidthFor(hkl)
    sps = instr.scansteps
    sw = width / sps
    instr.maw(hkl)
    op = instr._attached_omega.read(0)
    tp = instr._attached_ttheta.read(0)
    cscan([instr._attached_omega, instr._attached_ttheta], [op, tp],
          [sw, 2 * sw],
          sps // 2,
          instr,
          preset,
          subscan=subscan)
コード例 #5
0
def test_powderfit_from_data(session):
    tasdev = session.getDevice('Tas')
    tasdev.scanconstant = 2.0
    sample = session.getDevice('Sample')
    phidev = session.getDevice('t_phi')
    tasdet = session.getDevice('vtasdet')
    sample.lattice = [12.38, 12.38, 12.38]
    sample.orient1 = [1, 0, 0]
    sample.orient2 = [0, 1, 1]
    peaks = [(4, 0, 0, 0), (2, 1, 1, 0), (0, 2, 2, 0)]
    for peak in peaks:
        tasdev.maw(peak)
        cscan(phidev, phidev(), 0.2, 10, 1, tasdet)
    # since datasets are not numbered (no sink), number 0 will catch all
    res = powderfit('YIG', scans=[0])
    assert -0.105 <= res[0] <= 0.105
    assert -0.105 <= res[1] <= 0.105
コード例 #6
0
def test_cscan(session):
    m = session.getDevice('motor')
    cscan(m, 0, 1, 2)
    dataman = session.experiment.data
    dataset = dataman.getLastScans()[-1]
    assert dataset.devvaluelists == [[-2.], [-1.], [0.], [1.], [2.]]
コード例 #7
0
def centerpeak(*args, **kwargs):
    """Center a peak with multiple scans over multiple devices.

    This does repeated scans of all devices to iteratively center a peak until
    the peak center does not shift anymore.  Starting position is the current
    position of all devices.

    Non-keyword arguments are devices to scan over. At least one is required.

    Supported keyword arguments are:

    * ``rounds`` - maximum number of rounds (a round is one scan per device).
      The default is 5.
    * ``steps`` - number of steps per side for each scan. The default is 15.
    * ``steps_devname`` - special number of steps per side for this device.
    * ``step`` - step size for each scan. The default is 0.1.
    * ``step_devname`` - special step size for this device.
    * ``convergence`` - maximum delta of peak center between two scans of a
      device, in units of the scan step size. The default is 0.5.
    * ``fit`` - fit function to use for determining peak center, see below.
    * ``cont`` - True/False whether to use continuous scans. Default is false.
    * all further keyword arguments (like ``t=1``) are used as detector
      presets.

    Examples::

       # default scan without special options, count 2 seconds
       >>> centerpeak(omega, gamma, 2)
       # scan with device-specific step size and number of steps
       >>> centerpeak(omega, gamma, step_omega=0.05, steps_omega=20, t=1)
       # allow a large number of rounds with very small convergence window
       # (1/5 of step size)
       >>> centerpeak(omega, gamma, rounds=10, convergence=0.2, t=1)
       # center using Gaussian peak fits
       >>> centerpeak(omega, gamma, fit='gauss', t=1)

    Fit functions:

    * ``'center_of_mass'``: default, works for any peak shape
    * ``'gauss'``: symmetric Gaussian
    """
    nrounds = 5
    devices = []
    defsteps = 15
    nsteps = {}
    defstepsize = 0.1
    stepsizes = {}
    preset = {}
    fit = 'center_of_mass'
    allowed_fit = {'center_of_mass', 'gauss'}
    continuous = False
    convergence = 0.5
    for devname in args:
        if isinstance(devname, number_types):
            preset['t'] = devname
        else:
            devices.append(session.getDevice(devname, Moveable))
    if not devices:
        raise UsageError('need at least one device to scan over')
    for kw, value in kwargs.items():
        if kw == 'rounds':
            nrounds = value
        elif kw == 'fit':
            if value not in allowed_fit:
                raise UsageError('fit function %s is not allowed' % value)
            fit = value
        elif kw == 'convergence':
            convergence = value
        elif kw == 'steps':
            defsteps = value
        elif kw == 'step':
            defstepsize = value
        elif kw == 'cont':
            continuous = bool(value)
        elif kw.startswith('step_'):
            dev = session.getDevice(kw[5:], Moveable)
            if dev not in devices:
                raise UsageError('device %s not in list of devices to scan' %
                                 dev)
            stepsizes[dev] = value
        elif kw.startswith('steps_'):
            dev = session.getDevice(kw[6:], Moveable)
            if dev not in devices:
                raise UsageError('device %s not in list of devices to scan' %
                                 dev)
            nsteps[dev] = value
        else:
            preset[kw] = value
    for dev in devices:
        if dev not in stepsizes:
            stepsizes[dev] = defstepsize
        if dev not in nsteps:
            nsteps[dev] = defsteps

    # main loop
    lastround = {dev: dev.read() for dev in devices}
    for i in range(nrounds):
        session.log.info('Round %d of %d', i + 1, nrounds)
        session.log.info('*' * 100)
        # results of last round
        thisround = {}
        for dev in devices:
            center = lastround[dev]
            if continuous:
                contscan(dev,
                         center - nsteps[dev] * stepsizes[dev],
                         center + nsteps[dev] * stepsizes[dev],
                         speed=stepsizes[dev] / preset.get('t', 1),
                         timedelta=preset.get('t', 1))
            else:
                cscan(dev, center, stepsizes[dev], nsteps[dev], *devices,
                      **preset)
            if session.mode == SIMULATION:
                thisround[dev] = center
            elif fit == 'center_of_mass':
                thisround[dev] = center_of_mass()
            elif fit == 'gauss':
                params, _ = gauss()
                minvalue = center - abs(stepsizes[dev] * nsteps[dev])
                maxvalue = center + abs(stepsizes[dev] * nsteps[dev])
                if params is None:
                    maw(dev, center)
                    session.log.error('no Gaussian fit found in this scan')
                    return
                fit_center, fit_ampl, _fit_fwhm, fit_bkgd = params
                if math.isnan(fit_center) or \
                   not (minvalue <= fit_center <= maxvalue) or \
                   fit_ampl < 0.5 * fit_bkgd:
                    maw(dev, center)
                    session.log.error('Gaussian peak too small, or center '
                                      'outside scanning area')
                    return
                thisround[dev] = fit_center
            maw(dev, thisround[dev])
        session.log.info('*' * 100)
        again = False
        for dev in devices:
            diff = abs(lastround[dev] - thisround[dev])
            session.log.info('%-10s center: %8.6g -> %8.6g (delta %8.6g)', dev,
                             lastround[dev], thisround[dev], diff)
            if session.mode == SIMULATION:
                again = i < 1
                if i == 1:
                    session.log.info('=> dry run: limiting to 2 rounds')
            elif diff > convergence * stepsizes[dev]:
                if i == nrounds - 1:
                    session.log.info(
                        '=> would need another round, but command'
                        ' limited to %d rounds', nrounds)
                else:
                    session.log.info('=> needs another round')
                again = True
        if not again:
            session.log.info('=> found convergence on peak:')
            for dev in devices:
                session.log.info('%-10s : %s', dev, dev.format(dev()))
            return
        lastround = thisround
コード例 #8
0
def ScanDataset(name, speed=None, timedelta=None, start=1, cont=True):
    """Do an omega-scan over all HKL reflections in a given CSV dataset.

    Takes a CSV file created by `GenDataset()` (maybe edited) and does an
    omega scan over all HKLs in the list.

    Use ``start=N`` to start at a different line than the first.

    Use ``cont=False`` to select step scans instead of continuous scans.

    Examples::

       # omega scan of  all peaks in "low_t" with default settings
       >>> ScanDataset('low_t')
       # same, but with speed 0.1 and timedelta 1 second
       >>> ScanDataset('low_t', 0.1, 1)
       # start at row 100
       >>> ScanDataset('low_t', start=100)
       # with stepwise scans
       >>> ScanDataset('low_t', 0.1, 1, cont=False)
    """
    instr = session.instrument
    root = session.experiment.samplepath
    fullpath = path.join(root, name + '.csv')
    session.log.info('Reading reflection list from %s.', fullpath)

    all_pos = []
    with open(fullpath, 'r', encoding='utf-8') as fp:
        reader = csv.reader(fp)
        for row in reader:
            if row[0] == 'h':
                continue
            h, k, l, _, _, _, width = row[:7]
            all_pos.append(([float(h), float(k),
                             float(l)], float(width.replace(',', '.'))))

    session.log.info('%d reflections read.', len(all_pos))

    if start != 1:
        if len(all_pos) < start:
            session.log.info('Nothing to do.')
            return
        else:
            session.log.info('Starting at reflection number %d.', start)
            all_pos = all_pos[start - 1:]

    Remark('Scan dataset %s (%d reflections)' % (name, len(all_pos)))

    skipped = 0
    for i, (hkl, width) in enumerate(all_pos, start=start):
        session.log.info('')
        info = (i, len(all_pos) + start - 1, hkl[0], hkl[1], hkl[2])
        text = '*** Scanning %d/%d: (%4.4g %4.4g %4.4g)' % info
        scope = 'HKL %d/%d: (%4.4g %4.4g %4.4g)' % info
        if skipped:
            text += ' [%d skipped]' % skipped
            scope += ' [%d skipped]' % skipped
        session.log.info(text)
        session.beginActionScope(scope)
        try:
            calc = dict(instr._extractPos(instr._calcPos(hkl)))
            om1 = calc['omega'] - width / 2.
            om2 = calc['omega'] + width / 2.
            # optimization to avoid unnecessary omega movement,
            # currently disabled due to backlash concerns
            #
            # cur_om = instr._attached_omega.read()
            # if abs(cur_om - om1) > abs(cur_om - om2):
            #     om1, om2 = om2, om1
            umin, umax = instr._attached_omega.userlimits
            if om1 < umin:
                om1 = umin
            if om1 > umax:
                om1 = umax
            try:
                maw(instr._attached_gamma, calc['gamma'], instr._attached_nu,
                    calc['nu'], instr._attached_omega, om1)
            except SKIP_EXCEPTIONS:
                session.log.warning('Skipping scan', exc=1)
                skipped += 1
                continue
            except CONTINUE_EXCEPTIONS:
                session.log.warning('Positioning problem, continuing', exc=1)
            if cont:
                contscan(instr._attached_omega, om1, om2, speed, timedelta,
                         '(%4.4g %4.4g %4.4g)' % info[2:])
            else:
                stepsize = speed * timedelta
                # steps per side, not including the central point
                nsteps = int(round(width / 2 / stepsize))
                cscan(instr._attached_omega,
                      calc['omega'],
                      stepsize,
                      nsteps,
                      t=timedelta)
        finally:
            session.endActionScope()