def doRead(self, maxage=0): res = self._attached_io_status.read(maxage) if res == 1: return 'in' elif res == 2: return 'out' elif res in [0, 3]: raise PositionError(self, 'filter unit in error state, somewhere ' 'in between in/out') else: raise PositionError(self, 'invalid value of I/O: %s' % res)
def test_scan_errorhandling(session, log): t = session.getDevice('tdev') m = session.getDevice('motor') dataman = session.experiment.data # no errors, works fine scan(t, [0, 1, 2]) dataset = dataman.getLastScans()[-1] assert dataset.devvaluelists == [[0], [1], [2]] with log.allow_errors(): # limit error: skips the data points scan(t, [-10, 0, 10, 3]) dataset = dataman.getLastScans()[-1] assert dataset.devvaluelists == [[0], [3]] # communication error during move: also skips the data points t._value = 0 t._start_exception = CommunicationError() scan(t, [0, 1, 2, 3]) dataset = dataman.getLastScans()[-1] assert dataset.devvaluelists == [[ 0 ]] # tdev.move only raises when target != 0 # position error during move: ignored t._value = 0 t._read_exception = None t._start_exception = PositionError() scan(t, [0, 1, 2, 3]) dataset = dataman.getLastScans()[-1] assert dataset.devvaluelists == [[0], [None], [None], [None]] # position error during readout: ignored t._read_exception = PositionError() t._start_exception = None scan(t, [0, 1, 2, 3]) dataset = dataman.getLastScans()[-1] assert dataset.devvaluelists == [[None], [None], [None], [None]] # also as an environment device scan(m, [0, 1], t) dataset = dataman.getLastScans()[-1] assert dataset.devvaluelists == [[0.], [1.]] assert dataset.envvaluelists == [[None], [None]] # other errors: reraised t._start_exception = RuntimeError() assert raises(RuntimeError, scan, t, [0, 1, 2, 3])
def _checkDragerror(self): """Check if a "drag error" occurred. The values of motor and coder deviate too much. This indicates that the movement is blocked. This method sets the error state and returns False if a drag error occurs, and returns True otherwise. """ if self._maxdiff <= 0: return True diff = abs(self._attached_motor.read() - self._attached_coder.read()) self.log.debug('motor/coder diff: %s', diff) if diff > self._maxdiff: self._errorstate = MoveError( self, 'drag error (primary coder): ' 'difference %.4g, maximum %.4g' % (diff, self._maxdiff)) return False for obs in self._attached_obs: diff = abs(self._attached_motor.read() - obs.read()) if diff > self._maxdiff: self._errorstate = PositionError( self, 'drag error (%s): difference %.4g, maximum %.4g' % (obs.name, diff, self._maxdiff)) return False return True
def _step(self, devicename, pos): """Make one step in the changing sequence. evaluates the given keyword argument and moves the attached_device with the keyname to the value-position. Also checks success """ dev = self._adevs[devicename] # now log some info if pos == 'open': self.log.info("Open '%s'", dev.name) elif pos == 'closed': self.log.info("Close '%s'", dev.name) else: self.log.info("Move '%s' to '%s' position", dev.name, pos) try: dev.start(pos) if devicename == 'r3': # R3 does not wait! session.delay(2) if devicename == 'grip': # grip does not wait! session.delay(2) dev.wait() except Exception: # most probably it is touching the limit switch if devicename == 'lift': dev._adevs['moveables'][0].motor.stop() self.log.info('Limit switch ?') else: raise if dev.read(0) != pos: raise PositionError("Device '%s' did not reach its target '%s', " 'aborting' % (dev, pos))
def _mapReadValue(self, pos): """Override default inverse mapping to allow a deviation <= precision""" prec = self.precision def myiter(mapping): # use position names beginning with P as last option for name, value in mapping.items(): if name[0] != 'P': yield name, value for name, value in mapping.items(): if name[0] == 'P': yield name, value for name, value in myiter(self.mapping): if prec: if abs(pos - value) <= prec: return name elif pos == value: return name if self.fallback is not None: return self.fallback if self.relax_mapping: return self._attached_moveable.format(pos, True) raise PositionError(self, 'unknown position of %s' % self._attached_moveable)
def doRead(self, maxage=0): up = self._attached_holdstat.read(maxage) down = self._attached_mono_stat.read(maxage) if up != 'None': if up != down: raise PositionError(self, 'unknown position of %s' % self.name) return self._attached_holdstat.read(maxage)
def doStart(self, pos): if pos == self.read(0): return self._attached_sr7set.start(self.positions.index(pos)) if self.wait() != pos: raise PositionError(self, 'device returned wrong position') self.log.info('SR7: %s', pos)
def _mapReadValue(self, pos): """maps a tuple to one of the configured values""" hasprec = bool(self.precision) if hasprec: precisions = self.precision if len(precisions) == 1: precisions = [precisions[0]] * len(self.devices) for name, values in self.mapping.items(): if hasprec: for p, v, prec in zip(pos, values, precisions): if prec: if abs(p - v) > prec: break elif p != v: break else: # if there was no break we end here... return name else: if tuple(pos) == tuple(values): return name if self.fallback is not None: return self.fallback raise PositionError(self, 'unknown position of %s: %s' % ( ', '.join(str(d) for d in self.devices), ', '.join(d.format(p) for (p, d) in zip(pos, self.devices))))
def _checkTargetPosition(self, target, pos, error=True): """Check if the axis is at the target position. This method returns False if not arrived at target, or True otherwise. """ diff = abs(pos - target) prec = self.precision if (0 < prec <= diff) or (prec == 0 and diff): msg = 'precision error: difference %.4g, precision %.4g' % \ (diff, self.precision) if error: self._errorstate = MoveError(msg) else: self.log.debug(msg) return False maxdiff = self.dragerror for obs in self._attached_obs: diff = abs(target - (obs.read() - self.offset)) if 0 < maxdiff < diff: msg = 'precision error (%s): difference %.4g, maximum %.4g' % \ (obs, diff, maxdiff) if error: self._errorstate = PositionError(msg) else: self.log.debug(msg) return False return True
def _to_lambda(self, phi1, phi2, trans): """Calculate lambda from phi1, phi2, trans. May raise a PositionError. Not necessarily all arguments are used. Next iteration could evaluate all 3 args and return an average value... """ try: return abs(2 * self.dvalue1 * sin(radians(phi1))) except Exception: raise PositionError('can not determine lambda!')
def _mapReadValue(self, pos): """maps a tuple to one of the configured values""" for name, values in self.mapping.items(): if tuple(pos) == tuple(values): return name if self.fallback is not None: return self.fallback raise PositionError( self, 'unknown position of %s: %s' % (', '.join(str(d) for d in self._adevs), ', '.join( d.format(p) for (p, d) in zip(pos, self._adevs))))
def _mapReadValue(self, pos): prec = self.precision for name, value in self.mapping.items(): if prec: if abs(pos - value) <= prec: return name elif pos == value: return name if self.fallback is not None: return self.fallback raise PositionError(self, 'unknown position of %s' % self._attached_readable)
def doRead(self, maxage=0): res = self.doStatus()[0] if res == status.OK: if self._attached_sr7cl.doRead() == 1: return 'close' elif self._attached_sr7p1.doRead() == 1: return 'S1' elif self._attached_sr7p2.doRead() == 1: return 'S2' elif self._attached_sr7p3.doRead() == 1: return 'S3' else: raise PositionError(self, 'SR7 shutter moving or undefined')
def doRead(self, maxage=0): for _ in range(10): # try to filter out 'half-broken' values value = np.median([Sensor.doRead(self, maxage) for _ in range(3)]) # avoid fully broken values if self.limits[0] <= value <= self.limits[1]: return value # at least warn (every retry!) self.log.warning( 'Sensor value %s outside sensible range [%s..%s]' % (value, self.limits[0], self.limits[1])) # 10 times no good value -> error raise PositionError('Sensor value %s outside sensible range [%s..%s]' % (value, self.limits[0], self.limits[1]))
def _mapReadValue(self, pos): """Override default inverse mapping to allow a deviation <= precision""" for name, values in iteritems(self.mapping): value, prec = values if pos == value: return name elif prec: if abs(pos - value) <= prec: return name if self.fallback is not None: return self.fallback raise PositionError(self, 'unknown position of %s: %s' % (self._attached_moveable, self._attached_moveable.format(pos, True)) )
def _mapReadValue(self, value): """Hook for integration of mapping/switcher devices. This method is called with the value returned by `._readRaw()` and should map the raw value to a high-level value. By default, it maps values according to the reverse of the `nicos.core.mixins.HasMapping.mapping` parameter. """ if value in self._inverse_mapping: return self._inverse_mapping[value] elif self.relax_mapping: if self.fallback is not None: return self.fallback else: raise PositionError(self, 'unknown unmapped position %r' % value)
def _mapReadValue(self, pos): prec = self.precision if self._attached_table.read() != self.activeposition: return 'N.A.' for name, value in self.mapping.items(): if prec: if abs(pos - value) <= prec: return name elif pos == value: return name if self.fallback is not None: return self.fallback if self.relax_mapping: return self._attached_moveable.format(pos, True) raise PositionError(self, 'unknown position of %s' % self._attached_moveable)
def test_error_handling(session, log, tas): # check that if one subdev errors out, we wait for the other subdevs mfh = session.getDevice('t_mfh') phi = session.getDevice('t_phi') tas.maw([1.01, 0, 0, 1]) phi.speed = 1 mfh._status_exception = PositionError(mfh, 'wrong position') with log.allow_errors(): try: tas.maw([1, 0, 0, 1]) except MoveError: pass else: assert False, 'PositionError not raised' # but we still arrived with phi assert phi() == approx(-46.6, abs=0.1)
def _move2start(self): self.log.info('Move %s for monochromator change', ', '.join(sorted(self.changing_positions))) for dev, pos in self._changing_values.items(): dev.start(pos) # multiWait(self._changing_values) multiWait(self._changing_values.keys()) for dev, pos in self._changing_values.items(): if abs(dev.read(0) - pos) > dev.precision: raise PositionError( self, "'%s' did not reach target position " "'%s'" % (dev, pos)) for dev in self._changing_values: dev.fix('Monochromator change in progress')
def doStart(self, position): motor = self._attached_motor currentpos = self.read(0) motorpos = motor.read(0) if position == currentpos and motorpos == self.justpos: return if abs(motorpos - self.justpos) > 0.5: motorpos = motor.maw(0) self._attached_io_set.start(1 if position == 'in' else 0) if self.wait() != position: raise PositionError(self, 'device returned wrong position') if (self.doStatus()[0] == status.OK) and (motorpos != self.justpos): motorpos = motor.maw(self.justpos) self.log.info('rotation angle of filter: %s', motor.format(motorpos, unit=True))
def doRead(self, maxage=0): pos = [d.read(maxage) for d in self.devices] # Are we in the beam? if pos[0] == 'out': return None # calculate lambda from phi1 and then check the other positions # for consistency... lam = self._to_lambda(*pos[1:]) self.log.debug('lambda seems to be %.4f Angstroms', lam) compare_pos = self._from_lambda(lam) tol = [self.tolphi, self.tolphi, self.toltrans] for d, p, t, c in zip(self.devices[1:], pos[1:], tol, compare_pos): self.log.debug('%s is at %s and should be at %s for %.4f ' 'Angstroms', d, d.format(p), d.format(c), lam) if abs(p-c) > t: raise PositionError('%s is too far away for %.4f Angstroms' % (d, lam)) return lam
def doStart(self, value): if value == 'off': if self._attached_daq.mode == 'tof': # don't touch realtime self._attached_daq.mode = 'standard' self._attached_params.start((0, 0)) return elif value == 'manual': if self._attached_daq.mode == 'standard': self._attached_daq.mode = 'tof' return reso = float(value.strip('%')) / 100.0 sel_target = self._attached_selector.target det_target = self._attached_det_pos.target try: lam = self._attached_selector.presets[sel_target]['lam'] spread = self._attached_selector.presets[sel_target]['spread'] det_z = self._attached_det_pos.presets[sel_target][det_target]['z'] det_offset = self._attached_det_pos.offsets[det_z] except KeyError: raise PositionError( self, 'cannot calculate chopper settings: selector or ' 'detector device not at preset') from None self.log.debug('chopper calc inputs: reso=%f, lam=%f, spread=%f, ' 'det_z=%f', reso, lam, spread, det_z) freq, opening = calculate(lam, spread, reso, self.shade, 20.0 + det_z + det_offset, self.tauoffset, self.nmax) self.log.debug('calculated chopper settings: freq=%f, opening=%f', freq, opening) interval = int(1000000.0 / (freq * self.channels)) self.calcresult = freq, opening, interval self._attached_params.start((freq, opening)) self._attached_daq.mode = 'tof' self._attached_daq.tofchannels = self.channels self._attached_daq.tofinterval = interval self._attached_daq.tofprogression = 1.0 # linear channel widths self._attached_daq.tofcustom = [] # no custom channels
def _finalize(self): """Will be called after a successful monochromator change.""" # test this! # self.log.debug('Enabling Powerstages for %s', # ', '.join(sorted(self.changing_positions))) # for dev in self._changing_values: # dev.power = 'on' self.log.info('releasing mono devices') # self._attached_monochromator.release() for dev in self._changing_values: dev.release() self.log.info('move mono devices to the nominal positions') for dev, pos in self._init_values.items(): dev.start(pos) multiWait(self._init_values.keys()) for dev, pos in self._init_values.items(): if abs(dev.read(0) - pos) > dev.precision: raise PositionError( self, "'%s' did not reach target position " "'%s'" % (dev, pos))
def doRead(self, maxage=0): if self.target in self.states: return self.target raise PositionError(self, 'device is in an unknown state')