def pole_figure(numrows, speed, timedelta, sampleinfo): """Run a typical pole figure measurement. The command runs 'numrows' continuous scans over the 'phis' device, which makes a full turn (360 deg) during the measurement. The changed parameter device is 'chis'. It divides the angle of 90 deg into 'numrows' steps, starting at the half of the stepsize. A 'numrows' of 6 will generate the 'chis' positions of 172.5, 157.5, 142.5, 127.5, 112.5, and 97.5 deg. Examples:: # create a pole figure measurement with 6 steps taking every 10 s a # picture >>> pole_figure(6, 0.25, 10, 'Alpha_Ti') """ chis = session.getDevice('chis') phis = session.getDevice('phis') dchi = round(90.0 / numrows, 2) / 2.0 # creating a list beginnig from 180 + dchi downsteps to 90 + dchi positions = numpy.arange(90 + dchi, 180, 2 * dchi)[::-1] maw(phis, 0) for i, chipos in enumerate(positions): move_dev(chis, round(chipos, 2), maxtries=2) sleep(5) start, end = (360., 0.) if i % 2 else (0., 360.) contscan(phis, start, end, speed, timedelta, '%s_Chis_%s' % (sampleinfo, str(chis.read()))) sleep(5) maw(phis, 0) sleep(5) maw(chis, 180) sleep(5)
def prepare(session, dataroot): """Prepare a dataset for StressSpec""" session.experiment.setDetectors(['adet']) # Create devices needed in data sinks for dev in ['xt', 'yt', 'zt', 'slits', 'slitm', 'slite', 'slitp', 'omgm']: session.getDevice(dev) # Adjust the monochromator to reasonable position and check it tthm = session.getDevice('tthm') tthm.maw(69) transm = session.getDevice('transm') wav = session.getDevice('wav') assert wav.plane == '' # pylint: disable=compare-to-empty-string transm.maw('Ge') wav.plane = '311' wav.maw(1.7) # Perform different scans phis = session.getDevice('phis') timescan(1, t=0.05) scan(phis, 0, 0.1, 1, t=0.05, info='phi scan on time') scan(phis, 0, 0.1, 1, mon1=50, info='phi scan on monitor') contscan(phis, 0, 1, 1000, 0.001) yield
def omscan(hkl, width=None, speed=None, timedelta=None, **kwds): """Perform a continuous omega scan at the specified Q point. The default scan width is calculated from the instrumental resolution. Examples: >>> omscan((1, 0, 0)) # with default with, speed and timedelta >>> omscan((1, 0, 0), 5) # with a width of 5 degrees >>> omscan((1, 0, 0), 5, 0.1, 1) # with width, speed and timedelta """ instr = session.instrument if not isinstance(instr, SXTalBase): raise NicosError('your instrument is not a sxtal diffractometer') if width is None: width = instr.getScanWidthFor(hkl) calc = dict(instr._extractPos(instr._calcPos(hkl))) om1 = calc['omega'] - width / 2. om2 = calc['omega'] + width / 2. cur_om = instr._attached_omega.read() if abs(cur_om - om1) > abs(cur_om - om2): om1, om2 = om2, om1 maw(instr._attached_gamma, calc['gamma'], instr._attached_nu, calc['nu'], instr._attached_omega, om1) contscan(instr._attached_omega, om1, om2, speed, timedelta)
def test_contscan(session): m = session.getDevice('motor') mm = session.getDevice('manual') ContinuousScan.DELTA = 0.1 session.experiment.detlist = [session.getDevice('det')] try: contscan(m, 0, 2, 10) finally: ContinuousScan.DELTA = 1.0 session.experiment.detlist = [] assert m.speed == 0 # reset to old value dataman = session.experiment.data dataset = dataman.getLastScans()[-1] assert dataset.devvaluelists assert all(0 <= res[0] <= 2 for res in dataset.devvaluelists) # no speed parameter assert raises(UsageError, contscan, mm, 0, 2) # preset and multistep not allowed assert raises(UsageError, contscan, m, 0, 2, 2, t=1) assert raises(UsageError, contscan, m, 0, 2, 2, manual=[0, 1])
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
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()