Beispiel #1
0
def sleep(secs):
    """Sleep for a given number of seconds.

    This is different from Python's `time.sleep()` in that it allows breaking
    and stopping the sleep, and supports dry run mode.  Fractional values are
    supported.

    Examples:

    >>> sleep(10)     # sleep for 10 seconds
    >>> sleep(0.5)    # sleep for half a second
    """
    session.log.info('sleeping for %.1f seconds...', secs)

    if session.mode == SIMULATION:
        session.clock.tick(secs)
        return

    def f_notify(tmr):
        session.breakpoint(2)  # allow break and continue here
        session.action('%s left' % formatDuration(tmr.remaining_time()))

    session.beginActionScope('Sleeping')
    session.action('%s left' % formatDuration(secs))
    try:
        tmr = Timer(secs)
        tmr.wait(interval=1.0, notify_func=f_notify)
    finally:
        session.endActionScope()
Beispiel #2
0
 def isCompleted(self):
     if session.mode == SIMULATION:
         return True
     if not self.stopflag and self.endtime > currenttime():
         # arbitrary choice of max 5s
         session.delay(min(5, self.endtime - currenttime()))
         return False
     if self.duration > 3:
         session.endActionScope()
     return True
Beispiel #3
0
 def pointScope(self, num):
     if self.dataset.npoints == 0:
         session.beginActionScope('Point %d' % num)
     else:
         session.beginActionScope('Point %d/%d' %
                                  (num, self.dataset.npoints))
     try:
         yield
     finally:
         session.endActionScope()
Beispiel #4
0
 def prepareScan(self, position):
     # XXX with actionscope
     session.beginActionScope('Moving to start')
     try:
         # the move-before devices
         if self._firstmoves:
             fm_devs, fm_pos = zip(*self._firstmoves)
             self.moveDevices(fm_devs, fm_pos)
         # the scanned-over devices
         self.moveDevices(self._devices, position)
     finally:
         session.endActionScope()
Beispiel #5
0
    def run(self):
        if not self._subscan and getattr(session, '_currentscan', None):
            raise NicosError('cannot start scan while another scan is running')
        # stop previous inner_count / acquisition thread if available
        stop_acquire_thread()

        session._currentscan = self
        # XXX(dataapi): this is too early, dataset has no number yet
        session.beginActionScope(self.shortDesc())
        try:
            self._inner_run()
        finally:
            session.endActionScope()
            session._currentscan = None
        return self.dataset
Beispiel #6
0
 def execute(self, controller):
     """Execute the script in the given namespace, using "controller"
     to execute individual blocks.
     """
     session.scriptEvent('start', (self.name, self.text))
     session.countloop_request = None  # reset any pause flag from before
     # this is to allow the traceback module to report the script's
     # source code correctly
     updateLinecache('<script>', self.text)
     # note: checking session._experiment since using session.experiment
     # would try to create the device, which means you can't execute any
     # command when the experiment fails
     if session._experiment and session.mode == MASTER:
         session.experiment.scripts += [self.text]
         self._exp_script_index = len(session.experiment.scripts) - 1
     if self.name:
         session.elogEvent('scriptbegin', self.name)
         session.beginActionScope(path.basename(self.name))
     # notify clients of "input"
     session.log.log(INPUT, formatScript(self))
     try:
         while self.curblock < len(self.code) - 1:
             self._run.wait()
             self.curblock += 1
             self.blockStart = time.time()
             self.emitETA(controller)
             controller.start_exec(self.code[self.curblock],
                                   controller.namespace, None,
                                   self.settrace)
     finally:
         if self.name:
             session.endActionScope()
         if session._experiment and session.mode == MASTER:
             session.experiment.scripts = session.experiment.scripts[:-1]
         if self.name:
             session.elogEvent('scriptend', self.name)
Beispiel #7
0
 def __exit__(self, *args):
     session.endActionScope()
     if session.experiment and session.mode in (MASTER, SIMULATION):
         session.experiment.scripts = session.experiment.scripts[:-1]
     session.elogEvent('scriptend', self.filename)
Beispiel #8
0
 def __exit__(self, *args):
     session.endActionScope()
Beispiel #9
0
def acquire(point, preset, iscompletefunc=None):
    """Low-level acquisition function.

    The loop delay is configurable in the instrument object, and defaults to
    0.025 seconds.

    The result is stored in the given argument, which must be an empty list.
    This is so that a result can be returned even when a stop exception is
    propagated upwards.

    The *iscompletefunc* callback can be used to influence the stop of the
    detectors. When *iscompeletefunc* returns `True` the detectors will be
    stopped. This can be useful to implement scans with software
    synchronisation, e.g. stopping of the detector when the movement of
    the scanned axis has been finished although the preset has not yet
    been fulfilled.
    """
    if iscompletefunc is None:  # do not influence count loop using callback
        iscompletefunc = lambda: False
    # put detectors in a set and discard them when completed
    detset = set(point.detectors)
    delay = (session.instrument and session.instrument.countloopdelay or 0.025
             if session.mode != SIMULATION else 0.0)

    dataman = session.experiment.data

    session.beginActionScope('Counting')
    if session.countloop_request:
        _wait_for_continuation(delay, only_pause=True)
    for det in point.detectors:
        det.setPreset(**preset)

    for det in point.detectors:
        det.prepare()
    for det in point.detectors:
        waitForCompletion(det)

    dataman.updateMetainfo()
    point.started = currenttime()
    try:
        for det in point.detectors:
            det.start()
    except:
        session.endActionScope()
        raise
    session.delay(delay)
    try:
        quality = None
        while True:
            looptime = currenttime()
            for det in list(detset):
                if session.mode != SIMULATION:
                    quality = det.duringMeasureHook(looptime - point.started)
                if det.isCompleted():
                    det.finish()
                    quality = FINAL
                if quality:
                    try:
                        res = det.readResults(quality)
                    except Exception:
                        det.log.exception('error reading measurement data')
                        res = None
                    dataman.putResults(quality, {det.name: res})
                if quality == FINAL:
                    detset.discard(det)
            if not detset:
                # all detectors finished measuring
                break
            if session.countloop_request:
                for det in detset:
                    if not det.pause():
                        session.log.warning(
                            'detector %r could not be paused', det.name)
                if not _wait_for_continuation(delay):
                    for det in detset:
                        # next iteration of loop will see det is finished
                        det.finish()
                else:
                    for det in detset:
                        det.resume()
            if iscompletefunc():  # stop via callback function
                for det in detset:
                    det.stop()
            session.delay(delay)
    except BaseException as e:
        exc_info = sys.exc_info()
        point.finished = currenttime()
        if e.__class__.__name__ != 'ControlStop':
            session.log.warning('Exception during count, trying to save data',
                                exc=True)
        for det in detset:
            try:
                # XXX: in theory, stop() can return True or False to indicate
                # whether saving makes sense.
                #
                # However, it might be better to leave that to the data sink
                # handling the INTERRUPTED quality.
                det.stop()
                res = det.readResults(INTERRUPTED)
            except Exception:
                det.log.exception('error reading measurement data')
                res = None
            try:
                dataman.putResults(INTERRUPTED, {det.name: res})
            except Exception:
                det.log.exception('error saving measurement data')
        reraise(*exc_info)
    finally:
        point.finished = currenttime()
        session.endActionScope()
Beispiel #10
0
 def manualEnd(self):
     session.endActionScope()
     self.endScan()
Beispiel #11
0
    def _inner_run(self):
        try:
            self.prepareScan(self._startpositions[0])
        except (StopScan, SkipPoint, LimitError):
            return

        dataman = session.experiment.data
        self.beginScan()

        device = self._devices[0]
        detlist = self._detlist
        point = 0
        try:
            if session.mode == SIMULATION:
                preset = 1  # prevent all contscans taking 1 hour
            else:
                preset = max(self._distance / (self._speed or 0.1) * 5, 3600)

            devpos = device.read(0)

            self.preparePoint(None, None)

            for det in detlist:
                det.start(t=preset)
            device.move(self._endpositions[0][0])
            starttime = looptime = currenttime()

            last = {det.name: (det.read(), det.readArrays(INTERMEDIATE))
                    for det in detlist}

            while device.status(0)[0] == status.BUSY:
                session.breakpoint(2)
                sleeptime = max(0, looptime + self._timedelta - currenttime())
                session.log.debug('sleep time: %f', sleeptime)
                with self.pointScope(point + 1):
                    session.delay(sleeptime)
                    looptime = currenttime()
                    new_devpos = device.read(0)
                    read = {det.name: (det.read(),
                                       det.readArrays(INTERMEDIATE))
                            for det in detlist}
                    actualpos = [0.5 * (devpos + new_devpos)]
                    dataman.beginTemporaryPoint()
                    if point == 0:
                        dataman.updateMetainfo()
                    dataman.putValues({device.name: (None, actualpos)})
                    self.readEnvironment()
                    # TODO: if the data sink needs it ?
                    # dataman.updateMetainfo()
                    dataman.putResults(FINAL, self._calculate_diff(last, read))
                    dataman.finishPoint()
                    last = read
                    devpos = new_devpos
                    for det in detlist:
                        det.duringMeasureHook(looptime - starttime)
                    point += 1
            device.wait()  # important for simulation
        finally:
            session.endActionScope()
            for det in detlist:
                try:
                    det.finish()
                except Exception:
                    session.log.warning('could not stop %s', det, exc=1)
            try:
                device.stop()
                device.wait()
            except Exception:
                device.log.warning('could not stop %s', device, exc=1)
            self.endScan()
Beispiel #12
0
def waitfor(dev, condition, timeout=86400):
    """Wait for a device until a condition is fulfilled.

    Convenience function to avoid writing code like this:

    >>> while not motor.read() < 10:
    ...     sleep(0.3)

    which now can be written as:

    >>> waitfor(motor, '< 10')

    The supported conditions are [#]_:

    - '<', '<=', '==', '!=', '>=', '>' with a value
    - 'is False', 'is True', 'is None'
    - 'in list', where list could be a Python list or tuple

    An optional timeout value can be added, which denominates the maximum time
    the command will wait (in seconds).  If the timeout value is reached, an
    error will be raised.  The default timeout value is 86400 seconds (1 day).
    Example:

    >>> waitfor(T, '< 10', timeout=3600)

    Will wait a maximum of 1 hour for T to get below 10.

    .. note::

       In contrast to the `wait()` command this command will not only wait
       until the target is reached.  You may define also conditions which
       represent intermediate states of a movement or you may wait on
       external trigger signals and so on.

    .. [#] The device value, determined by ``dev.read()``, will be added in
       front of the condition, so the resulting conditions is:

        >>> dev.read() < 10

       The condition parameter will be given as a simple comparison to
       the value of the device.
    """
    dev = session.getDevice(dev, Readable)
    full_condition = '_v %s' % condition

    try:
        ast.parse(full_condition)
    except Exception:
        raise UsageError('Could not parse condition %r' % condition)

    if session.mode == SIMULATION:
        return

    def check(tmr):
        session.breakpoint(2)  # allow break and continue here
        waitfor.cond_fulfilled = eval(full_condition, {}, {'_v': dev.read(0)})
        if waitfor.cond_fulfilled:
            session.log.info('Waiting for \'%s %s\' finished.', dev, condition)
            tmr.stop()

    waitfor.cond_fulfilled = False
    try:
        session.beginActionScope('Waiting until %s %s' % (dev, condition))
        tmr = Timer(timeout if timeout else 86400)  # max wait time 1 day
        tmr.wait(dev._base_loop_delay * 3, check)
    finally:
        if not waitfor.cond_fulfilled:
            raise NicosTimeoutError(
                dev, 'Waiting for \'%s %s\' timed out.' % (dev, condition))
        session.endActionScope()
Beispiel #13
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()
Beispiel #14
0
def multiWait(devices):
    """Wait for the *devices*.

    Returns a dictionary mapping devices to current values after waiting.

    This is the main waiting loop to be used when waiting for multiple devices.
    It checks the device status until all devices are OK or errored.

    Errors raised are handled like in the following way:
    The error is logged, and the first exception with the highest serverity
    (exception in `CONTINUE_EXECPTIONS` < `SKIP_EXCPTIONS` < other exceptions)
    is re-raised at the end.

    *baseclass* allows to restrict the devices waited on.
    """
    from nicos.core.device import Waitable

    def get_target_str():
        return ', '.join(
            '%s -> %s' %
            (dev,
             dev.format(dev.target)) if hasattr(dev, 'target') else str(dev)
            for dev in reversed(devlist))

    delay = 0.3
    final_exc = None
    devlist = list(devIter(devices, baseclass=Waitable, allwaiters=True))
    session.log.debug('multiWait: initial devices %s, all waiters %s', devices,
                      devlist)
    values = {}
    loops = -2  # wait 2 iterations for full loop
    eta_update = 1 if session.mode != SIMULATION else 0
    first_ts = currenttime()
    session.beginActionScope('Waiting')
    eta_str = ''
    target_str = get_target_str()
    session.action(target_str)
    try:
        while devlist:
            session.log.debug('multiWait: iteration %d, devices left %s',
                              loops, devlist)
            loops += 1
            for dev in devlist[:]:
                try:
                    done = dev.isCompleted()
                    if done:
                        dev.finish()
                except Exception:
                    final_exc = filterExceptions(sys.exc_info(), final_exc)
                    # remove this device from the waiters - we might still have
                    # its subdevices in the list so that multiWait() should not
                    # return until everything is either OK or ERROR
                    devlist.remove(dev)
                    if devlist:
                        # at least one more device left, show the exception now
                        dev.log.exception('while waiting')
                    continue
                if not done:
                    # we found one busy dev, normally go to next iteration
                    # until this one is done (saves going through the whole
                    # list of devices and doing unnecessary HW communication)
                    if loops % 10:
                        break
                    # every 10 loops, go through everything to get an accurate
                    # display in the action line
                    continue
                if dev in devices:
                    # populate the results dictionary, but only with the values
                    # of excplicitly given devices
                    values[dev] = dev.read()
                # this device is done: don't wait for it anymore
                devlist.remove(dev)
                target_str = get_target_str()
                session.action(eta_str + target_str)
            if devlist:
                if eta_update >= 1:
                    eta_update -= 1
                    now = currenttime()
                    eta = {dev.estimateTime(now - first_ts) for dev in devlist}
                    eta.discard(None)
                    # use max here as we wait for ALL movements to finish
                    eta_str = ('estimated %s left / ' %
                               formatDuration(max(eta)) if eta else '')
                    session.action(eta_str + target_str)
                session.delay(delay)
                eta_update += delay
        if final_exc:
            reraise(*final_exc)
    finally:
        session.endActionScope()
        session.log.debug('multiWait: finished')
    return values