Exemple #1
0
    def __init__(self, name, role, parent, ranges=None, **kwargs):
        axes = {
            "pressure":
            model.Axis(unit="Pa",
                       choices={
                           PRESSURE_VENTED: "vented",
                           PRESSURE_PUMPED: "vacuum"
                       })
        }
        model.Actuator.__init__(self,
                                name,
                                role,
                                parent=parent,
                                axes=axes,
                                **kwargs)

        # last official position
        if self.GetStatus() == 0:
            self._position = PRESSURE_PUMPED
        else:
            self._position = PRESSURE_VENTED

        # RO, as to modify it the client must use .moveRel() or .moveAbs()
        self.position = model.VigilantAttribute({"pressure": self._position},
                                                unit="Pa",
                                                readonly=True)
        # Almost the same as position, but gives the current position
        self.pressure = model.VigilantAttribute(self._position,
                                                unit="Pa",
                                                readonly=True)

        # will take care of executing axis move asynchronously
        self._executor = CancellableThreadPoolExecutor(
            max_workers=1)  # one task at a time
Exemple #2
0
    def __init__(self, name, role, **kwargs):
        """
        Initialises the component
        """
        # TODO: or just provide .targetPressure (like .targetTemperature) ?
        # Or maybe provide .targetPosition: position that would be reached if
        # all the requested move were instantly applied?
        # TODO: support multiple pressures (low vacuum, high vacuum)
        axes = {
            "pressure":
            model.Axis(unit="Pa",
                       choices={
                           PRESSURE_VENTED: "vented",
                           PRESSURE_PUMPED: "vacuum"
                       })
        }
        model.Actuator.__init__(self, name, role, axes=axes, **kwargs)
        # For simulating moves
        self._position = PRESSURE_PUMPED  # last official position
        self._goal = PRESSURE_PUMPED
        self._time_goal = 0  # time the goal was/will be reached
        self._time_start = 0  # time the move started

        # RO, as to modify it the client must use .moveRel() or .moveAbs()
        self.position = model.VigilantAttribute({"pressure": self._position},
                                                unit="Pa",
                                                readonly=True)
        # Almost the same as position, but gives the current position
        self.pressure = model.VigilantAttribute(self._position,
                                                unit="Pa",
                                                readonly=True)

        # will take care of executing axis move asynchronously
        self._executor = CancellableThreadPoolExecutor(
            max_workers=1)  # one task at a time
Exemple #3
0
    def __init__(self, name, role, port, axes, ustepsize, **kwargs):
        """
        port (str): port name (only if sn is not specified)
        axes (list of str): names of the axes, from the 1st to the 3rd.
        ustepsize (list of float): size of a microstep in m  
        inverted (set of str): names of the axes which are inverted (IOW, either
         empty or the name of the axis)
        """
        if len(axes) != 3:
            raise ValueError("Axes must be a list of 3 axis names (got %s)" %
                             (axes, ))
        self._axes_names = axes  # axes names in order

        if len(axes) != len(ustepsize):
            raise ValueError("Expecting %d ustepsize (got %s)" %
                             (len(axes), ustepsize))
        for sz in ustepsize:
            if sz > 10e-3:  # sz is typically ~1µm, so > 1 cm is very fishy
                raise ValueError("ustepsize should be in meter, but got %g" %
                                 (sz, ))
        self._ustepsize = ustepsize

        self._serial = self._openSerialPort(port)
        self._port = port
        self._ser_access = threading.Lock()
        self._target = 1  # TODO: need to be selected by user? When is it not 1?

        self._resynchonise()

        modl, vmaj, vmin = self.GetVersion()
        if modl != 3110:
            logging.warning(
                "Controller TMCM-%d is not supported, will try anyway", modl)
        if name is None and role is None:  # For scan only
            return

        # will take care of executing axis move asynchronously
        self._executor = CancellableThreadPoolExecutor(
            max_workers=1)  # one task at a time

        axes_def = {}
        for n, sz in zip(self._axes_names, self._ustepsize):
            # Mov abs supports ±2³¹ but the actual position is only within ±2²³
            rng = [(-2**23) * sz, (2**23 - 1) * sz]
            # Probably not that much, but there is no info unless the axis has
            # limit switches and we run a referencing
            axes_def[n] = model.Axis(range=rng, unit="m")
        model.Actuator.__init__(self, name, role, axes=axes_def, **kwargs)

        driver_name = driver.getSerialDriver(self._port)
        self._swVersion = "%s (serial driver: %s)" % (odemis.__version__,
                                                      driver_name)
        self._hwVersion = "TMCM-%d (firmware %d.%02d)" % (modl, vmaj, vmin)

        self.position = model.VigilantAttribute({}, unit="m", readonly=True)
        self._updatePosition()

        # TODO: add support for changing speed. cf p.68: axis param 4 + p.81 + TMC 429 p.6
        self.speed = model.VigilantAttribute({}, unit="m/s", readonly=True)
        self._updateSpeed()
Exemple #4
0
    def __init__(self, cnvs):
        super(PointSelectOverlay, self).__init__(cnvs)
        # Prevent the cursor from resetting on clicks

        # Physical position of the last click
        self.v_pos = model.VigilantAttribute(None)
        self.w_pos = model.VigilantAttribute(None)
        self.p_pos = model.VigilantAttribute(None)
Exemple #5
0
    def __init__(self, name, role, positions, has_pressure=True, **kwargs):
        """
        Initialises the component
        positions (list of str): each pressure positions supported by the
          component (among the allowed ones)
        has_pressure (boolean): if True, has a pressure VA with the current
         pressure.
        """
        # TODO: or just provide .targetPressure (like .targetTemperature) ?
        # Or maybe provide .targetPosition: position that would be reached if
        # all the requested move were instantly applied?

        chp = {}
        for p in positions:
            try:
                chp[PRESSURES[p]] = p
            except KeyError:
                raise ValueError("Pressure position %s is unknown" % (p, ))
        axes = {"vacuum": model.Axis(unit="Pa", choices=chp)}
        model.Actuator.__init__(self, name, role, axes=axes, **kwargs)
        # For simulating moves
        self._position = PRESSURE_VENTED  # last official position
        self._goal = PRESSURE_VENTED
        self._time_goal = 0  # time the goal was/will be reached
        self._time_start = 0  # time the move started

        # RO, as to modify it the client must use .moveRel() or .moveAbs()
        self.position = model.VigilantAttribute({"vacuum": self._position},
                                                unit="Pa",
                                                readonly=True)
        if has_pressure:
            # Almost the same as position, but gives the current position
            self.pressure = model.VigilantAttribute(self._position,
                                                    unit="Pa",
                                                    readonly=True)

            self._press_timer = util.RepeatingTimer(
                1, self._updatePressure, "Simulated pressure update")
            self._press_timer.start()
        else:
            self._press_timer = None

        # Indicates whether the chamber is opened or not
        # Just pretend it's always closed, and allow the user to change that
        # for instance via CLI.
        self.opened = model.BooleanVA(False)

        # will take care of executing axis move asynchronously
        self._executor = CancellableThreadPoolExecutor(
            max_workers=1)  # one task at a time
Exemple #6
0
    def __init__(self,
                 name,
                 coordinates,
                 roc_2,
                 roc_3,
                 asm,
                 multibeam,
                 descanner,
                 detector,
                 overlap=0,
                 pre_calibrate=False):
        """
        :param name: (str) Name of the region of acquisition (ROA). It is the name of the megafield (id) as stored on
                     the external storage.
        :param coordinates: (float, float, float, float) xmin, ymin, xmax, ymax
                            Bounding box coordinates of the ROA in [m]. The coordinates are in the sample carrier
                            coordinate system, which corresponds to the component with role='stage'.
        :param roc_2: (FastEMROC) Corresponding region of calibration (ROC). Used for dark offset and digital
                      gain calibration.
        :param roc_3: (FastEMROC) Corresponding region of calibration (ROC). Used for the final scanner rotation,
                      final scanning amplitude and cell translation (cell stitching) calibration (field corrections).
        :param asm: (technolution.AcquisitionServer) The acquisition server module component.
        :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 overlap: (float), optional
            The amount of overlap required between single fields. An overlap of 0.2 means that two neighboring fields
            overlap by 20%. By default, the overlap is 0, this means there is no overlap and one field is exactly next
            to the neighboring field.
        :param pre_calibrate: (bool) If True run pre-calibrations before each ROA acquisition.
        """
        self.name = model.StringVA(name)
        self.coordinates = model.TupleContinuous(coordinates,
                                                 range=((-1, -1, -1, -1),
                                                        (1, 1, 1, 1)),
                                                 cls=(int, float),
                                                 unit='m')
        self.roc_2 = model.VigilantAttribute(roc_2)
        self.roc_3 = model.VigilantAttribute(roc_3)
        self._asm = asm
        self._multibeam = multibeam
        self._descanner = descanner
        self._detector = detector

        # List of tuples(int, int) containing the position indices of each field to be acquired.
        # Automatically updated when the coordinates change.
        self.field_indices = []
        self.overlap = overlap
        self.pre_calibrate = pre_calibrate
        self.coordinates.subscribe(self.on_coordinates, init=True)
    def __init__(self, microscope, main_app):
        super(MonoScanPlugin, self).__init__(microscope, main_app)

        # Can only be used on a Sparc with a monochromator
        if not microscope:
            return
        try:
            self.ebeam = model.getComponent(role="e-beam")
            self.mchr = model.getComponent(role="monochromator")
            self.sgrh = model.getComponent(role="spectrograph")
        except LookupError:
            logging.debug("No mochromator and spectrograph found, cannot use the plugin")
            return

        self.addMenu("Acquisition/Monochromator scan...", self.start)

        # the SEM survey stream (will be updated when showing the window)
        self._survey_s = None

        # Create a stream for monochromator scan
        self._mchr_s = MonochromatorScanStream("Spectrum", self.mchr, self.ebeam, self.sgrh)

        # The settings to be displayed in the dialog
        # Trick: we use the same VAs as the stream, so they are directly synchronised
        self.startWavelength = self._mchr_s.startWavelength
        self.endWavelength = self._mchr_s.endWavelength
        self.numberOfPixels = self._mchr_s.numberOfPixels
        self.dwellTime = self._mchr_s.dwellTime

        self.filename = model.StringVA("a.h5")
        self.expectedDuration = model.VigilantAttribute(1, unit="s", readonly=True)

        # Update the expected duration when values change
        self.dwellTime.subscribe(self._update_exp_dur)
        self.numberOfPixels.subscribe(self._update_exp_dur)
Exemple #8
0
    def __init__(self, name, role, axes, ranges=None, **kwargs):
        """
        axes (set of string): names of the axes
        """
        assert len(axes) > 0
        if ranges is None:
            ranges = {}

        axes_def = {}
        self._position = {}
        init_speed = {}
        for a in axes:
            rng = ranges.get(a, [-0.1, 0.1])
            axes_def[a] = model.Axis(unit="m", range=rng, speed=[0., 10.])
            # start at the centre
            self._position[a] = (rng[0] + rng[1]) / 2
            init_speed[a] = 10.0  # we are super fast!

        model.Actuator.__init__(self, name, role, axes=axes_def, **kwargs)

        # RO, as to modify it the client must use .moveRel() or .moveAbs()
        self.position = model.VigilantAttribute(self._applyInversionAbs(
            self._position),
                                                unit="m",
                                                readonly=True)

        self.speed = model.MultiSpeedVA(init_speed, [0., 10.], "m/s")
Exemple #9
0
    def __init__(self, name, role, wlp, **kwargs):
        """
        wlp (list of floats): polynomial for conversion from distance from the 
          center of the CCD to wavelength (in m). So, typically, a first order
          polynomial contains as first element the center wavelength, and as
          second element the light dispersion (in m/m).
        """
        if kwargs.get("inverted", None):
            raise ValueError("Axis of spectrograph cannot be inverted")

        if not isinstance(wlp, list) or len(wlp) < 1:
            raise ValueError("wlp need to be a list of at least one float")

        self._swVersion = "N/A (Odemis %s)" % odemis.__version__
        self._hwVersion = name

        self._wlp = wlp
        pos = {"wavelength": self._wlp[0]}
        wla = model.Axis(range=(0, 2400e-9), unit="m")
        model.Actuator.__init__(self,
                                name,
                                role,
                                axes={"wavelength": wla},
                                **kwargs)
        self.position = model.VigilantAttribute(pos, unit="m", readonly=True)
Exemple #10
0
    def __init__(self, fake_img):
        """
        Use .fake_img to change the image sent by the ccd
        Args:
            fake_img: 2D DataArray
        """
        super(FakeCCD, self).__init__("testccd", "ccd")
        self.exposureTime = model.FloatContinuous(0.1, (1e-6, 1000), unit="s")
        res = fake_img.shape[1], fake_img.shape[0]  # X, Y
        depth = 2 ** (fake_img.dtype.itemsize * 8)
        self.shape = (res[0], res[1], depth)
        self.binning = model.TupleContinuous((1, 1), [(1, 1), (8, 8)],
                                       cls=(int, long, float), unit="")
        self.resolution = model.ResolutionVA(res, [(1, 1), res])
        self.readoutRate = model.FloatVA(1e9, unit="Hz", readonly=True)

        pxs_sens = fake_img.metadata.get(model.MD_SENSOR_PIXEL_SIZE, (10e-6, 10e-6))
        self.pixelSize = model.VigilantAttribute(pxs_sens, unit="m", readonly=True)

        self.data = CCDDataFlow(self)
        self._acquisition_thread = None
        self._acquisition_lock = threading.Lock()
        self._acquisition_init_lock = threading.Lock()
        self._acquisition_must_stop = threading.Event()
        self.fake_img = fake_img

        self._metadata = fake_img.metadata
Exemple #11
0
    def __init__(self, name, role, port, bands, _scan=False, **kwargs):
        """
        port (string): name of the serial port to connect to. Can be a pattern,
         in which case, all the ports fitting the pattern will be tried, and the
         first one which looks like an FW102C will be used.
        bands (dict 1<=int<=12 -> 2-tuple of floats > 0 or str):
          filter position -> lower and higher bound of the wavelength (m) of the
          light which goes _through_. If it's a list, it implies that the filter
          is multi-band.
        _scan (bool): only for internal usage
        raise IOError if no device answering or not a compatible device
        """
        self._ser_access = threading.Lock()
        self._port = self._findDevice(port)
        logging.info("Found FW102C device on port %s", self._port)
        if _scan:
            return

        # check bands contains correct data
        self._maxpos = self.GetMaxPosition()
        if not bands:
            raise ValueError("Argument bands must contain at least one band")
        try:
            for pos, band in bands.items():
                if not 1 <= pos <= self._maxpos:
                    raise ValueError("Filter position should be between 1 and "
                                     "%d, but got %d." % (self._maxpos, pos))
                # To support "weird" filter, we accept strings
                if isinstance(band, basestring):
                    if not band.strip():
                        raise ValueError("Name of filter %d is empty" % pos)
                else:
                    self._checkBand(band)
        except Exception:
            logging.exception("Failed to parse bands %s", bands)
            raise

        axes = {"band": model.Axis(choices=bands)}
        model.Actuator.__init__(self, name, role, axes=axes, **kwargs)

        driver_name = driver.getSerialDriver(self._port)
        self._swVersion = "%s (serial driver: %s)" % (odemis.__version__,
                                                      driver_name)
        self._hwVersion = self._idn

        # will take care of executing axis move asynchronously
        self._executor = CancellableThreadPoolExecutor(
            max_workers=1)  # one task at a time

        self._speed = self.GetSpeed()

        curpos = self.GetPosition()
        self.position = model.VigilantAttribute({"band": curpos},
                                                readonly=True)

        # TODO: MD_OUT_WL or MD_IN_WL depending on affect
        self._metadata = {
            model.MD_FILTER_NAME: name,
            model.MD_OUT_WL: self._axes["band"].choices[curpos]
        }
Exemple #12
0
    def __init__(self, name, role, children, axes,
                 rotation=0, scale=None, translation=None, **kwargs):
        """
        children (dict str -> actuator): name to objective lens actuator
        axes (list of 2 strings): names of the axes for x and y
        scale (None tuple of 2 floats): scale factor from exported to original position
        rotation (float): rotation factor (in radians)
        translation (None or tuple of 2 floats): translation offset (in m)
        """
        assert len(axes) == 2
        if len(children) != 1:
            raise ValueError("ConvertStage needs 1 child")

        self._child = children.values()[0]
        self._axes_child = {"x": axes[0], "y": axes[1]}
        if scale is None:
            scale = (1, 1)
        if translation is None:
            translation = (0, 0)

        # TODO: range of axes could at least be updated with scale + translation
        axes_def = {"x": self._child.axes[axes[0]],
                    "y": self._child.axes[axes[1]]}
        model.Actuator.__init__(self, name, role, axes=axes_def, **kwargs)

        self._metadata[model.MD_POS_COR] = translation
        self._metadata[model.MD_ROTATION_COR] = rotation
        self._metadata[model.MD_PIXEL_SIZE_COR] = scale
        self._updateConversion()

        # RO, as to modify it the client must use .moveRel() or .moveAbs()
        self.position = model.VigilantAttribute({"x": 0, "y": 0},
                                                unit="m", readonly=True)
        # it's just a conversion from the child's position
        self._child.position.subscribe(self._updatePosition, init=True)
Exemple #13
0
    def __init__(self, name, role, parent, axes, ranges=None, **kwargs):
        assert len(axes) > 0
        if ranges is None:
            ranges = {}

        axes_def = {}
        self._position = {}

        # Just z axis
        a = axes[0]
        # The maximum, obviously, is not 1 meter. We do not actually care
        # about the range since Tescan API will adjust the value set if the
        # required one is out of limits.
        rng = [0, 1]
        axes_def[a] = model.Axis(unit="m", range=rng)

        # start at the centre
        self._position[a] = parent._device.GetWD() * 1e-3

        model.Actuator.__init__(self,
                                name,
                                role,
                                parent=parent,
                                axes=axes_def,
                                **kwargs)

        # RO, as to modify it the client must use .moveRel() or .moveAbs()
        self.position = model.VigilantAttribute(self._applyInversionAbs(
            self._position),
                                                unit="m",
                                                readonly=True)

        # will take care of executing axis move asynchronously
        self._executor = CancellableThreadPoolExecutor(
            max_workers=1)  # one task at a time
Exemple #14
0
    def __init__(self, name, role, children, axes, angle=0):
        """
        children (dict str -> actuator): name to actuator with 2+ axes
        axes (list of string): names of the axes for x and y
        angle (float in degrees): angle of inclination (counter-clockwise) from
          virtual to physical
        """
        assert len(axes) == 2
        if len(children) != 1:
            raise ValueError("StageIncliner needs 1 child")

        self._child = children.values()[0]
        self._axes_child = {"x": axes[0], "y": axes[1]}
        self._angle = angle

        axes_def = {
            "x": self._child.axes[axes[0]],
            "y": self._child.axes[axes[1]]
        }
        model.Actuator.__init__(self, name, role, axes=axes_def)

        # RO, as to modify it the client must use .moveRel() or .moveAbs()
        self.position = model.VigilantAttribute({
            "x": 0,
            "y": 0
        },
                                                unit="m",
                                                readonly=True)
        # it's just a conversion from the child's position
        self._child.position.subscribe(self._updatePosition, init=True)
Exemple #15
0
    def __init__(self, microscope, main_app):
        super(TimelapsePlugin, self).__init__(microscope, main_app)
        # Can only be used with a microscope
        if not microscope:
            return

        self.period = model.FloatContinuous(10, (1e-3, 10000),
                                            unit="s",
                                            setter=self._setPeriod)
        # TODO: prevent period < acquisition time of all streams
        self.numberOfAcquisitions = model.IntContinuous(100, (2, 100000))
        self.semOnlyOnLast = model.BooleanVA(False)
        self.filename = model.StringVA("a.h5")
        self.expectedDuration = model.VigilantAttribute(1,
                                                        unit="s",
                                                        readonly=True)

        self.period.subscribe(self._update_exp_dur)
        self.numberOfAcquisitions.subscribe(self._update_exp_dur)

        # On SECOM/DELPHI, propose to only acquire the SEM at the end
        if microscope.role in ("secom", "delphi"):
            self.vaconf["semOnlyOnLast"][
                "control_type"] = odemis.gui.CONTROL_CHECK

        self._dlg = None
        self.addMenu("Acquisition/Timelapse...\tCtrl+T", self.start)

        self._to_store = queue.Queue(
        )  # queue of tuples (str, [DataArray]) for saving data
        self._sthreads = []  # the saving threads
        self._exporter = None  # dataio exporter to use
Exemple #16
0
    def __init__(self, name, role, wlp, children=None, **kwargs):
        """
        wlp (list of floats): polynomial for conversion from distance from the
          center of the CCD to wavelength (in m):
          w = wlp[0] + wlp[1] * x + wlp[2] * x²... 
          where w is the wavelength (in m), x is the position from the center
          (in m, negative are to the left), and p is the polynomial
          (in m, m^0, m^-1...). So, typically, a first order
          polynomial contains as first element the center wavelength, and as
          second element the light dispersion (in m/m)
        """
        if kwargs.get("inverted", None):
            raise ValueError("Axis of spectrograph cannot be inverted")

        if not isinstance(wlp, list) or len(wlp) < 1:
            raise ValueError("wlp need to be a list of at least one float")

        # Note: it used to need a "ccd" child, but not anymore
        self._swVersion = "N/A (Odemis %s)" % odemis.__version__
        self._hwVersion = name

        self._wlp = wlp
        pos = {"wavelength": self._wlp[0]}
        wla = model.Axis(range=(0, 2400e-9), unit="m")
        model.Actuator.__init__(self,
                                name,
                                role,
                                axes={"wavelength": wla},
                                **kwargs)
        self.position = model.VigilantAttribute(pos, unit="m", readonly=True)
Exemple #17
0
    def __init__(self, microscope, main_app):
        super(AveragePlugin, self).__init__(microscope, main_app)
        # Can only be used with a microscope
        if not microscope:
            return

        # Check which stream the microscope supports
        main_data = self.main_app.main_data
        if not main_data.ebeam:
            return

        self.addMenu("Acquisition/Averaged frame...", self.start)

        dt = main_data.ebeam.dwellTime
        dtrg = (dt.range[0], min(dt.range[1], 1))
        self.dwellTime = model.FloatContinuous(dt.value,
                                               range=dtrg,
                                               unit=dt.unit)
        self.scale = main_data.ebeam.scale
        # Trick to pass the component (ebeam to binning_1d_from_2d())
        self.vaconf["scale"]["choices"] = (
            lambda cp, va, cf: odemis.gui.conf.util.binning_1d_from_2d(
                self.main_app.main_data.ebeam, va, cf))
        self.resolution = main_data.ebeam.resolution  # Just for info
        self.accumulations = model.IntContinuous(10, (1, 10000))
        self.filename = model.StringVA("a.h5")
        self.expectedDuration = model.VigilantAttribute(1,
                                                        unit="s",
                                                        readonly=True)

        self.dwellTime.subscribe(self._update_exp_dur)
        self.accumulations.subscribe(self._update_exp_dur)
        self.scale.subscribe(self._update_exp_dur)
Exemple #18
0
    def __init__(self, microscope, main_app):
        super(ZStackPlugin, self).__init__(microscope, main_app)
        # Can only be used with a microscope
        main_data = self.main_app.main_data
        
        if not microscope or main_data.focus is None:
            return

        self.focus = main_data.focus
        self._zrange = self.focus.axes['z'].range
        zunit = self.focus.axes['z'].unit
        self._old_pos = self.focus.position.value
        z = max(self._zrange[0], min(self._old_pos['z'], self._zrange[1]))
        self.zstart = model.FloatContinuous(z, range=self._zrange, unit=zunit)
        self.zstep = model.FloatContinuous(1e-6, range=(-1e-5, 1e-5), unit=zunit, setter=self._setZStep)
        self.numberOfAcquisitions = model.IntContinuous(3, (2, 999), setter=self._setNumberOfAcquisitions)

        self.filename = model.StringVA("a.h5")
        self.expectedDuration = model.VigilantAttribute(1, unit="s", readonly=True)

        self.zstep.subscribe(self._update_exp_dur)
        self.numberOfAcquisitions.subscribe(self._update_exp_dur)
        
        # Two acquisition order possible:
        # * for each Z, all the streams (aka intertwined): Z exactly the same for each stream
        # * for each stream, the whole Z stack: Might be faster (if filter wheel used for changing wavelength)
        self._streams_intertwined = True
        if main_data.light_filter and len(main_data.light_filter.axes["band"].choices) > 1:
            logging.info("Filter-wheel detected, Z-stack will be acquired stream-per-stream")
            self._streams_intertwined = False

        self._acq_streams = None  # previously folded streams, for optimisation
        self._dlg = None
        self.addMenu("Acquisition/ZStack...\tCtrl+B", self.start)
Exemple #19
0
    def __init__(self, name, role, parent, **kwargs):
        """
        axes (set of string): names of the axes
        """

        fwd_info = parent.fwd_info()
        axes_def = {
            "z": model.Axis(unit=fwd_info["unit"], range=fwd_info["range"]),
        }

        model.Actuator.__init__(self,
                                name,
                                role,
                                parent=parent,
                                axes=axes_def,
                                **kwargs)

        # will take care of executing axis move asynchronously
        self._executor = CancellableThreadPoolExecutor(
            max_workers=1)  # one task at a time

        # RO, as to modify it the server must use .moveRel() or .moveAbs()
        self.position = model.VigilantAttribute({}, unit="m", readonly=True)
        self._updatePosition()

        # Refresh regularly the position
        self._pos_poll = util.RepeatingTimer(5, self._refreshPosition,
                                             "Position polling")
        self._pos_poll.start()
Exemple #20
0
    def __init__(self, name, role, axes, ranges=None, **kwargs):
        """
        axes (set of string): names of the axes
        ranges (dict string -> float,float): min/max of the axis
        """
        assert len(axes) > 0
        if ranges is None:
            ranges = {}

        axes_def = {}
        self._position = {}
        init_speed = {}
        for a in axes:
            rng = ranges.get(a, (-0.1, 0.1))
            axes_def[a] = model.Axis(unit="m", range=rng, speed=(0., 10.))
            # start at the centre
            self._position[a] = (rng[0] + rng[1]) / 2
            init_speed[a] = 1.0  # we are fast!

        model.Actuator.__init__(self, name, role, axes=axes_def, **kwargs)

        # Special file "stage.fail" => will cause simulation of hardware error
        if os.path.exists("stage.fail"):
            raise HwError("stage.fail file present, simulating error")

        self._executor = model.CancellableThreadPoolExecutor(max_workers=1)

        # RO, as to modify it the client must use .moveRel() or .moveAbs()
        self.position = model.VigilantAttribute({}, unit="m", readonly=True)
        self._updatePosition()

        self.speed = model.MultiSpeedVA(init_speed, (0., 10.), "m/s")
Exemple #21
0
    def __init__(self, name, role, parent, **kwargs):
        """
        axes (set of string): names of the axes
        """

        self.parent = parent

        axes_def = {
            # Ranges are from the documentation
            "z": model.Axis(unit="m", range=(FOCUS_RANGE[0] * 1e-3, FOCUS_RANGE[1] * 1e-3)),
        }

        model.Actuator.__init__(self, name, role, parent=parent, axes=axes_def, **kwargs)

        # will take care of executing axis move asynchronously
        self._executor = CancellableThreadPoolExecutor(max_workers=1)  # one task at a time

        # RO, as to modify it the client must use .moveRel() or .moveAbs()
        self.position = model.VigilantAttribute({},
                                    unit="m", readonly=True)
        self._updatePosition()

        # Refresh regularly the position
        self._pos_poll = util.RepeatingTimer(5, self._refreshPosition, "Focus position polling")
        self._pos_poll.start()
Exemple #22
0
    def __init__(self, name, coordinates, roc, asm, multibeam, descanner,
                 detector):
        """
        :param name: (str) Name of the region of acquisition (ROA). It is the name of the megafield (id) as stored on
                     the external storage.
        :param coordinates: (float, float, float, float) left, top, right, bottom, Bounding box
                            coordinates of the ROA in [m]. The coordinates are in the sample carrier coordinate
                            system, which corresponds to the component with role='stage'.
        :param roc: (FastEMROC) Corresponding region of calibration (ROC).
        :param asm: (technolution.AcquisitionServer) The acquisition server module component.
        :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.
        """
        self.name = model.StringVA(name)
        self.coordinates = model.TupleContinuous(coordinates,
                                                 range=((-1, -1, -1, -1),
                                                        (1, 1, 1, 1)),
                                                 cls=(int, float),
                                                 unit='m')
        self.roc = model.VigilantAttribute(roc)
        self._asm = asm
        self._multibeam = multibeam
        self._descanner = descanner
        self._detector = detector

        # List of tuples(int, int) containing the position indices of each field to be acquired.
        # Automatically updated when the coordinates change.
        self.field_indices = []
        self.coordinates.subscribe(self.on_coordinates, init=True)
Exemple #23
0
    def __init__(self, microscope, main_app):
        super(ZStackPlugin, self).__init__(microscope, main_app)
        # Can only be used with a microscope
        main_data = self.main_app.main_data

        if not microscope or main_data.focus is None:
            return

        self.focus = main_data.focus
        self._zrange = self.focus.axes['z'].range
        zunit = self.focus.axes['z'].unit
        self.old_pos = self.focus.position.value
        self.zstart = model.FloatContinuous(self.old_pos['z'],
                                            range=self._zrange,
                                            unit=zunit)
        self.zstep = model.FloatContinuous(1e-6,
                                           range=(-1e-5, 1e-5),
                                           unit=zunit,
                                           setter=self._setZStep)
        self.numberofAcquisitions = model.IntContinuous(
            3, (2, 999), setter=self._setNumberOfAcquisitions)

        self.filename = model.StringVA("a.h5")
        self.expectedDuration = model.VigilantAttribute(1,
                                                        unit="s",
                                                        readonly=True)

        self.zstep.subscribe(self._update_exp_dur)
        self.numberofAcquisitions.subscribe(self._update_exp_dur)

        self._acq_streams = None  # previously folded streams, for optimisation
        self._dlg = None
        self.addMenu("Acquisition/ZStack...\tCtrl+B", self.start)
Exemple #24
0
    def __init__(self):
        fview = gmodel.MicroscopeView("fakeview")
        self.focussedView = omodel.VigilantAttribute(fview)

        self.main = Object()
        self.main.light = None
        self.main.ebeam = None
        self.main.debug = omodel.VigilantAttribute(fview)
        self.focussedView = omodel.VigilantAttribute(fview)

        self.light = None
        self.light_filter = None
        self.ccd = None
        self.sed = None
        self.ebeam = None
        self.tool = None
        self.subscribe = None
Exemple #25
0
 def __init__(self, name):
     model.Emitter.__init__(self, name, "fakeebeam", parent=None)
     self._shape = (2048, 2048)
     self.resolution = model.ResolutionVA((256, 256), [(1, 1), self._shape])
     self.pixelSize = model.VigilantAttribute((1e-9, 1e-9),
                                              unit="m",
                                              readonly=True)
     self.magnification = model.FloatVA(1000.)
Exemple #26
0
    def __init__(self, name, role, port, axes, **kwargs):
        """
        port (string): name of the serial port to connect to the controllers
        axes (dict string=> 2-tuple (0<=int<=15, 0<=int<=1)): the configuration of the network.
         for each axis name the controller address and channel
         Note that even if it's made of several controllers, each controller is 
         _not_ seen as a child from the odemis model point of view.
        """

        ser = PIRedStone.openSerialPort(port)
#        ser = FakePIRedStone.openSerialPort(port) # use FakePIRedStone for testing

        # Not to be mistaken with axes which is a simple public view
        self._axis_to_child = {} # axis name -> (PIRedStone, channel)
        axes_def = {} # axis name -> Axis
        # TODO also a rangesRel : min and max of a step
        position = {}
        speed = {}
        controllers = {} # address => PIRedStone
        for axis, (add, channel) in axes.items():
            if not add in controllers:
                controllers[add] = PIRedStone(ser, add)
#                controllers[add] = FakePIRedStone(ser, add) # use FakePIRedStone for testing
            controller = controllers[add]
            self._axis_to_child[axis] = (controller, channel)

            position[axis] = controller.getPosition(channel)
            # TODO request also the ranges from the arguments?
            # For now we put very large one
            ad = model.Axis(canAbs=False, unit="m", range=(-1, 1),
                            speed=(10e-6, 0.5))
            # Just to make sure it doesn't go too fast
            speed[axis] = 0.1 # m/s
            axes_def[axis] = ad

        model.Actuator.__init__(self, name, role, axes=axes_def, **kwargs)
        
        # RO, as to modify it the client must use .moveRel() or .moveAbs()
        self.position = model.VigilantAttribute(position, unit="m", readonly=True)

        # min speed = don't be crazy slow. max speed from hardware spec
        self.speed = model.MultiSpeedVA(speed, range=[10e-6, 0.5], unit="m/s",
                                        setter=self._setSpeed)
        self._setSpeed(speed)

        # set HW and SW version
        self._swVersion = "%s (serial driver: %s)" % (odemis.__version__,
                                                      driver.getSerialDriver(port))
        hwversions = []
        for axis, (ctrl, channel) in self._axis_to_child.items():
            hwversions.append("'%s': %s" % (axis, ctrl.versionReport()))
        self._hwVersion = ", ".join(hwversions)

        # to acquire before sending anything on the serial port
        self.ser_access = threading.Lock()

        self._action_mgr = ActionManager(self)
        self._action_mgr.start()
Exemple #27
0
    def __init__(self, microscope, main_app):
        # Called when the plugin is loaed (ie, at GUI initialisation)
        super(Correlator2D, self).__init__(microscope, main_app)
        if not microscope or microscope.role not in ("sparc", "sparc2"):
            return
        try:
            self.ebeam = model.getComponent(role="e-beam")
            self.correlator = model.getComponent(role="time-correlator")
            self.sed = model.getComponent(role="se-detector")

        except LookupError:
            logging.debug("Hardware not found, cannot use the plugin")
            return

        # the SEM survey stream (will be updated when showing the window)
        self._survey_s = None

        # Create a stream for correlator spectral measurement
        self._correlator_s = CorrelatorScanStream("Correlator data",
                                                  self.correlator, self.sed,
                                                  self.ebeam,
                                                  main_app.main_data.opm)

        # For reading the ROA and anchor ROI
        self._acqui_tab = main_app.main_data.getTabByName(
            "sparc_acqui").tab_data_model

        self.dwellTime = self._correlator_s.dwellTime
        self.pixelDuration = self._correlator_s.pixelDuration
        self.syncOffset = self._correlator_s.syncOffset
        self.syncDiv = self._correlator_s.syncDiv

        # The scanning positions are defined by ROI (as selected in the acquisition tab) + stepsize
        # Based on these values, the scanning resolution is computed
        self.roi = self._correlator_s.roi
        self.stepsize = self._correlator_s.stepsize
        self.cropvalue = self._correlator_s.cropvalue
        self.xres = model.IntVA(1, unit="px")
        self.yres = model.IntVA(1, unit="px")

        self.nDC = self._correlator_s.nDC

        self.filename = model.StringVA("a.h5")
        self.expectedDuration = model.VigilantAttribute(1,
                                                        unit="s",
                                                        readonly=True)

        # Update the expected duration when values change, depends both dwell time and # of pixels
        self.dwellTime.subscribe(self._update_exp_dur)
        self.stepsize.subscribe(self._update_exp_dur)
        self.nDC.subscribe(self._update_exp_dur)

        # subscribe to update X/Y res
        self.stepsize.subscribe(self._update_res)
        self.roi.subscribe(self._update_res)

        self.addMenu("Acquisition/CL time correlator scan...", self.start)
Exemple #28
0
    def __init__(self,
                 name,
                 role,
                 children,
                 axes,
                 rotation=0,
                 scale=None,
                 translation=None):
        """
        children (dict str -> actuator): name to objective lens actuator
        axes (list of 2 strings): names of the axes for x and y
        scale (None tuple of 2 floats): scale factor from exported to original position
        rotation (float): rotation factor (in radians)
        translation (None or tuple of 2 floats): translation offset (in m)
        """
        assert len(axes) == 2
        if len(children) != 1:
            raise ValueError("ConvertStage needs 1 child")

        self._child = children.values()[0]
        self._axes_child = {"x": axes[0], "y": axes[1]}
        if scale is None:
            scale = (1, 1)
        if translation is None:
            translation = (0, 0)
        # TODO: range of axes could at least be updated with scale + translation
        axes_def = {
            "x": self._child.axes[axes[0]],
            "y": self._child.axes[axes[1]]
        }
        model.Actuator.__init__(self, name, role, axes=axes_def)

        # Rotation * scaling for convert back/forth between exposed and child
        self._MtoChild = numpy.array(
            [[math.cos(rotation) * scale[0], -math.sin(rotation) * scale[0]],
             [math.sin(rotation) * scale[1],
              math.cos(rotation) * scale[1]]])

        self._MfromChild = numpy.array(
            [[math.cos(-rotation) / scale[0], -math.sin(-rotation) / scale[1]],
             [math.sin(-rotation) / scale[0],
              math.cos(-rotation) / scale[1]]])

        # Offset between origins of the coordinate systems
        self._O = numpy.array([translation[0], translation[1]],
                              dtype=numpy.float)

        # RO, as to modify it the client must use .moveRel() or .moveAbs()
        self.position = model.VigilantAttribute({
            "x": 0,
            "y": 0
        },
                                                unit="m",
                                                readonly=True)
        # it's just a conversion from the child's position
        self._child.position.subscribe(self._updatePosition, init=True)
Exemple #29
0
    def _init_projection_vas(self):
        """ Initialize the VAs related with image projection
        """
        # DataArray or None: RGB projection of the raw data
        self.image = model.VigilantAttribute(None)

        # Don't call at init, so don't set metadata if default value
        self.tint.subscribe(self.onTint)

        self.intensityRange.subscribe(self._onIntensityRange)
Exemple #30
0
    def __init__(self, name, role, **kwargs):
        axes_def = {"z": model.Axis(unit="m", range=[-0.3, 0.3])}
        self._position = {"z": 0}

        model.Actuator.__init__(self, name, role, axes=axes_def, **kwargs)

        # RO, as to modify it the client must use .moveRel() or .moveAbs()
        self.position = model.VigilantAttribute(
                                    self._applyInversionAbs(self._position),
                                    unit="m", readonly=True)