Ejemplo n.º 1
0
    def run_calibration(self, calibration):
        """
        Run a calibration.
        """
        if calibration == Calibrations.OPTICAL_AUTOFOCUS:
            calibration.value.run(self._scanner, self._multibeam, self._descanner, self._detector,
                                  self._dataflow, self._ccd, self._stage)

        elif calibration == Calibrations.SCAN_ROTATION_PREALIGN:
            calibration.value.run(self._scanner, self._multibeam, self._descanner,
                                  self._detector, self._dataflow, self._ccd)

        elif calibration == Calibrations.DESCAN_GAIN_STATIC:
            calibration.value.run(self._scanner, self._multibeam, self._descanner,
                                  self._detector, self._dataflow, self._ccd)

        elif calibration == Calibrations.SCAN_AMPLITUDE_PREALIGN:
            s_offset, s_amplitude = calibration.value.run(self._scanner, self._multibeam, self._descanner,
                                                          self._detector, self._dataflow, self._ccd)
            self.asm_config["multibeam"]["scanOffset"] = s_offset
            self.asm_config["multibeam"]["scanAmplitude"] = s_amplitude

        elif calibration == Calibrations.IMAGE_ROTATION_PREALIGN:
            calibration.value.run(self._scanner, self._multibeam, self._descanner, self._detector,
                                  self._dataflow, self._ccd, self._det_rotator)

        elif calibration == Calibrations.IMAGE_TRANSLATION_PREALIGN:
            d_offset = calibration.value.run(self._scanner, self._multibeam, self._descanner,
                                             self._detector, self._dataflow, self._ccd)
            self.asm_config["descanner"]["scanOffset"] = d_offset

        elif calibration == Calibrations.IMAGE_ROTATION_FINAL:
            calibration.value.run(self._scanner, self._multibeam, self._descanner,
                                  self._detector, self._dataflow, self._det_rotator)

        elif calibration == Calibrations.IMAGE_TRANSLATION_FINAL:
            d_offset = calibration.value.run(self._scanner, self._multibeam, self._descanner,
                                             self._detector, self._dataflow, self._ccd)
            self.asm_config["descanner"]["scanOffset"] = d_offset

        elif calibration == Calibrations.DARK_OFFSET:
            dark_offset = calibration.value.run(self._scanner, self._multibeam, self._descanner,
                                                self._detector, self._dataflow)
            self.asm_config["mppc"]["cellDarkOffset"] = dark_offset

        elif calibration == Calibrations.DIGITAL_GAIN:
            digital_gain = calibration.value.run(self._scanner, self._multibeam, self._descanner,
                                                 self._detector, self._dataflow)
            self.asm_config["mppc"]["cellDigitalGain"] = digital_gain

        elif calibration == Calibrations.SCAN_ROTATION_FINAL:
            calibration.value.run(self._scanner, self._multibeam, self._descanner, self._detector, self._dataflow)

        elif calibration == Calibrations.SCAN_AMPLITUDE_FINAL:
            s_offset, s_amplitude = calibration.value.run(self._scanner, self._multibeam, self._descanner,
                                                          self._detector, self._dataflow)
            self.asm_config["multibeam"]["scanOffset"] = s_offset
            self.asm_config["multibeam"]["scanAmplitude"] = s_amplitude

        elif calibration == Calibrations.CELL_TRANSLATION:
            translation, resolution, cell_complete_resolution = calibration.value.run(self._scanner, self._multibeam,
                                                                                      self._descanner, self._detector,
                                                                                      self._dataflow,
                                                                                      plot_cell_translation=True)
            self.asm_config["mppc"]["cellTranslation"] = translation
            self.asm_config["multibeam"]["resolution"] = resolution
            self.asm_config["mppc"]["cellCompleteResolution"] = cell_complete_resolution

        else:
            raise ValueError(f"Unknown calibration {calibration.name}.")

        # TODO only needed for an acquisition -> move to acquisition code by reading the calibrated values
        #  from the respective MD (implement similar method to get_config_asm)
        configure_asm(self._multibeam, self._descanner, self._detector, self._dataflow, self.asm_config, upload=False)
Ejemplo n.º 2
0
    def run_calibrations(self, calibration):
        """
        Run a calibration.
        """
        if calibration == Calibrations.OPTICAL_AUTOFOCUS:
            autofocus_multiprobe.run_autofocus(self._scanner, self._multibeam, self._descanner, self._detector,
                                               self._dataflow, self._ccd, self._stage)
            configure_asm(self._multibeam, self._descanner, self._detector, self._dataflow, self.asm_config,
                          upload=False)

        elif calibration == Calibrations.SCAN_ROTATION_PREALIGN:
            scan_rotation_pre_align.run_scan_rotation_pre_align(self._scanner, self._multibeam, self._descanner,
                                                                self._detector, self._dataflow, self._ccd)
            configure_asm(self._multibeam, self._descanner, self._detector, self._dataflow, self.asm_config,
                          upload=False)

        elif calibration == Calibrations.SCAN_AMPLITUDE_PREALIGN:
            s_offset, s_amplitude = scan_amplitude_pre_align.run_scan_amplitude_pre_align(self._scanner,
                                                                                          self._multibeam,
                                                                                          self._descanner,
                                                                                          self._detector,
                                                                                          self._dataflow,
                                                                                          self._ccd)
            self.asm_config["multibeam"]["scanOffset"] = s_offset
            self.asm_config["multibeam"]["scanAmplitude"] = s_amplitude
            configure_asm(self._multibeam, self._descanner, self._detector, self._dataflow, self.asm_config,
                          upload=False)

        elif calibration == Calibrations.DESCAN_GAIN_STATIC:
            descan_gain.run_descan_gain_static(self._scanner, self._multibeam, self._descanner,
                                               self._detector, self._dataflow, self._ccd)
            configure_asm(self._multibeam, self._descanner, self._detector, self._dataflow, self.asm_config,
                          upload=False)

        elif calibration == Calibrations.IMAGE_ROTATION_PREALIGN:
            image_rotation_pre_align.run_image_rotation_pre_align(self._scanner, self._multibeam, self._descanner,
                                                                  self._detector, self._dataflow, self._ccd,
                                                                  self._det_rotator)
            configure_asm(self._multibeam, self._descanner, self._detector, self._dataflow, self.asm_config,
                          upload=False)

        elif calibration == Calibrations.IMAGE_TRANSLATION_PREALIGN:
            d_offset = image_translation_pre_align.run_image_translation_pre_align(self._scanner, self._multibeam,
                                                                                   self._descanner, self._detector,
                                                                                   self._dataflow, self._ccd)
            self.asm_config["descanner"]["scanOffset"] = d_offset
            configure_asm(self._multibeam, self._descanner, self._detector, self._dataflow, self.asm_config,
                          upload=False)

        elif calibration == Calibrations.IMAGE_ROTATION_FINAL:
            image_rotation.run_image_rotation(self._scanner, self._multibeam, self._descanner,
                                              self._detector, self._dataflow, self._det_rotator)
            configure_asm(self._multibeam, self._descanner, self._detector, self._dataflow, self.asm_config,
                          upload=False)

        elif calibration == Calibrations.IMAGE_TRANSLATION_FINAL:
            d_offset = image_translation.run_image_translation(self._scanner, self._multibeam, self._descanner,
                                                               self._detector, self._dataflow, self._ccd)
            self.asm_config["descanner"]["scanOffset"] = d_offset
            configure_asm(self._multibeam, self._descanner, self._detector, self._dataflow, self.asm_config,
                          upload=False)

        elif calibration == Calibrations.DARK_OFFSET:
            dark_offset = dark_offset_correction.run_dark_offset(self._scanner, self._multibeam, self._descanner,
                                                                 self._detector, self._dataflow)
            self.asm_config["mppc"]["cellDarkOffset"] = dark_offset
            configure_asm(self._multibeam, self._descanner, self._detector, self._dataflow, self.asm_config,
                          upload=False)

        elif calibration == Calibrations.DIGITAL_GAIN:
            digital_gain = digital_gain_correction.run_digital_gain(self._scanner, self._multibeam, self._descanner,
                                                                    self._detector, self._dataflow)
            self.asm_config["mppc"]["cellDigitalGain"] = digital_gain
            configure_asm(self._multibeam, self._descanner, self._detector, self._dataflow, self.asm_config,
                          upload=False)

        elif calibration == Calibrations.SCAN_ROTATION_FINAL:
            scan_rotation.run_scan_rotation(self._scanner, self._multibeam, self._descanner,
                                            self._detector, self._dataflow)
            configure_asm(self._multibeam, self._descanner, self._detector, self._dataflow, self.asm_config,
                          upload=False)

        elif calibration == Calibrations.SCAN_AMPLITUDE_FINAL:
            s_offset, s_amplitude = scan_amplitude.run_scan_amplitude(self._scanner, self._multibeam, self._descanner,
                                                                      self._detector, self._dataflow)
            self.asm_config["multibeam"]["scanOffset"] = s_offset
            self.asm_config["multibeam"]["scanAmplitude"] = s_amplitude
            configure_asm(self._multibeam, self._descanner, self._detector, self._dataflow, self.asm_config,
                          upload=False)

        elif calibration == Calibrations.CELL_TRANSLATION:
            translation = cell_translation.run_cell_translation(self._scanner, self._multibeam, self._descanner,
                                                                self._detector, self._dataflow,
                                                                plot_cell_translation=True)
            self.asm_config["mppc"]["cellTranslation"] = translation
            configure_asm(self._multibeam, self._descanner, self._detector, self._dataflow, self.asm_config,
                          upload=False)
Ejemplo n.º 3
0
    def run(self):
        """
        Runs a set of calibration procedures and return the calibrated settings.
        :returns:
            self.asm_config: (nested dict) A dictionary containing factory and/or calibrated settings. Settings
            that are calibrated or are overwriting factory settings. The content of the dict is:
            multibeam:
                scanOffset: (tuple) The x and y start of the scanning movement (start of scan ramp) of the multibeam
                            scanner in arbitrary units.
                scanAmplitude: (tuple) The x and y heights of the scan ramp of the multibeam scanner in arbitrary units.
                dwellTime: (float) The acquisition time for one pixel within a cell image in seconds.
                resolution: (tuple) The effective resolution of a single field image excluding overscanned pixels
                                    in pixels.
            descanner:
                scanOffset: (tuple) The x and y start of the scanning movement (start of scan ramp) of the descanner
                            in arbitrary units.
                scanAmplitude: (tuple) The x and y heights of the scan ramp of the descanner in arbitrary units.
            mppc:
                cellCompleteResolution: (tuple) The resolution of a cell image including overscanned pixels in pixels.
                cellTranslation: (tuple of tuples of shape mppc.shape) The origin for each cell image within the
                                 overscanned cell image in pixels.
                cellDarkOffset: (tuple of tuples of shape mppc.shape) The dark offset correction for each cell image.
                cellDigitalGain: (tuple of tuples of shape mppc.shape) The digital gain correction for each cell image.
        :raise:
            Exception: If a calibration failed.
            CancelledError: If the calibration was cancelled.
        """

        # Get the estimated time for all requested calibrations.
        total_calibration_time = self.estimate_calibration_time()

        # No need to set the start time of the future: it's automatically done when setting its state to running.
        self._future.set_progress(end=time.time() + total_calibration_time)  # provide end time to future
        logging.info("Starting calibrations, with expected duration of %f s", total_calibration_time)

        try:
            logging.debug("Starting calibration, reading initial hardware settings.")
            self.asm_config = get_config_asm(self._multibeam, self._descanner, self._detector)

            # reset beamshift
            self._beamshift.shift.value = (0, 0)

            if self.stage_pos:
                # move to region of calibration (ROC) position
                sf = self._stage.moveAbs({'x': self.stage_pos[0], 'y': self.stage_pos[1]})
                sf.result()  # wait until stage is at correct position

            # loop over calibrations in list (order in list is important!)
            for calib in self.calibrations:
                logging.debug("Starting calibration %s", calib)
                # TODO return a sub-future when implemented for calibrations
                self.run_calibration(calib)

                # def _pass_future_progress(sub_f, start, end):
                #     f.set_progress(start, end)

                # TODO Connect the progress of the sub-future to the main future when sub-futures are implemented
                # sf.add_update_callback(_pass_future_progress)
                # sf.result()

                # remove from set of calibrations when finished
                self._calibrations_remaining.discard(calib)

                # In case the calibrations were cancelled by a client, before the future returned,
                # raise cancellation error.
                if self._cancelled:
                    raise CancelledError()

                # Update the time left for the calibrations remaining
                self._future.set_progress(end=time.time() + self.estimate_calibration_time())
                logging.debug("Finished calibration %s successfully", calib)

        except CancelledError:
            logging.debug("Calibration was cancelled.")
            raise
        except Exception as ex:
            logging.error("Calibration failed: %s", ex, exc_info=True)
            raise
        finally:
            # Remove references to the calibrations once all calibrations are finished/cancelled.
            self._calibrations_remaining.clear()
            self._scanner.blanker.value = True  # always blank the beam to reduce beam damage on sample
            # put system back into state ready for next task and set calibrated settings
            if self.asm_config is None:
                logging.warning("Failed to retrieve asm configuration, configure_asm cannot be executed.")
            else:
                configure_asm(self._multibeam, self._descanner, self._detector, self._dataflow, self.asm_config)
            logging.debug("Calibrations finished.")

        return self.asm_config
Ejemplo n.º 4
0
    def pre_calibrate(self):
        """
        Run optical multiprobe autofocus and image translation pre-alignment before the ROA acquisition.
        The image translation pre-alignment adjusts the descanner.scanOffset VA such that the image of the
        multiprobe is roughly centered on the mppc detector. This function reads in the ASM configuration
        and makes sure all values, except the descanner offset, are set back after the calibrations are run.

        NOTE: Canceling is currently not supported.

        """
        if not fastem_calibrations:
            raise ModuleNotFoundError(
                "Need fastem_calibrations repository to run pre-calibrations.")

        asm_config = None

        try:
            logging.debug("Read initial Hw settings.")
            asm_config = configure_hw.get_config_asm(self._multibeam,
                                                     self._descanner,
                                                     self._detector)
            fastem_conf.configure_scanner(self._scanner,
                                          fastem_conf.MEGAFIELD_MODE)

            # Set the beamshift to zero before adjusting the descanner offset, this ensures that the maximum beamshift
            # range can be utilized when the pattern is centered on the mppc detector.
            self._beamshift.shift.value = (0, 0)

            # Autofocus multiprobe ensures the beams are focused at the start of the ROA acquisition.
            logging.debug("Running optical autofocus before ROA acquisition.")
            autofocus_multiprobe.run_autofocus(self._scanner, self._multibeam,
                                               self._descanner, self._detector,
                                               self._detector.data, self._ccd,
                                               self._stage)

            configure_hw.configure_asm(self._multibeam,
                                       self._descanner,
                                       self._detector,
                                       self._detector.data,
                                       asm_config,
                                       upload=False)
            # Image translation pre-alignment ensures that the image of the multiprobe is roughly centered on the
            # mppc detector.
            logging.debug(
                "Running image translation pre alignment before ROA acquisition."
            )
            descanner_offset = image_translation_pre_align.run_image_translation_pre_align(
                self._scanner, self._multibeam, self._descanner,
                self._detector, self._detector.data, self._ccd)

            # Set the descanner offset to the value calibrated with the image translation pre-alignment.
            asm_config["descanner"]["scanOffset"] = descanner_offset
            logging.debug(f"Descanner offset set to: {descanner_offset}")
            # Blank the beam to reduce beam damage on the sample.
            self._scanner.blanker.value = True

        except Exception as ex:
            logging.warning(
                "Exception during pre-calibration of the ROA acquisition.",
                exc_info=True)
            raise
        finally:
            # Blank the beam after the acquisition is done.
            self._scanner.blanker.value = True
            if asm_config is None:
                logging.warning(
                    "Failed to retrieve asm configuration, configure_asm cannot be executed."
                )
            else:
                # put system into state ready for next task
                # upload=False: it is enough to set calibrated values on HW during following acquisition
                configure_hw.configure_asm(self._multibeam,
                                           self._descanner,
                                           self._detector,
                                           self._detector.data,
                                           asm_config,
                                           upload=False)

            logging.debug("Finish pre-calibration.")