def test_default_fluo(self): """ Check the default values for the FluoStream are fitting the current HW settings """ em_choices = self.light_filter.axes["band"].choices # no light info self.light.emissions.value = [0] * len(self.light.emissions.value) s1 = stream.FluoStream("fluo1", self.ccd, self.ccd.data, self.light, self.light_filter) # => stream emission is based on filter self.assertEqual(s1.excitation.choices, set(self.light.spectra.value)) self.assertEqual(set(s1.emission.choices), set(conversion.ensureTuple(em_choices.values()))) em_idx = self.light_filter.position.value["band"] em_hw = em_choices[em_idx] self.assertEqual(s1.emission.value, conversion.ensureTuple(em_hw)) # => stream excitation is light spectra closest below emission self.assertIn(s1.excitation.value, self.light.spectra.value) em_center = numpy.mean(em_hw) ex_centers = [s[2] for s in s1.excitation.choices] try: expected_ex = min([c for c in ex_centers if c < em_center], key=lambda c: em_center - c) except ValueError: # no excitation < em_center expected_ex = min(ex_centers) self.assertEqual(s1.excitation.value[2], expected_ex) # with light info (last emission is used) self.light.emissions.value[-1] = 0.9 s2 = stream.FluoStream("fluo2", self.ccd, self.ccd.data, self.light, self.light_filter) # => stream emission is based on filter self.assertEqual(s2.excitation.choices, set(self.light.spectra.value)) self.assertEqual(set(s2.emission.choices), set(conversion.ensureTuple(em_choices.values()))) em_idx = self.light_filter.position.value["band"] em_hw = em_choices[em_idx] self.assertEqual(s2.emission.value, conversion.ensureTuple(em_hw)) # => stream excitation is based on light.emissions self.assertIn(s2.excitation.value, self.light.spectra.value) expected_ex = self.light.spectra.value[-1] # last value of emission self.assertEqual(s2.excitation.value, expected_ex)
def test_fluo(self): """ Check that the hardware settings are correctly set based on the settings """ s1 = stream.FluoStream("fluo1", self.ccd, self.ccd.data, self.light, self.light_filter) self.ccd.exposureTime = 1 # s, to avoid acquiring too many images # Check we manage to get at least one image self._image = None s1.image.subscribe(self._on_image) s1.should_update.value = True s1.is_active.value = True # change the stream setting (for each possible excitation) for i, exc in enumerate(self.light.spectra.value): s1.excitation.value = exc time.sleep(0.1) # check the hardware setting is updated exp_intens = [0] * len(self.light.spectra.value) exp_intens[i] = 1 self.assertEqual(self.light.emissions.value, exp_intens) time.sleep(2) s1.is_active.value = False self.assertFalse(self._image is None, "No image received after 2s")
def setUpClass(cls): try: test.start_backend(CRYOSECOM_CONFIG) except LookupError: logging.info("A running backend is already found, skipping tests") cls.backend_was_running = True return except IOError as exp: logging.error(str(exp)) raise # create some streams connected to the backend cls.microscope = model.getMicroscope() cls.ccd = model.getComponent(role="ccd") cls.ebeam = model.getComponent(role="e-beam") cls.sed = model.getComponent(role="se-detector") cls.light = model.getComponent(role="light") cls.focus = model.getComponent(role="focus") cls.light_filter = model.getComponent(role="filter") cls.stage = model.getComponent(role="stage") # Create 1 sem stream and 2 fm streams to be used in testing ss1 = stream.SEMStream( "sem1", cls.sed, cls.sed.data, cls.ebeam, emtvas={"dwellTime", "scale", "magnification", "pixelSize"}) fs1 = stream.FluoStream("fluo1", cls.ccd, cls.ccd.data, cls.light, cls.light_filter, focuser=cls.focus) fs1.excitation.value = sorted(fs1.excitation.choices)[0] fs2 = stream.FluoStream("fluo2", cls.ccd, cls.ccd.data, cls.light, cls.light_filter) fs2.excitation.value = sorted(fs2.excitation.choices)[-1] cls.sem_streams = [ss1] cls.fm_streams = [fs1, fs2]
def acquire_timelapse(num, period, filename): """ num (int or None): if None, will never stop, unless interrupted """ # Find components by their role ccd = model.getComponent(role="ccd") ebeam = model.getComponent(role="e-beam") sed = model.getComponent(role="se-detector") light = model.getComponent(role="light") light_filter = model.getComponent(role="filter") stage = model.getComponent(role="stage") focus = model.getComponent(role="focus") # Prepare the streams and acquisition manager # The settings of the emissions and excitation are based on the current # hardware settings. stfm = stream.FluoStream("Fluorescence image", ccd, ccd.data, light, light_filter) # Force the excitation light using that command: # stfm.excitation.value = (4.72e-07, 4.79e-07, 4.85e-07, 4.91e-07, 4.97e-07) stem = stream.SEMStream("Secondary electrons", sed, sed.data, ebeam) # Special stream that will run the overlay and update the metadata based on this # Note: if more complex overlay is needed (eg, with background subtraction, # or with saving the CCD image), we'd need to directly call FindOverlay()) stovl = stream.OverlayStream("Overlay", ccd, ebeam, sed) stovl.dwellTime.value = OVERLAY_DT acq_streams = [stem, stfm, stovl] # Prepare to save each acquisition in a separate file exporter = dataio.find_fittest_converter(filename) basename, ext = os.path.splitext(filename) fn_pattern = basename + "%04d" + ext fn_pos = basename + "pos.csv" fpos = open(fn_pos, "a") fpos.write("time\tX\tY\tZ\n") # Run acquisition every period try: i = 1 while True: logging.info("Acquiring image %d", i) start = time.time() # Acquire all the images f = acq.acquire(acq_streams) data, e = f.result() if e: logging.error("Acquisition failed with %s", e) # It can partially fail, so still allow to save the data successfully acquired # Note: the actual time of the position is the one when the position was read # by the pigcs driver. spos = stage.position.value fpos.write("%.20g\t%g\t%g\t%g\n" % (time.time(), spos["x"], spos["y"], focus.position.value["z"])) # Save the file if data: exporter.export(fn_pattern % (i,), data) # TODO: run autofocus from time to time? left = period - (time.time() - start) if left < 0: logging.warning("Acquisition took longer than the period (%g s overdue)", -left) else: logging.info("Sleeping for another %g s", left) time.sleep(left) if i == num: # will never be True if num is None break i += 1 except KeyboardInterrupt: logging.info("Closing after only %d images acquired", i) except Exception: logging.exception("Failed to acquire all the images.") raise fpos.close()