Beispiel #1
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 #2
0
    def moveAbs(self, pos):
        if not pos:
            return model.InstantaneousFuture()
        self._checkMoveAbs(pos)
        pos = self._applyInversionAbs(pos)

        for axis, new_pos in pos.items():
            self._position[axis] = new_pos
            logging.info("moving axis %s to %f", axis, self._position[axis])

        self._updatePosition()
        return model.InstantaneousFuture()
Beispiel #3
0
    def moveRel(self, shift, update=False):
        if not shift:
            return model.InstantaneousFuture()
        self._checkMoveRel(shift)

        f = self._createFuture(set(shift.keys()), update)
        return self._executor.submitf(f, self._doMoveRel, f, shift)
Beispiel #4
0
    def reference(self, axes):
        if not axes:
            return model.InstantaneousFuture()
        self._checkReference(axes)

        f = self._executor.submit(self._doReference, axes)
        return f
Beispiel #5
0
    def moveAbs(self, pos):
        if not pos:
            return model.InstantaneousFuture()
        self._checkMoveAbs(pos)
        pos = self._applyInversionAbs(pos)

        maxtime = 0
        for axis, new_pos in pos.items():
            change = self._position[axis] - new_pos
            self._position[axis] = new_pos
            logging.info("moving axis %s to %f", axis, self._position[axis])
            maxtime = max(maxtime, abs(change) / self.speed.value[axis])

        # TODO queue the move
        self._updatePosition()
        return model.InstantaneousFuture()
Beispiel #6
0
    def __init__(self, name, detector, dataflow, emitter, forcemd=None, **kwargs):
        """
        forcemd (None or dict of MD_* -> value): force the metadata of the
          .image DataArray to be overridden by this metadata.
        """
        super(LiveStream, self).__init__(name, detector, dataflow, emitter, **kwargs)

        self._forcemd = forcemd

        self.is_active.subscribe(self._onActive)

        # Region of interest as left, top, right, bottom (in ratio from the
        # whole area of the emitter => between 0 and 1)
        self.roi = model.TupleContinuous((0, 0, 1, 1),
                                         range=((0, 0, 0, 0), (1, 1, 1, 1)),
                                         cls=(int, long, float))

        self._ht_needs_recompute = threading.Event()
        self._hthread = threading.Thread(target=self._histogram_thread,
                                         args=(weakref.ref(self),),
                                         name="Histogram computation")
        self._hthread.daemon = True
        self._hthread.start()

        self._prev_dur = None
        self._prep_future = model.InstantaneousFuture()
Beispiel #7
0
    def test_get_fov(self):
        """
        Test getting the fov for sem and fm streams
        """
        area = (-0.001, -0.001, 0.001, 0.001)
        overlap = 0.2
        tiled_acq_task = TiledAcquisitionTask(
            self.fm_streams,
            self.stage,
            area=area,
            overlap=overlap,
            future=model.InstantaneousFuture())
        sem_fov = tiled_acq_task._getFov(self.sem_streams[0])

        exp_sem_fov = (self.ebeam.shape[0] * self.ebeam.pixelSize.value[0],
                       self.ebeam.shape[1] * self.ebeam.pixelSize.value[1])
        self.assertEqual(len(sem_fov), 2)  # (float, float)
        (self.assertAlmostEqual(x, y) for x, y in zip(sem_fov, exp_sem_fov))

        fm_fov = tiled_acq_task._getFov(self.fm_streams[0])
        self.assertEqual(len(fm_fov), 2)
        pixel_size = self.ccd.getMetadata()[model.MD_PIXEL_SIZE]
        exp_fm_fov = (self.ccd.shape[0] * pixel_size[0],
                      self.ccd.shape[1] * pixel_size[1])
        (self.assertAlmostEqual(x, y) for x, y in zip(fm_fov, exp_fm_fov))

        with self.assertRaises(TypeError):
            tiled_acq_task._getFov(None)
Beispiel #8
0
    def test_generate_indices(self):
        """
        Test output of X, Y position indices scanning order
        """
        area = (-0.001, -0.001, 0.001, 0.001)
        overlap = 0.2
        tiled_acq_task = TiledAcquisitionTask(
            self.fm_streams,
            self.stage,
            area=area,
            overlap=overlap,
            future=model.InstantaneousFuture())
        gen = tiled_acq_task._generateScanningIndices((0, 0))
        self.assertEqual(list(gen), [])

        gen = tiled_acq_task._generateScanningIndices((1, 1))
        res_gen = [(0, 0)]
        self.assertEqual(list(gen), res_gen)

        gen = tiled_acq_task._generateScanningIndices((2, 2))
        res_gen = [(0, 0), (1, 0), (1, 1), (0, 1)]
        self.assertEqual(list(gen), res_gen)

        gen = list(tiled_acq_task._generateScanningIndices((2, 4)))
        res_gen = [(0, 0), (1, 0), (1, 1), (0, 1), (0, 2), (1, 2), (1, 3),
                   (0, 3)]
        self.assertEqual(list(gen), res_gen)
Beispiel #9
0
    def _prepare_opm(self):
        if self._opm is None:
            return model.InstantaneousFuture()

        logging.debug(u"Setting optical path for %s", self.name.value)
        f = self._opm.setPath(self)
        return f
Beispiel #10
0
    def moveAbs(self, pos):
        """
        Move the stage to the defined position in m for each axis given.
        pos dict(string-> float): name of the axis and position in m
        """
        if not pos:
            return model.InstantaneousFuture()
        self._checkMoveAbs(pos)
        pos = self._applyInversionAbs(pos)

        child_to_move = collections.defaultdict(
            dict)  # child -> moveAbs argument
        for axis, distance in pos.items():
            child, child_axis = self._axis_to_child[axis]
            child_to_move[child].update({child_axis: distance})
            logging.debug("Moving axis %s (-> %s) to %g", axis, child_axis,
                          distance)

        futures = []
        for child, move in child_to_move.items():
            f = child.moveAbs(move)
            futures.append(f)

        if len(futures) == 1:
            return futures[0]
        else:
            # TODO return future composed of multiple futures
            return futures[0]
Beispiel #11
0
    def moveRel(self, shift):
        """
        Move the stage the defined values in m for each axis given.
        shift dict(string-> float): name of the axis and shift in m
        """
        if not shift:
            return model.InstantaneousFuture()
        self._checkMoveRel(shift)
        shift = self._applyInversionRel(shift)

        # merge multiple axes for the same children
        child_to_move = collections.defaultdict(
            dict)  # child -> moveRel argument
        for axis, distance in shift.items():
            child, child_axis = self._axis_to_child[axis]
            child_to_move[child].update({child_axis: distance})
            logging.debug("Moving axis %s (-> %s) by %g", axis, child_axis,
                          distance)

        futures = []
        for child, move in child_to_move.items():
            f = child.moveRel(move)
            futures.append(f)

        if len(futures) == 1:
            return futures[0]
        else:
            # TODO return future composed of multiple futures
            return futures[0]
Beispiel #12
0
    def moveAbs(self, pos, update=False):
        if not pos:
            return model.InstantaneousFuture()
        self._checkMoveAbs(pos)

        f = self._createFuture(set(pos.keys()), update)
        return self._executor.submitf(f, self._doMoveAbs, f, pos)
Beispiel #13
0
 def setView(self, view, tab_data):
     super(PointSpectrumViewport, self).setView(view, tab_data)
     wx.CallAfter(self.bottom_legend.SetToolTipString, "Wavelength")
     wx.CallAfter(self.left_legend.SetToolTipString, "Intensity")
     self._peak_fitter = peak.PeakFitter()
     self._peak_future = model.InstantaneousFuture()
     self._curve_overlay = overlay.view.CurveOverlay(self.canvas)
Beispiel #14
0
    def moveAbs(self, pos):
        if not pos:
            return model.InstantaneousFuture()
        self._checkMoveAbs(pos)
        pos = self._applyInversion(pos)

        return self._executor.submit(self._doMovePos, pos.values()[0])
Beispiel #15
0
    def moveRel(self, shift):
        """
        Move the stage the defined values in m for each axis given.
        shift dict(string-> float): name of the axis and shift in m
        returns (Future): future that control the asynchronous move
        """
        if not shift:
            return model.InstantaneousFuture()
        self._checkMoveRel(shift)

        fs = []
        for axis in shift:
            if axis == "wavelength":
                # cannot convert it directly to an absolute move, because
                # several in a row must mean they accumulate. So we queue a
                # special task. That also means the range check is delayed until
                # the actual position is known.
                f = self._executor.submit(self._doSetWavelengthRel,
                                          shift[axis])
                fs.append(f)
            elif axis == "slit":
                f = self._executor.submit(self._doSetSlitRel, shift[axis])
                fs.append(f)
        # TODO: handle correctly when more than one future
        return fs[-1]
Beispiel #16
0
    def moveAbs(self, pos):
        """
        Move the stage the defined values in m for each axis given.
        pos dict(string-> float): name of the axis and new position in m
        returns (Future): future that control the asynchronous move
        """
        if not pos:
            return model.InstantaneousFuture()
        self._checkMoveAbs(pos)

        # If grating needs to be changed, change it first, then the wavelength
        fs = []
        if "grating" in pos:
            g = pos["grating"]
            wl = pos.get("wavelength")
            fs.append(self._executor.submit(self._doSetGrating, g, wl))
        elif "wavelength" in pos:
            wl = pos["wavelength"]
            fs.append(self._executor.submit(self._doSetWavelengthAbs, wl))

        if "slit" in pos:
            width = pos["slit"]
            fs.append(self._executor.submit(self._doSetSlitAbs, width))

        return fs[-1]
Beispiel #17
0
    def moveRel(self, shift):
        if not shift:
            return model.InstantaneousFuture()
        self._checkMoveRel(shift)
        shift = self._applyInversion(shift)

        return self._executor.submit(self._doMoveRel, shift)
Beispiel #18
0
 def moveRel(self, shift):
     if not shift:
         return model.InstantaneousFuture()
     self._checkMoveRel(shift)
     # TODO move to the +N next position? (and modulo number of axes)
     raise NotImplementedError(
         "Relative move on enumerated axis not supported")
Beispiel #19
0
def cryoTiltSample(rx, rz=0):
    """
    Provide the ability to switch between imaging and tilted position, withing bumping into anything.
    Imaging position is considered when rx and rz are equal 0, otherwise it's considered tilting
    :param rx: (float) rotation movement in x axis
    :param rz: (float) rotation movement in z axis
    :return (CancellableFuture -> None): cancellable future of the move to observe the progress, and control raising the ValueError exception
    """
    # Get the stage and align components from the backend components
    stage = model.getComponent(role='stage')
    align = model.getComponent(role='align')

    f = model.CancellableFuture()
    f.task_canceller = _cancelCryoMoveSample
    f._task_state = RUNNING
    f._task_lock = threading.Lock()
    f._running_subf = model.InstantaneousFuture()
    # Run in separate thread
    executeAsyncTask(f, _doCryoTiltSample, args=(
        f,
        stage,
        align,
        rx,
        rz,
    ))
    return f
Beispiel #20
0
    def moveRel(self, shift):
        if not shift:
            return model.InstantaneousFuture()
        self._checkMoveRel(shift)
        shift = self._applyInversionRel(shift)

        for axis, change in shift.items():
            self._position[axis] += change
            rng = self.axes[axis].range
            if not rng[0] < self._position[axis] < rng[1]:
                logging.warning("moving axis %s to %f, outside of range %r",
                                axis, self._position[axis], rng)
            else:
                logging.info("moving axis %s to %f", axis, self._position[axis])

        self._updatePosition()
        return model.InstantaneousFuture()
Beispiel #21
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
Beispiel #22
0
 def applyAutoContrast(self):
     """
     (Simulation of) run the calibration for the brightness/contrast.
     (Identical interface as the phenom driver)
     """
     self.contrast.value = 0.5
     self.brightness.value = 0.5
     return model.InstantaneousFuture()
Beispiel #23
0
    def test_get_number_of_tiles(self):
        """
        Test get number of tiles using different values of total area, fov and overlap
        :return:
        """
        fov = compute_camera_fov(self.ccd)

        # use area as multiples of fov (in case simulator parameters changed)
        tiled_acq_task = TiledAcquisitionTask(
            self.fm_streams,
            self.stage,
            area=(0, 0, 2 * fov[0], 2 * fov[1]),
            overlap=0.2,
            future=model.InstantaneousFuture())
        num_tiles, starting_pos = tiled_acq_task._getNumberOfTiles()
        self.assertEqual(num_tiles, (3, 3))

        tiled_acq_task = TiledAcquisitionTask(
            self.fm_streams,
            self.stage,
            area=(0, 0, 2 * fov[0], 2 * fov[1]),
            overlap=0,
            future=model.InstantaneousFuture())
        num_tiles, starting_pos = tiled_acq_task._getNumberOfTiles()
        self.assertEqual(num_tiles, (2, 2))

        tiled_acq_task = TiledAcquisitionTask(
            self.fm_streams,
            self.stage,
            area=(0, 0, fov[0] / 2, fov[1] / 2),  # smaller than fov
            overlap=0,
            future=model.InstantaneousFuture())

        num_tiles, starting_pos = tiled_acq_task._getNumberOfTiles()
        self.assertEqual(num_tiles, (1, 1))

        # Precisely 1 x 2 FoV => should give 1 x 2 tiles
        tiled_acq_task = TiledAcquisitionTask(
            self.fm_streams,
            self.stage,
            area=(0, 0, fov[0], 2 * fov[1]),
            overlap=0,
            future=model.InstantaneousFuture())
        num_tiles, starting_pos = tiled_acq_task._getNumberOfTiles()
        self.assertEqual(num_tiles, (1, 2))
Beispiel #24
0
    def moveAbs(self, pos):

        if not isinstance(pos, dict):
            raise ValueError("Dictionary required")

        if not pos:
            return model.InstantaneousFuture()
        self._checkMoveAbs(pos)
        return self._executor.submit(self._changePressure, pos["pressure"])
Beispiel #25
0
    def moveAbs(self, pos):
        if not pos:
            return model.InstantaneousFuture()
        self._checkMoveAbs(pos)
        pos = self._applyInversion(pos)

        f = self._createFuture()
        f = self._executor.submitf(f, self._doMoveAbs, f, pos)
        return f
Beispiel #26
0
    def moveAbs(self, pos):
        for axis, value in pos.items():
            if axis == "wavelength":
                # it's read-only, so we change it via _value
                self.position._value[axis] = value
                self.position.notify(self.position.value)
            else:
                raise LookupError("Axis '%s' doesn't exist" % axis)

        return model.InstantaneousFuture()
Beispiel #27
0
    def moveAbs(self, pos):
        if not pos:
            return model.InstantaneousFuture()
        pos = self._removeOffset(pos)  # Get the position in controller coord.
        self._checkMoveAbs(pos)
        pos = self._applyInversion(pos)

        f = self._createMoveFuture()
        f = self._executor.submitf(f, self._doMoveAbs, f, pos)
        return f
Beispiel #28
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 #29
0
    def moveAbs(self, pos):
        """
        pos (dict): pos in m
        """
        if not pos:
            return model.InstantaneousFuture()
        self._checkMoveAbs(pos)

        foc = pos["z"] * 1e3
        f = self._executor.submit(self._doMoveAbs, foc)
        return f
Beispiel #30
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)