Beispiel #1
0
def DelphiCalibration(main_data, overview_pressure, vacuum_pressure,
                      vented_pressure):
    """
    Wrapper for DoDelphiCalibration. It provides the ability to check the
    progress of the procedure.
    main_data (odemis.gui.model.MainGUIData)
    overview_pressure (float): NavCam pressure value
    vacuum_pressure (float): Pressure under vacuum
    vented_pressure (float): Pressure when vented
    returns (ProgressiveFuture): Progress DoDelphiCalibration
    """
    # Create ProgressiveFuture and update its state to RUNNING
    est_start = time.time() + 0.1
    f = model.ProgressiveFuture(start=est_start,
                                end=est_start + estimateDelphiCalibration())
    f._delphi_calib_state = RUNNING

    # Task to run
    f.task_canceller = _CancelDelphiCalibration
    f._delphi_calib_lock = threading.Lock()

    # Run in separate thread
    delphi_calib_thread = threading.Thread(
        target=executeTask,
        name="Delphi Calibration",
        args=(f, _DoDelphiCalibration, f, main_data, overview_pressure,
              vacuum_pressure, vented_pressure))

    delphi_calib_thread.start()
    return f
Beispiel #2
0
    def save(self, dlg):
        """
        Stores the current CL data into a TIFF/HDF5 file
        """
        f = model.ProgressiveFuture()

        try:
            das = self._acquire(dlg, f)
        except CancelledError:
            logging.debug("Stopping acquisition + export, as it was cancelled")
            return
        except Exception as e:
            logging.exception("Failed to acquire CL data: %s", e)
            return

        fn = self.filename.value
        bn, ext = splitext(fn)
        if ext == ".png":
            logging.debug("Using HDF5 instead of PNG")
            fn = bn + ".h5"
        exporter = dataio.find_fittest_converter(fn)

        try:
            exporter.export(fn, das)
        except Exception:
            logging.exception("Failed to store data in %s", fn)

        f.set_result(None)  # Indicate it's over
        self._update_filename()
Beispiel #3
0
    def acquire(self, dlg):
        # ccd = self.main_data.ccd
        exp = self.exposureTime.value
        # ccd.exposureTime.value = exp

        f = model.ProgressiveFuture()
        f.task_canceller = lambda l: True  # To allow cancelling while it's running
        f.set_running_or_notify_cancel()  # Indicate the work is starting now
        dlg.showProgress(f)

        d = []
        for i in range(10):
            left = (10 - i) * exp
            f.set_progress(end=time.time() + left)
            # d.append(ccd.data.get())
            time.sleep(exp)
            if f.cancelled():
                return

        f.set_result(None)  # Indicate it's over

        if d:
            dataio.hdf5.export(self.filename.value, d)

        dlg.Destroy()
Beispiel #4
0
def acquire(streams, settings_obs=None):
    """ Start an acquisition task for the given streams.

    It will decide in which order the stream must be acquired.

    ..Note:
        It is highly recommended to not have any other acquisition going on.

    :param streams: [Stream] the streams to acquire
    :param settings_obs: [SettingsObserver or None] class that contains a list of all VAs
        that should be saved as metadata
    :return: (ProgressiveFuture) an object that represents the task, allow to
        know how much time before it is over and to cancel it. It also permits
        to receive the result of the task, which is a tuple:
            (list of model.DataArray): the raw acquisition data
            (Exception or None): exception raised during the acquisition
    """

    # create a future
    future = model.ProgressiveFuture()

    # create a task
    task = AcquisitionTask(streams, future, settings_obs)
    future.task_canceller = task.cancel  # let the future cancel the task

    # connect the future to the task and run in a thread
    executeAsyncTask(future, task.run)

    # return the interface to manipulate the task
    return future
Beispiel #5
0
def acquire(roa, path, multibeam, descanner, detector, stage):
    """
    Start a megafield acquisition task for a given region of acquisition (ROA).

    :param roa: (FastEMROA) The acquisition region object to be acquired (megafield).
    :param path: (str) Path on the external storage where the image data is stored. Here, it is possible
                to specify sub-directories (such as acquisition date and project name) additional to the main
                path as specified in the component.
                The ASM will create the directory on the external storage, including the parent directories,
                if they do not exist.
    :param multibeam: (technolution.EBeamScanner) The multibeam scanner component of the acquisition server module.
    :param descanner: (technolution.MirrorDescanner) The mirror descanner component of the acquisition server module.
    :param detector: (technolution.MPPC) The detector object to be used for collecting the image data.
    :param stage: (actuator.ConvertStage) The stage in the corrected scan coordinate system, the x and y axes are
        aligned with the x and y axes of the multiprobe and the multibeam scanner.

    :return: (ProgressiveFuture) Acquisition future object, which can be cancelled. The result of the future is
             a tuple that contains:
                (model.DataArray): The acquisition data, which depends on the value of the detector.dataContent VA.
                (Exception or None): Exception raised during the acquisition or None.
    """
    f = model.ProgressiveFuture()

    # TODO: pass path through attribute on ROA instead of argument?
    # Create a task that acquires the megafield image.
    task = AcquisitionTask(multibeam, descanner, detector, stage, roa, path, f)

    f.task_canceller = task.cancel  # lets the future know how to cancel the task.

    # Connect the future to the task and run it in a thread.
    # task.run is executed by the executor and runs as soon as no other task is executed
    _executor.submitf(f, task.run)

    return f
Beispiel #6
0
def AlignSpot(ccd, stage, escan, focus, type=OBJECTIVE_MOVE, dfbkg=None, rng_f=None):
    """
    Wrapper for DoAlignSpot. It provides the ability to check the progress of
    spot mode procedure or even cancel it.
    ccd (model.DigitalCamera): The CCD
    stage (model.Actuator): The stage
    escan (model.Emitter): The e-beam scanner
    focus (model.Actuator): The optical focus
    type (string): Type of move in order to align
    dfbkg (model.DataFlow): dataflow of se- or bs- detector for background
      subtraction
    rng_f (tuple of floats): range to apply Autofocus on if needed
    returns (model.ProgressiveFuture):    Progress of DoAlignSpot,
                                         whose result() will return:
            returns (float):    Final distance to the center (m)
    """
    # Create ProgressiveFuture and update its state to RUNNING
    est_start = time.time() + 0.1
    f = model.ProgressiveFuture(start=est_start,
                                end=est_start + estimateAlignmentTime(ccd.exposureTime.value))
    f._task_state = RUNNING

    # Task to run
    f.task_canceller = _CancelAlignSpot
    f._alignment_lock = threading.Lock()
    f._done = threading.Event()

    # Create autofocus and centerspot module
    f._autofocusf = model.InstantaneousFuture()
    f._centerspotf = model.InstantaneousFuture()

    # Run in separate thread
    executeAsyncTask(f, _DoAlignSpot,
                     args=(f, ccd, stage, escan, focus, type, dfbkg, rng_f))
    return f
Beispiel #7
0
def acquire(streams):
    """ Start an acquisition task for the given streams.

    It will decide in which order the stream must be acquired.

    ..Note:
        It is highly recommended to not have any other acquisition going on.

    :param streams: [Stream] the streams to acquire
    :return: (ProgressiveFuture) an object that represents the task, allow to
        know how much time before it is over and to cancel it. It also permits
        to receive the result of the task, which is:
        (list of model.DataArray): the raw acquisition data

    """

    # create a future
    future = model.ProgressiveFuture()

    # create a task
    task = AcquisitionTask(streams, future)
    future.task_canceller = task.cancel  # let the future cancel the task

    # run executeTask in a thread
    thread = threading.Thread(target=_futures.executeTask,
                              name="Acquisition task",
                              args=(future, task.run))
    thread.start()

    # return the interface to manipulate the task
    return future
Beispiel #8
0
def CenterSpot(ccd, stage, escan, mx_steps, type=OBJECTIVE_MOVE, dfbkg=None):
    """
    Wrapper for _DoCenterSpot.
    ccd (model.DigitalCamera): The CCD
    stage (model.Actuator): The stage
    escan (model.Emitter): The e-beam scanner
    mx_steps (int): Maximum number of steps to reach the center
    type (*_MOVE or BEAM_SHIFT): Type of move in order to align
    dfbkg (model.DataFlow or None): If provided, will be used to start/stop
     the e-beam emission (it must be the dataflow of se- or bs-detector) in
     order to do background subtraction. If None, no background subtraction is
     performed.
    returns (model.ProgressiveFuture):    Progress of _DoCenterSpot,
                                         whose result() will return:
                (float):    Final distance to the center #m
                (2 floats): vector to the spot from the center (m, m)
    """
    # Create ProgressiveFuture and update its state to RUNNING
    est_start = time.time() + 0.1
    f = model.ProgressiveFuture(start=est_start,
                                end=est_start + estimateCenterTime(ccd.exposureTime.value))
    f._spot_center_state = RUNNING
    f.task_canceller = _CancelCenterSpot
    f._center_lock = threading.Lock()

    # Run in separate thread
    executeAsyncTask(f, _DoCenterSpot,
                     args=(f, ccd, stage, escan, mx_steps, type, dfbkg))
    return f
Beispiel #9
0
def align(main_data):
    """
    :param main_data (odemis.gui.model.FastEMMainGUIData):
    :returns: (ProgressiveFuture): acquisition future
    """
    f = model.ProgressiveFuture()
    _executor.submitf(f, _run_fake_alignment)
    return f
Beispiel #10
0
    def acquire(self, dlg):
        main_data = self.main_app.main_data
        str_ctrl = main_data.tab.value.streambar_controller
        stream_paused = str_ctrl.pauseStreams()
        dlg.pauseSettings()

        nb = self.numberOfAcquisitions.value
        p = self.period.value
        ss, last_ss = self._get_acq_streams()

        fn = self.filename.value
        exporter = dataio.find_fittest_converter(fn)
        bs, ext = splitext(fn)
        fn_pat = bs + "-%.5d" + ext

        sacqt = acq.estimateTime(ss)
        intp = max(0, p - sacqt)
        if p < sacqt:
            logging.warning(
                "Acquisition will take %g s, but period between acquisition must be only %g s",
                sacqt, p
            )

        # TODO: if drift correction, use it over all the time

        f = model.ProgressiveFuture()
        f.task_canceller = lambda l: True  # To allow cancelling while it's running
        f.set_running_or_notify_cancel()  # Indicate the work is starting now
        dlg.showProgress(f)

        for i in range(nb):
            left = nb - i
            dur = sacqt * left + intp * (left - 1)
            if left == 1 and last_ss:
                ss += last_ss
                dur += acq.estimateTime(ss) - sacqt

            startt = time.time()
            f.set_progress(end=startt + dur)
            das, e = acq.acquire(ss).result()
            if f.cancelled():
                dlg.resumeSettings()
                return

            exporter.export(fn_pat % (i,), das)

            # Wait the period requested, excepted the last time
            if left > 1:
                sleept = (startt + p) - time.time()
                if sleept > 0:
                    time.sleep(sleept)
                else:
                    logging.info("Immediately starting next acquisition, %g s late", -sleept)

        f.set_result(None)  # Indicate it's over

        # self.showAcquisition(self.filename.value)
        dlg.Close()
Beispiel #11
0
    def _fast_acquire_one(self, dlg, st, last_ss):
        """
        Acquires one stream, *as fast as possible* (ie, the period is not used).
        Only works with LiveStreams (and not with MDStreams)
        st (LiveStream)
        last_ss (list of Streams): all the streams to be acquire on the last time
        """
        # Essentially, we trick a little bit the stream, by convincing it that
        # we want a live view, but instead of display the data, we store them.
        # It's much faster because we don't have to stop/start the detector between
        # each acquisition.
        nb = self.numberOfAcquisitions.value

        fn = self.filename.value
        self._exporter = dataio.find_fittest_converter(fn)
        bs, ext = splitext(fn)
        fn_pat = bs + "-%.5d" + ext

        self._acq_completed = threading.Event()

        f = model.ProgressiveFuture()
        f.task_canceller = self._cancel_fast_acquire
        f._stream = st
        if last_ss:
            nb -= 1
            extra_dur = acq.estimateTime([st] + last_ss)
        else:
            extra_dur = 0
        self._hijack_live_stream(st, f, nb, fn_pat, extra_dur)

        try:
            # Start acquisition and wait until it's done
            f.set_running_or_notify_cancel(
            )  # Indicate the work is starting now
            dlg.showProgress(f)
            st.is_active.value = True
            self._acq_completed.wait()

            if f.cancelled():
                dlg.resumeSettings()
                return
        finally:
            st.is_active.value = False  # just to be extra sure it's stopped
            logging.debug("Restoring stream %s", st)
            self._restore_live_stream(st)

        # last "normal" acquisition, if needed
        if last_ss:
            logging.debug("Acquiring last acquisition, with all the streams")
            ss = [st] + last_ss
            f.set_progress(end=time.time() + acq.estimateTime(ss))
            das, e = acq.acquire(
                ss, self.main_app.main_data.settings_obs).result()
            self._save_data(fn_pat % (nb, ), das)

        self._stop_saving_threads()  # Wait for all the data to be stored
        f.set_result(None)  # Indicate it's over
Beispiel #12
0
def AutoFocusSpectrometer(spectrograph, focuser, detectors, selector=None):
    """
    Run autofocus for a spectrograph. It will actually run autofocus on each
    gratings, and for each detectors. The input slit should already be in a
    good position (typically, almost closed), and a light source should be
    active.
    Note: it's currently tailored to the Andor Shamrock SR-193i. It's recommended
    to put the detector on the "direct" output as first detector.
    spectrograph (Actuator): should have grating and wavelength.
    focuser (Actuator): should have a z axis
    detectors (Detector or list of Detectors): all the detectors available on
      the spectrometer. The first detector will be used to autofocus all the
      gratings, and each other detector will be focused with the original
      grating.
    selector (Actuator or None): must have a rx axis with each position corresponding
     to one of the detectors. If there is only one detector, selector can be None.
    return (ProgressiveFuture -> dict((grating, detector)->focus position)): a progressive future
      which will eventually return a map of grating/detector -> focus position.
    """
    if not isinstance(detectors, collections.Iterable):
        detectors = [detectors]
    if not detectors:
        raise ValueError("At least one detector must be provided")
    if len(detectors) > 1 and selector is None:
        raise ValueError("No selector provided, but multiple detectors")

    # Create ProgressiveFuture and update its state to RUNNING
    est_start = time.time() + 0.1
    detector = detectors[0]
    if model.hasVA(detector, "exposureTime"):
        et = detector.exposureTime.value
    else:
        # Completely random... but we are in a case where probably that's the last
        # thing the caller will care about.
        et = 1

    # 1 time / grating + 1 time / extra detector
    cnts = len(spectrograph.axes["grating"].choices) + (len(detectors) - 1)
    f = model.ProgressiveFuture(start=est_start,
                                end=est_start +
                                cnts * estimateAutoFocusTime(et))
    f.task_canceller = _CancelAutoFocusSpectrometer
    # Extra info for the canceller
    f._autofocus_state = RUNNING
    f._autofocus_lock = threading.Lock()
    f._subfuture = InstantaneousFuture()

    # Run in separate thread
    autofocus_thread = threading.Thread(target=executeTask,
                                        name="Spectrometer Autofocus",
                                        args=(f, _DoAutoFocusSpectrometer, f,
                                              spectrograph, focuser, detectors,
                                              selector))

    autofocus_thread.start()
    return f
Beispiel #13
0
def acquire(roa, path):
    """
    :param roa: (FastEMROA) acquisition region to be acquired
    :param path: (str) path and filename of the acquisition on the server
    :returns: (ProgressiveFuture): acquisition future
    """
    # TODO: pass path through attribute on ROA instead of second argument?
    f = model.ProgressiveFuture()
    _executor.submitf(f, _run_fake_acquisition)
    return f
Beispiel #14
0
def acquireTiledArea(streams,
                     stage,
                     area,
                     overlap=0.2,
                     settings_obs=None,
                     log_path=None,
                     zlevels=None,
                     registrar=REGISTER_GLOBAL_SHIFT,
                     weaver=WEAVER_MEAN):
    """
    Start a tiled acquisition task for the given streams (SEM or FM) in order to
    build a complete view of the TEM grid. Needed tiles are first acquired for
    each stream, then the complete view is created by stitching the tiles.

    :param streams: (Stream) the streams to acquire
    :param stage: (Actuator) the sample stage to move to the possible tiles locations
    :param area: (float, float, float, float) left, top, right, bottom points of acquisition area
    :param overlap: (float) the amount of overlap between each acquisition
    :param settings_obs: (SettingsObserver or None) class that contains a list of all VAs
        that should be saved as metadata
    :param log_path: (string) directory and filename pattern to save acquired images for debugging
    :param zlevels: (list(float) or None) focus z positions required zstack acquisition
    :return: (ProgressiveFuture) an object that represents the task, allow to
        know how much time before it is over and to cancel it. It also permits
        to receive the result of the task, which is a list of model.DataArray:
        the stitched acquired tiles data
    """
    # Create a progressive future with running sub future
    future = model.ProgressiveFuture()
    future.running_subf = model.InstantaneousFuture()
    future._task_lock = threading.Lock()
    # Create a tiled acquisition task
    task = TiledAcquisitionTask(streams,
                                stage,
                                area,
                                overlap,
                                settings_obs,
                                log_path,
                                future=future,
                                zlevels=zlevels,
                                registrar=registrar,
                                weaver=weaver)
    future.task_canceller = task._cancelAcquisition  # let the future cancel the task
    # Estimate memory and check if it's sufficient to decide on running the task
    mem_sufficient, mem_est = task.estimateMemory()
    if not mem_sufficient:
        raise IOError(
            "Not enough RAM to safely acquire the overview: %g GB needed" %
            (mem_est / 1024**3, ))

    future.set_progress(end=task.estimateTime() + time.time())
    # connect the future to the task and run in a thread
    executeAsyncTask(future, task.run)

    return future
Beispiel #15
0
def acquire(roa,
            path,
            scanner,
            multibeam,
            descanner,
            detector,
            stage,
            ccd,
            beamshift,
            lens,
            pre_calibrations=None):
    """
    Start a megafield acquisition task for a given region of acquisition (ROA).

    :param roa: (FastEMROA) The acquisition region object to be acquired (megafield).
    :param path: (str) Path on the external storage where the image data is stored. Here, it is possible
                to specify sub-directories (such as acquisition date and project name) additional to the main
                path as specified in the component.
                The ASM will create the directory on the external storage, including the parent directories,
                if they do not exist.
    :param scanner: (xt_client.Scanner) Scanner component connecting to the XT adapter.
    :param multibeam: (technolution.EBeamScanner) The multibeam scanner component of the acquisition server module.
    :param descanner: (technolution.MirrorDescanner) The mirror descanner component of the acquisition server module.
    :param detector: (technolution.MPPC) The detector object to be used for collecting the image data.
    :param stage: (actuator.ConvertStage) The stage in the sample carrier coordinate system. The x and y axes are
        aligned with the x and y axes of the ebeam scanner.
        FIXME use: The stage in the corrected scan coordinate system, the x and y axes are
            aligned with the x and y axes of the multiprobe and the multibeam scanner.
    :param ccd: (model.DigitalCamera) A camera object of the diagnostic camera.
    :param beamshift: (tfsbc.BeamShiftController) Component that controls the beamshift deflection.
    :param lens: (static.OpticalLens) Optical lens component.
    :param pre_calibrations: (list[Calibrations]) List of calibrations that should be run before the ROA acquisition.
                             Default is None.

    :return: (ProgressiveFuture) Acquisition future object, which can be cancelled. The result of the future is
             a tuple that contains:
                (model.DataArray): The acquisition data, which depends on the value of the detector.dataContent VA.
                (Exception or None): Exception raised during the acquisition or None.
    """

    est_dur = estimate_acquisition_time(roa, pre_calibrations)
    f = model.ProgressiveFuture(start=time.time(), end=time.time() + est_dur)

    # TODO: pass path through attribute on ROA instead of argument?
    # Create a task that acquires the megafield image.
    task = AcquisitionTask(scanner, multibeam, descanner, detector, stage, ccd,
                           beamshift, lens, roa, path, pre_calibrations, f)

    f.task_canceller = task.cancel  # lets the future know how to cancel the task.

    # Connect the future to the task and run it in a thread.
    # task.run is executed by the executor and runs as soon as no other task is executed
    _executor.submitf(f, task.run)

    return f
Beispiel #16
0
def SEMCCDAcquisition(escan, ccd, detector, light):
    f = model.ProgressiveFuture()
    f._acq_state = RUNNING

    # Task to run
    doAcquisition = _DoAcquisition
    f.task_canceller = _CancelAcquisition

    # Run in separate thread
    executeAsyncTask(f, doAcquisition, args=(f, escan, ccd, detector, light))
    return f
Beispiel #17
0
    def moveAbs(self, pos):
        if not pos:
            return model.InstantaneousFuture()
        self._checkMoveAbs(pos)

        new_pres = pos["pressure"]
        est_start = time.time() + 0.1
        f = model.ProgressiveFuture(start=est_start,
                                    end=est_start + self._getDuration(new_pres))

        return self._executor.submitf(f, self._changePressure, f, new_pres)
Beispiel #18
0
    def do_progressive_long(self, duration=5):
        """
        return a ProgressiveFuture, which will have the estimated time shorten
        """
        # First estimate the time to 10s, and then it will be shorten
        start = time.time() + 1
        end = start + 10
        f = model.ProgressiveFuture(start, end)

        # run in a separate thread
        executeAsyncTask(f, self._long_pessimistic_task, args=(f, duration))
        return f
Beispiel #19
0
def acquireTiledArea(stream, stage, area, live_stream=None):
    """
    :param stream: (SEMStream) Stream used for the acquisition.
     It must have the detector and emitter connected to the TFS XT client detector and scanner.
     It should be in focus.
     It must NOT have the following local VAs: horizontalFoV. resolution, scale
      (because the VAs of the hardware will be changed directly, and so they shouldn’t be changed by the stream).
    :param stage: (Actuator). It should have axes "x" and "y", which should already be referenced.
    :param area: (float, float, float, float) minx, miny, maxx, maxy:  coordinates of the overview region
    :param live_stream: (StaticStream or None): StaticStream to be updated with
       each tile acquired, to build up live the whole acquisition. NOT SUPPORTED YET.
    : return: (ProgressiveFuture), acquisition future. It returns the complete DataArray.
    """
    # Check the parameters
    if len(area) != 4:
        raise ValueError("area should be 4 float, but got %r" % (area, ))

    for vaname in ("horizontalFoV", "resolution", "scale"):
        if vaname in stream.emt_vas:
            raise ValueError("Stream shouldn't have its own VA %s" %
                             (vaname, ))

    if set(stage.axes) < {"x", "y"}:
        raise ValueError("Stage needs axes x and y, but has %s" %
                         (stage.axes.keys(), ))
    if model.hasVA(stage, "referenced"):
        refd = stage.referenced.value
        for a in ("x", "y"):
            if a in refd:
                if not refd[a]:
                    raise ValueError(
                        "Stage axis '%s' is not referenced. Reference it first"
                        % (a, ))
            else:
                logging.warning(
                    "Going to use the stage in absolute mode, but it doesn't report %s in .referenced VA",
                    a)

    else:
        logging.warning(
            "Going to use the stage in absolute mode, but it doesn't have .referenced VA"
        )

    if live_stream:
        raise NotImplementedError("live_stream not supported")

    est_dur = estimateTiledAcquisitionTime(stream, stage, area)
    f = model.ProgressiveFuture(start=time.time(), end=time.time() + est_dur)
    _executor.submitf(f, _run_overview_acquisition, f, stream, stage, area,
                      live_stream)

    return f
Beispiel #20
0
def FindOverlay(repetitions,
                dwell_time,
                max_allowed_diff,
                escan,
                ccd,
                detector,
                skew=False,
                bgsub=False):
    """
    Wrapper for DoFindOverlay. It provides the ability to check the progress of overlay procedure
    or even cancel it.
    repetitions (tuple of ints): The number of CL spots are used
    dwell_time (float): Time to scan each spot #s
    max_allowed_diff (float): Maximum allowed difference in electron coordinates #m
    escan (model.Emitter): The e-beam scanner
    ccd (model.DigitalCamera): The CCD
    detector (model.Detector): The electron detector
    skew (boolean): If True, also compute skew
    bgsub (boolean): If True, apply background substraction in grid scanning
    returns (model.ProgressiveFuture): Progress of DoFindOverlay, whose result() will return:
            tuple: Transformation parameters
                translation (Tuple of 2 floats)
                scaling (Float)
                rotation (Float)
            dict : Transformation metadata
    """
    # Create ProgressiveFuture and update its state to RUNNING
    est_start = time.time() + 0.1
    f = model.ProgressiveFuture(start=est_start,
                                end=est_start +
                                estimateOverlayTime(dwell_time, repetitions))
    f._find_overlay_state = RUNNING

    # Task to run
    f.task_canceller = _CancelFindOverlay
    f._overlay_lock = threading.Lock()
    f._done = threading.Event()

    # Create scanner for scan grid
    f._scanner = GridScanner(repetitions, dwell_time, escan, ccd, detector,
                             bgsub)

    # Run in separate thread
    overlay_thread = threading.Thread(target=executeTask,
                                      name="SEM/CCD overlay",
                                      args=(f, _DoFindOverlay, f, repetitions,
                                            dwell_time, max_allowed_diff,
                                            escan, ccd, detector, skew))

    overlay_thread.start()
    return f
Beispiel #21
0
def acquireTiledArea(streams,
                     stage,
                     area,
                     overlap=0.2,
                     settings_obs=None,
                     log_path=None,
                     zlevels=None,
                     registrar=REGISTER_GLOBAL_SHIFT,
                     weaver=WEAVER_MEAN,
                     focusing_method=FocusingMethod.NONE):
    """
    Start a tiled acquisition task for the given streams (SEM or FM) in order to
    build a complete view of the TEM grid. Needed tiles are first acquired for
    each stream, then the complete view is created by stitching the tiles.

    Parameters are the same as for TiledAcquisitionTask
    :return: (ProgressiveFuture) an object that represents the task, allow to
        know how much time before it is over and to cancel it. It also permits
        to receive the result of the task, which is a list of model.DataArray:
        the stitched acquired tiles data
    """
    # Create a progressive future with running sub future
    future = model.ProgressiveFuture()
    future.running_subf = model.InstantaneousFuture()
    future._task_lock = threading.Lock()
    # Create a tiled acquisition task
    task = TiledAcquisitionTask(streams,
                                stage,
                                area,
                                overlap,
                                settings_obs,
                                log_path,
                                future=future,
                                zlevels=zlevels,
                                registrar=registrar,
                                weaver=weaver,
                                focusing_method=focusing_method)
    future.task_canceller = task._cancelAcquisition  # let the future cancel the task
    # Estimate memory and check if it's sufficient to decide on running the task
    mem_sufficient, mem_est = task.estimateMemory()
    if not mem_sufficient:
        raise IOError(
            "Not enough RAM to safely acquire the overview: %g GB needed" %
            (mem_est / 1024**3, ))

    future.set_progress(end=task.estimateTime() + time.time())
    # connect the future to the task and run in a thread
    executeAsyncTask(future, task.run)

    return future
Beispiel #22
0
    def acquire(self):
        """
        Runs the acquisition
        returns Future that will have as a result a DataArray with the 3D data
        """
        # Make sure the stream is prepared (= optical path set)
        # TODO: move the optical path change done in the plugin.acquire() to here
        # self.prepare().result()

        # Hard coded optical path (as the OPM doesn't know about this special mode)
        logging.info("Preparing optical path")
        # Configure the optical path for the CCD we need
        mvs = self._opm.selectorsToPath(self._detector.name)
        # On Odemis 2.9-, mvs is just a list of futures
        # On Odemis 2.10+, mvs is a list of tuples(future, comp, pos) => only keep the futures
        fs = [m[0] if isinstance(m, tuple) else m for m in mvs]
        # move lens 2 into position
        for p, n in self._lsw.axes["x"].choices.items():
            if n == "on":
                f = self._lsw.moveAbs({"x": p})
                fs.append(f)
                break

        # move big slit into position
        for p, n in self._bigslit.axes["x"].choices.items():
            if n == "off":
                f = self._bigslit.moveAbs({"x": p})
                fs.append(f)
                break

        # wait for all the moves to be over
        for f in fs:
            f.result()

        logging.debug("Optical path configured")

        est_start = time.time() + 0.1
        # Create a "Future", which is an object that can be used to follow the
        # task completion while it's going on, and get the result.
        f = model.ProgressiveFuture(start=est_start,
                                    end=est_start +
                                    self.estimateAcquisitionTime())
        f.task_canceller = self._cancelAcquisition
        f._acq_state = RUNNING
        f._acq_lock = threading.Lock()
        f._acq_done = threading.Event()

        # run task in separate thread
        executeAsyncTask(f, self._runAcquisition, args=(f, ))
        return f
Beispiel #23
0
def SEMCCDAcquisition(escan, ccd, detector, light):
    f = model.ProgressiveFuture()
    f._acq_state = RUNNING

    # Task to run
    doAcquisition = _DoAcquisition
    f.task_canceller = _CancelAcquisition

    # Run in separate thread
    acq_thread = threading.Thread(target=_executeTask,
                  name="SEMCCDAcquisition",
                  args=(f, doAcquisition, f, escan, ccd, detector, light))

    acq_thread.start()
    return f
Beispiel #24
0
    def do_progressive_long(self, duration=5):
        """
        return a ProgressiveFuture, which will have the estimated time shorten
        """
        # First estimate the time to 10s, and then it will be shorten
        start = time.time() + 1
        end = start + 10
        f = model.ProgressiveFuture(start, end)

        # run executeTask in a thread
        thread = threading.Thread(target=executeTask,
                                  name="Long task",
                                  args=(f, self._long_pessimistic_task, f,
                                        duration))
        thread.start()
        return f
    def test_pf_connector(self):
        """
        Test ProgressiveFutureConnector
        """
        # Add a gauge (progress bar) and label for testing
        gauge = wx.Gauge(self.panel)
        stxt = wx.StaticText(self.panel)
        self.add_control(gauge, flags=wx.EXPAND | wx.ALL)
        self.add_control(stxt, flags=wx.EXPAND | wx.ALL)

        test.gui_loop(0.2)

        # Create the ProgressiveFuture
        now = time.time()
        pf = model.ProgressiveFuture(now, now + 60)  # one min
        # future.task_canceller = self.cancel_task

        # Create the connector
        pfc = widgets.ProgressiveFutureConnector(pf, bar=gauge, label=stxt)
        test.gui_loop(0.3)  # need to wait at least 0.25 s

        # Check ratio at beginning
        r1 = gauge.Value / gauge.Range
        self.assertLessEqual(r1, 0.1)
        self.assertGreater(len(stxt.LabelText), 6)

        # wait 2 s and see if the progress increased
        test.gui_loop(2)
        r2 = gauge.Value / gauge.Range
        self.assertGreater(r2, r1)

        # Make it look a lot longer => should update backwards
        pf.set_progress(end=now + 120)
        test.gui_loop(0.3)  # need to wait at least 0.25 s
        r3 = gauge.Value / gauge.Range
        self.assertLess(r3, r2)

        # wait 2 s and see if the progress increased
        test.gui_loop(2)
        r4 = gauge.Value / gauge.Range
        self.assertGreater(r4, r3)

        # Make it look a little longer => should not update
        pf.set_progress(end=now + 121)
        test.gui_loop(0.3)  # need to wait at least 0.25 s
        r5 = gauge.Value / gauge.Range
        self.assertEqual(r5, r4)
Beispiel #26
0
def AlignSpot(ccd,
              stage,
              escan,
              focus,
              type=OBJECTIVE_MOVE,
              background=False,
              dataflow=None):
    """
    Wrapper for DoAlignSpot. It provides the ability to check the progress of
    spot mode procedure or even cancel it.
    ccd (model.DigitalCamera): The CCD
    stage (model.Actuator): The stage
    escan (model.Emitter): The e-beam scanner
    focus (model.Actuator): The optical focus
    type (string): Type of move in order to align
    background (boolean): If True apply background substraction
    dataflow (model.DataFlow): dataflow of se- or bs- detector
    returns (model.ProgressiveFuture):    Progress of DoAlignSpot,
                                         whose result() will return:
            returns (float):    Final distance to the center #m 
    """
    # Create ProgressiveFuture and update its state to RUNNING
    est_start = time.time() + 0.1
    f = model.ProgressiveFuture(start=est_start,
                                end=est_start +
                                estimateAlignmentTime(ccd.exposureTime.value))
    f._spot_alignment_state = RUNNING

    # Task to run
    f.task_canceller = _CancelAlignSpot
    f._alignment_lock = threading.Lock()
    f._done = threading.Event()

    # Create autofocus and centerspot module
    f._autofocusf = model.InstantaneousFuture()
    f._centerspotf = model.InstantaneousFuture()

    # Run in separate thread
    alignment_thread = threading.Thread(target=executeTask,
                                        name="Spot alignment",
                                        args=(f, _DoAlignSpot, f, ccd, stage,
                                              escan, focus, type, background,
                                              dataflow))

    alignment_thread.start()
    return f
    def acquire(self):
        """
        Runs the acquisition
        returns Future that will have as a result a DataArray with the spectrum
        """
        est_start = time.time() + 0.1
        f = model.ProgressiveFuture(start=est_start,
                                    end=est_start + self.estimateAcquisitionTime())
        f.task_canceller = self._cancelAcquisition
        f._acq_state = RUNNING
        f._acq_lock = threading.Lock()
        f._acq_done = threading.Event()

        # run task in separate thread
        self._acq_thread = threading.Thread(target=acq._futures.executeTask,
                                            name="Monochromator scan acquisition",
                                            args=(f, self._runAcquisition, f))
        self._acq_thread.start()
        return f
Beispiel #28
0
    def acquire(self, dlg):
        nb = self.numberOfAcquisitions.value
        p = self.period.value
        sacqt = self._stream.estimateAcquisitionTime()
        intp = max(0, p - sacqt)
        if p < sacqt:
            logging.warning(
                "Acquisition will take %g s, but period between acquisition must be only %g s",
                sacqt, p)

        exporter = dataio.find_fittest_converter(self.filename.value)

        f = model.ProgressiveFuture()
        f.task_canceller = lambda l: True  # To allow cancelling while it's running
        f.set_running_or_notify_cancel()  # Indicate the work is starting now
        dlg.showProgress(f)

        das = []
        for i in range(nb):
            left = nb - i
            dur = sacqt * left + intp * (left - 1)
            startt = time.time()
            f.set_progress(end=startt + dur)
            d, e = acq.acquire([self._stream]).result()
            das.extend(d)
            if f.cancelled():
                return

            # Wait the period requested, excepted the last time
            if left > 1:
                sleept = (startt + p) - time.time()
                if sleept > 0:
                    time.sleep(sleept)
                else:
                    logging.info(
                        "Immediately starting next acquisition, %g s late",
                        -sleept)

        exporter.export(self.filename.value, das)
        f.set_result(None)  # Indicate it's over

        # self.showAcquisition(self.filename.value)
        dlg.Destroy()
Beispiel #29
0
    def _acquire(self, dlg):
        acquirer = GridAcquirer((self.xres.value, self.yres.value))

        estt = self.xres.value * self.yres.value * (
            acquirer.ccd.exposureTime.value + 0.1) * 1.1
        f = model.ProgressiveFuture(end=time.time() + estt)
        f.task_canceller = lambda f: acquirer.stop_acquisition(
        )  # To allow cancelling while it's running
        f.set_running_or_notify_cancel()  # Indicate the work is starting now
        dlg.showProgress(f)

        fn_prefix, fn_ext = os.path.splitext(self.filename.value)
        try:
            acquirer.acquire_grid(fn_prefix)
        except Exception:
            logging.exception("Failed to acquire the data")
        finally:
            f.set_result(None)  # Indicate it's over

        dlg.Destroy()
Beispiel #30
0
    def acquire(self):
        """
        Runs the acquisition
        returns Future that will have as a result a DataArray with the spectrum
        """
        # Make sure every stream is prepared, not really necessary to check _prepared
        f = self.prepare()
        f.result()

        est_start = time.time() + 0.1
        f = model.ProgressiveFuture(start=est_start,
                                    end=est_start +
                                    self.estimateAcquisitionTime())
        f.task_canceller = self._cancelAcquisition
        f._acq_state = RUNNING
        f._acq_lock = threading.Lock()
        f._acq_done = threading.Event()

        # run task in separate thread
        executeAsyncTask(f, self._runAcquisition, args=(f, ))
        return f