Пример #1
0
    def test_acq_fine_align(self):
        """
        try acquisition with SEM + Optical + overlay streams
        """
        # Create the streams
        sems = stream.SEMStream("test sem", self.sed, self.sed.data, self.ebeam)
        # SEM settings are via the current hardware settings
        self.ebeam.dwellTime.value = self.ebeam.dwellTime.range[0]

        fs1 = stream.FluoStream("test orange", self.ccd, self.ccd.data,
                                self.light, self.light_filter)
        fs1.excitation.value = fs1.excitation.range[0] + 5e-9
        fs1.emission.value = fs1.emission.range[0] + 5e-9
        fs2 = stream.FluoStream("test blue", self.ccd, self.ccd.data,
                                self.light, self.light_filter)
        fs2.excitation.value = fs2.excitation.range[1] - 5e-9
        fs2.emission.value = fs2.emission.range[1] - 5e-9
        self.ccd.exposureTime.value = 0.1 # s

        ovrl = stream.OverlayStream("overlay", self.ccd, self.ebeam, self.sed)
        ovrl.dwellTime.value = 0.3
        ovrl.repetition.value = (7, 7)

        streams = [sems, fs1, fs2, ovrl]
        est_time = acq.estimateTime(streams)

        sum_est_time = sum(s.estimateAcquisitionTime() for s in streams)
        self.assertGreaterEqual(est_time, sum_est_time)

        # prepare callbacks
        self.past = None
        self.left = None
        self.updates = 0
        self.done = 0

        # Run acquisition
        start = time.time()
        f = acq.acquire(streams)
        f.add_update_callback(self.on_progress_update)
        f.add_done_callback(self.on_done)

        data = f.result()
        dur = time.time() - start
        self.assertGreater(dur, est_time / 2) # Estimated time shouldn't be too small

        self.assertIsInstance(data[0], model.DataArray)
        self.assertEqual(len(data), len(streams) - 1)

        # No overlay correction metadata anywhere (it has all been merged)
        for d in data:
            for k in [model.MD_ROTATION_COR, model.MD_PIXEL_SIZE_COR, model.MD_POS_COR]:
                self.assertNotIn(k, d.metadata)

#        thumb = acq.computeThumbnail(st, f)
#        self.assertIsInstance(thumb, model.DataArray)

        self.assertGreaterEqual(self.updates, 1) # at least one update at end
        self.assertEqual(self.left, 0)
        self.assertEqual(self.done, 1)
        self.assertTrue(not f.cancelled())
Пример #2
0
 def _create_overlay_stream(self, streams):
     for s in streams:
         if isinstance(s, EMStream):
             em_det = s.detector
             em_emt = s.emitter
         elif isinstance(s, stream.OpticalStream) and not isinstance(
                 s, stream.ScannedFluoStream):
             opt_det = s.detector
     main_data = self.main_app.main_data
     st = stream.OverlayStream("Fine alignment",
                               opt_det,
                               em_emt,
                               em_det,
                               opm=main_data.opm)
     st.dwellTime.value = main_data.fineAlignDwellTime.value
     return st
Пример #3
0
    def test_overlay_stream(self):
        # Create the stream
        ovrl = stream.OverlayStream("test overlay", self.ccd, self.ebeam, self.sed)

        ovrl.dwellTime.value = 0.3
        ovrl.repetition.value = (7, 7)

        f = ovrl.acquire()
        das = f.result()
        cor_md = das[0].metadata
        for k in [model.MD_ROTATION_COR, model.MD_PIXEL_SIZE_COR, model.MD_POS_COR]:
            self.assertIn(k, cor_md)

        # Try to cancel
        f = ovrl.acquire()
        time.sleep(1)
        f.cancel()
        self.assertTrue(f.cancelled())
Пример #4
0
    def __init__(self, parent, orig_tab_data):
        xrcfr_acq.__init__(self, parent)

        self.conf = get_acqui_conf()

        for n in presets:
            self.cmb_presets.Append(n)
        # TODO: record and reuse the preset used?
        self.cmb_presets.Select(0)

        self.filename = model.StringVA(create_filename(self.conf.last_path, self.conf.fn_ptn,
                                                       self.conf.last_extension, self.conf.fn_count))
        self.filename.subscribe(self._onFilename, init=True)

        # The name of the last file that got written to disk (used for auto viewing on close)
        self.last_saved_file = None
        
        # True when acquisition occurs
        self.acquiring = False

        # a ProgressiveFuture if the acquisition is going on
        self.acq_future = None
        self._acq_future_connector = None

        self._main_data_model = orig_tab_data.main

        # duplicate the interface, but with only one view
        self._tab_data_model = self.duplicate_tab_data_model(orig_tab_data)

        # Create a new settings controller for the acquisition dialog
        self._settings_controller = SecomSettingsController(
            self,
            self._tab_data_model,
            highlight_change=True  # also adds a "Reset" context menu
        )

        orig_view = orig_tab_data.focussedView.value
        self._view = self._tab_data_model.focussedView.value
        self._hidden_view = StreamView("Plugin View Hidden")

        self.streambar_controller = StreamBarController(self._tab_data_model,
                                                        self.pnl_secom_streams,
                                                        static=True,
                                                        ignore_view=True)
        # The streams currently displayed are the one visible
        self.add_all_streams()

        # The list of streams ready for acquisition (just used as a cache)
        self._acq_streams = {}

        # FIXME: pass the fold_panels

        # Compute the preset values for each preset
        self._preset_values = {}  # dict string -> dict (SettingEntries -> value)
        self._orig_entries = get_global_settings_entries(self._settings_controller)
        for sc in self.streambar_controller.stream_controllers:
            self._orig_entries += get_local_settings_entries(sc)
        self._orig_settings = preset_as_is(self._orig_entries)  # to detect changes
        for n, preset in presets.items():
            self._preset_values[n] = preset(self._orig_entries)
        # Presets which have been confirmed on the hardware
        self._presets_confirmed = set() # (string)

        self.start_listening_to_va()

        # If it could be possible to do fine alignment, allow the user to choose
        if self._can_fine_align(self._tab_data_model.streams.value):
            self.chkbox_fine_align.Show()
            # Set to True to make it the default, but will be automatically
            # disabled later if the current visible streams don't allow it.
            self.chkbox_fine_align.Value = True

            for s in self._tab_data_model.streams.value:
                if isinstance(s, EMStream):
                    em_det = s.detector
                    em_emt = s.emitter
                elif isinstance(s, OpticalStream) and not isinstance(s, ScannedFluoStream):
                    opt_det = s.detector
            self._ovrl_stream = stream.OverlayStream("Fine alignment", opt_det, em_emt, em_det,
                                                     opm=self._main_data_model.opm)
            self._ovrl_stream.dwellTime.value = self._main_data_model.fineAlignDwellTime.value
        else:
            self.chkbox_fine_align.Show(False)
            self.chkbox_fine_align.Value = False

        self._prev_fine_align = self.chkbox_fine_align.Value

        # make sure the view displays the same thing as the one we are
        # duplicating
        self._view.view_pos.value = orig_view.view_pos.value
        self._view.mpp.value = orig_view.mpp.value
        self._view.merge_ratio.value = orig_view.merge_ratio.value

        # attach the view to the viewport
        self.pnl_view_acq.canvas.fit_view_to_next_image = False
        self.pnl_view_acq.setView(self._view, self._tab_data_model)

        # The TOOL_ROA is not present because we don't allow the user to change
        # the ROA), so we need to explicitly request the canvas to show the ROA.
        if hasattr(self._tab_data_model, "roa") and self._tab_data_model.roa is not None:
            cnvs = self.pnl_view_acq.canvas
            self.roa_overlay = RepetitionSelectOverlay(cnvs, self._tab_data_model.roa,
                                                             self._tab_data_model.fovComp)
            cnvs.add_world_overlay(self.roa_overlay)

        self.Bind(wx.EVT_CHAR_HOOK, self.on_key)

        self.btn_cancel.Bind(wx.EVT_BUTTON, self.on_close)
        self.btn_change_file.Bind(wx.EVT_BUTTON, self.on_change_file)
        self.btn_secom_acquire.Bind(wx.EVT_BUTTON, self.on_acquire)
        self.cmb_presets.Bind(wx.EVT_COMBOBOX, self.on_preset)
        self.Bind(wx.EVT_CLOSE, self.on_close)
        # on_streams_changed is compatible because it doesn't use the args
        self.chkbox_fine_align.Bind(wx.EVT_CHECKBOX, self.on_streams_changed)

        self.on_preset(None) # will force setting the current preset

        # To update the estimated time when streams are removed/added
        self._view.stream_tree.flat.subscribe(self.on_streams_changed)
        self._hidden_view.stream_tree.flat.subscribe(self.on_streams_changed)
Пример #5
0
    def __init__(self, parent, orig_tab_data):
        xrcfr_acq.__init__(self, parent)

        self.conf = get_acqui_conf()

        for n in presets:
            self.cmb_presets.Append(n)
        # TODO: record and reuse the preset used?
        self.cmb_presets.Select(0)

        self.filename = model.StringVA(self._get_default_filename())
        self.filename.subscribe(self._onFilename, init=True)

        # The name of the last file that got written to disk (used for auto viewing on close)
        self.last_saved_file = None

        # a ProgressiveFuture if the acquisition is going on
        self.acq_future = None
        self._acq_future_connector = None

        self._main_data_model = orig_tab_data.main

        # duplicate the interface, but with only one view
        self._tab_data_model = self.duplicate_tab_data_model(orig_tab_data)

        # Create a new settings controller for the acquisition dialog
        self._settings_controller = SecomSettingsController(
            self,
            self._tab_data_model,
            highlight_change=True  # also adds a "Reset" context menu
        )

        # To turn on/off the fan
        self._orig_fan_speed = None
        self._orig_fan_temp = None

        orig_view = orig_tab_data.focussedView.value
        self._view = self._tab_data_model.focussedView.value

        self.streambar_controller = StreamBarController(
            self._tab_data_model, self.pnl_secom_streams)
        # The streams currently displayed are the one visible
        self.add_all_streams()

        # FIXME: pass the fold_panels

        # Compute the preset values for each preset
        self._preset_values = {
        }  # dict string -> dict (SettingEntries -> value)
        orig_entries = get_global_settings_entries(self._settings_controller)
        for sc in self.streambar_controller.stream_controllers:
            orig_entries += get_local_settings_entries(sc)
        self._orig_settings = preset_as_is(orig_entries)  # to detect changes
        for n, preset in presets.items():
            self._preset_values[n] = preset(orig_entries)
        # Presets which have been confirmed on the hardware
        self._presets_confirmed = set()  # (string)

        # If it could be possible to do fine alignment, allow the user to choose
        if self._can_fine_align(self._tab_data_model.streams.value):
            self.chkbox_fine_align.Show()
            # Set to True to make it the default, but will be automatically
            # disabled later if the current visible streams don't allow it.
            self.chkbox_fine_align.Value = True

            for s in self._tab_data_model.streams.value:
                if isinstance(s, EMStream):
                    em_det = s.detector
                    em_emt = s.emitter
                elif isinstance(s, OpticalStream):
                    opt_det = s.detector
            self._ovrl_stream = stream.OverlayStream("Fine alignment", opt_det,
                                                     em_emt, em_det)
            self._ovrl_stream.dwellTime.value = self._main_data_model.fineAlignDwellTime.value
        else:
            self.chkbox_fine_align.Show(False)
            self.chkbox_fine_align.Value = False

        self._prev_fine_align = self.chkbox_fine_align.Value

        # make sure the view displays the same thing as the one we are
        # duplicating
        self._view.view_pos.value = orig_view.view_pos.value
        self._view.mpp.value = orig_view.mpp.value
        self._view.merge_ratio.value = orig_view.merge_ratio.value

        # attach the view to the viewport
        self.pnl_view_acq.canvas.fit_view_to_next_image = False
        self.pnl_view_acq.setView(self._view, self._tab_data_model)

        self.Bind(wx.EVT_CHAR_HOOK, self.on_key)

        self.btn_cancel.Bind(wx.EVT_BUTTON, self.on_close)
        self.btn_change_file.Bind(wx.EVT_BUTTON, self.on_change_file)
        self.btn_secom_acquire.Bind(wx.EVT_BUTTON, self.on_acquire)
        self.cmb_presets.Bind(wx.EVT_COMBOBOX, self.on_preset)
        self.Bind(wx.EVT_CLOSE, self.on_close)
        # on_streams_changed is compatible because it doesn't use the args
        self.chkbox_fine_align.Bind(wx.EVT_CHECKBOX, self.on_streams_changed)

        self.on_preset(None)  # will force setting the current preset

        # TODO: use the presets VAs and subscribe to each of them, instead of
        # using pub/sub messages
        pub.subscribe(self.on_setting_change, 'setting.changed')

        # TODO: we should actually listen to the stream tree, but it's not
        # currently possible. => listen to .flat once it's there
        # Currently just use view.lastUpdate which should be "similar"
        # (but doesn't work if the stream contains no image)
        self._view.lastUpdate.subscribe(self.on_streams_changed)
Пример #6
0
    def __init__(self, parent, orig_tab_data):
        xrcfr_acq.__init__(self, parent)

        self.conf = get_acqui_conf()

        for n in presets:
            self.cmb_presets.Append(n)
        # TODO: record and reuse the preset used?
        self.cmb_presets.Select(0)

        self.filename = model.StringVA(self._get_default_filename())
        self.filename.subscribe(self._onFilename, init=True)

        # a ProgressiveFuture if the acquisition is going on
        self.acq_future = None
        self._acq_future_connector = None

        # duplicate the interface, but with only one view
        self._tab_data_model = self.duplicate_tab_data_model(orig_tab_data)

        # Create a new settings controller for the acquisition dialog
        self._settings_controller = SecomSettingsController(self,
                                                       self._tab_data_model,
                                                       highlight_change=True)
        # FIXME: pass the fold_panels

        # Compute the preset values for each preset
        self._preset_values = {} # dict string -> dict (SettingEntries -> value)
        orig_entries = self._settings_controller.entries
        self._orig_settings = preset_as_is(orig_entries) # to detect changes
        for n, preset in presets.items():
            self._preset_values[n] = preset(orig_entries)
        # Presets which have been confirmed on the hardware
        self._presets_confirmed = set() # (string)

        orig_view = orig_tab_data.focussedView.value
        view = self._tab_data_model.focussedView.value

        self.stream_controller = StreamController(self._tab_data_model,
                                                  self.pnl_secom_streams)
        # The streams currently displayed are the one visible
        self.add_all_streams(orig_view.getStreams())

        # If it could be possible to do fine alignment, allow the user to choose
        if self._can_fine_align(self._tab_data_model.streams.value):
            self.chkbox_fine_align.Show()
            # Set to True to make it the default, but will be automatically
            # disabled later if the current visible streams don't allow it.
            self.chkbox_fine_align.Value = True
            main_data = self._tab_data_model.main
            self._ovrl_stream = stream.OverlayStream("fine alignment", main_data.ccd,
                                         main_data.ebeam, main_data.sed)
            self._ovrl_stream.dwellTime.value = main_data.fineAlignDwellTime.value
        else:
            self.chkbox_fine_align.Show(False)
            self.chkbox_fine_align.Value = False

        self._prev_fine_align = self.chkbox_fine_align.Value

        # make sure the view displays the same thing as the one we are
        # duplicating
        view.view_pos.value = orig_view.view_pos.value
        view.mpp.value = orig_view.mpp.value
        view.merge_ratio.value = orig_view.merge_ratio.value

        # attach the view to the viewport
        self.pnl_view_acq.setView(view, self._tab_data_model)

        self.Bind(wx.EVT_CHAR_HOOK, self.on_key)

        self.btn_cancel.Bind(wx.EVT_BUTTON, self.on_close)
        self.btn_change_file.Bind(wx.EVT_BUTTON, self.on_change_file)
        self.btn_secom_acquire.Bind(wx.EVT_BUTTON, self.on_acquire)
        self.cmb_presets.Bind(wx.EVT_COMBOBOX, self.on_preset)
        self.Bind(wx.EVT_CLOSE, self.on_close)
        # on_streams_changed is compatible because it doesn't use the args
        self.chkbox_fine_align.Bind(wx.EVT_CHECKBOX, self.on_streams_changed)

        self.on_preset(None) # will force setting the current preset

        pub.subscribe(self.on_setting_change, 'setting.changed')
        # TODO: we should actually listen to the stream tree, but it's not
        # currently possible.
        # Currently just use view.last_update which should be "similar"
        view.lastUpdate.subscribe(self.on_streams_changed)
Пример #7
0
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()