def test_multi_det(self): """ Test AutoFocus Spectrometer with multiple detectors """ # Note: a full procedure would start by setting the slit to the smallest position # (cf optical path mode "spec-focus") and activating an energy source self.focus.moveAbs({"z": self._good_focus + 400e-6}).result() f = align.AutoFocusSpectrometer(self.spgr, self.focus, [self.ccd, self.spccd], self.selector) res = f.result(timeout=900) for (g, d), fpos in res.items(): self.assertIn(d, (self.ccd, self.spccd)) # Only check that the focus is correct with the CCD as the simulator # doesn't actually connects the focus position to the spccd image # (so the image is always the same, and the autofocus procedure # picks a random position) if d is self.ccd: self.assertAlmostEqual(fpos, self._good_focus, 3) # The number of entries depend on the implementation. For now, we expect # an entry for each combination grating/detector ngs = len(self.spgr.axes["grating"].choices) nds = 2 self.assertEqual(len(res), ngs * nds)
def test_cancel(self): """ Test cancelling does cancel (relatively quickly) """ self.focus.moveAbs({"z": self._good_focus + 400e-6}).result() f = align.AutoFocusSpectrometer(self.spgr, self.focus, [self.ccd]) time.sleep(2) f.cancel() self.assertTrue(f.cancelled()) with self.assertRaises(CancelledError): res = f.result(timeout=900)
def test_one_det(self): """ Test AutoFocus Spectrometer on CCD """ self.focus.moveAbs({"z": self._good_focus - 200e-6}).result() f = align.AutoFocusSpectrometer(self.spgr, self.focus, self.ccd) res = f.result(timeout=900) for (g, d), fpos in res.items(): self.assertIs(d, self.ccd) self.assertAlmostEqual(fpos, self._good_focus, 3) self.assertEqual(len(res.keys()), len(self.spgr.axes["grating"].choices))
def main(args): """ Handles the command line arguments args is the list of arguments passed return (int): value to return to the OS as program exit code """ # arguments handling parser = argparse.ArgumentParser(description="Automated focus procedure") parser.add_argument("--detector", "-d", dest="detector", default="ccd", help="role of the detector (default: ccd)") parser.add_argument("--focuser", "-f", dest="focuser", default="focus", help="role of the focus component (default: focus). " "It must be an actuator with a 'z' axis.") parser.add_argument("--spectrograph", "-s", dest="spectrograph", help="role of the spectrograph component. " "If provided, a full spectrometer autofocus will be executed.") parser.add_argument("--log-level", dest="loglev", metavar="<level>", type=int, default=1, help="set verbosity level (0-2, default = 1)") options = parser.parse_args(args[1:]) # Set up logging before everything else if options.loglev < 0: logging.error("Log-level must be positive.") return 127 loglev_names = [logging.WARNING, logging.INFO, logging.DEBUG] loglev = loglev_names[min(len(loglev_names) - 1, options.loglev)] logging.getLogger().setLevel(loglev) try: # find components by their role try: det = model.getComponent(role=options.detector) except LookupError: raise ValueError("Failed to find detector '%s'" % (options.detector,)) try: focuser = model.getComponent(role=options.focuser) except LookupError: raise ValueError("Failed to find focuser '%s'" % (options.focuser,)) emt = None if det.role in ("se-detector", "bs-detector", "cl-detector"): # For EM images, the emitter is not necessary, but helps to get a # better step size in the search (and time estimation) try: emt = model.getComponent(role="e-beam") except LookupError: logging.info("Failed to find e-beam emitter") pass if options.spectrograph: try: spgr = model.getComponent(role=options.spectrograph) # TODO: allow multiple detectors except LookupError: raise ValueError("Failed to find spectrograph '%s'" % (options.spectrograph,)) else: spgr = None logging.info("Original focus position: %f m", focuser.position.value["z"]) # Apply autofocus try: if spgr: future_focus = align.AutoFocusSpectrometer(spgr, focuser, det) foc = future_focus.result(1000) # putting a timeout allows to get KeyboardInterrupts logging.info("Focus levels after applying autofocus: %s", "".join("\n\tgrating %d on %s @ %f m" % (g, d.name, f) for (g, d), f in foc.items())) else: future_focus = align.AutoFocus(det, emt, focuser) foc_pos, fm_final = future_focus.result(1000) # putting a timeout allows to get KeyboardInterrupts logging.info("Focus level after applying autofocus: %f @ %f m", fm_final, foc_pos) except KeyboardInterrupt: future_focus.cancel() raise except KeyboardInterrupt: logging.info("Interrupted before the end of the execution") return 1 except ValueError as exp: logging.error("%s", exp) return 127 except Exception: logging.exception("Unexpected error while performing action.") return 127 return 0