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")
def __init__(self): # will take care of executing peak fitting asynchronously # Maximum one task at a time as curve_fit() is not thread-safe self._executor = model.CancellableThreadPoolExecutor(max_workers=1)
import time from concurrent.futures import CancelledError import numpy from odemis import model, util from odemis.acq import stitching from odemis.acq.stitching import REGISTER_IDENTITY from odemis.acq.stream import SEMStream from odemis.util import TimeoutError SINGLE_BEAM_ROTATION_DEFAULT = 0 # 0 is typically a good guess (better than multibeam rotation of ~0.0157 rad) MULTI_BEAM_ROTATION_DEFAULT = 0 # The executor is a single object, independent of how many times the module (fastem.py) is loaded. _executor = model.CancellableThreadPoolExecutor(max_workers=1) class FastEMROA(object): """ Representation of a FastEM ROA (region of acquisition). The region of acquisition is a megafield image, which consists of a sequence of single field images. Each single field image itself consists of cell images. The number of cell images is defined by the shape of the multiprobe and detector. """ 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
def __init__(self, name, role, vas=None, axes=None, **kwargs): """ Only VA's specified in vas are created. Their type is determined based on the supplied initial value, and the presence of range or choices in. Both the presence of VA's and the presence of axes are optional. vas (dict (string -> dict (string -> any))): This dict maps desired VA names to a dict with VA properties. The VA property dict can contain the following keys: "value" (any): initial values of the VA "readonly" (bool): optional, True for read only VA, defaults to False "unit" (str or None): optional, the unit of the VA, defaults to None "range" (float, float): optional, min/max of the VA. Incompatible with "choices". "choices" (list, set or dict): optional, possible values available to the VA. Incompatible with "range". axes (dict (string -> dict (string -> any))): dict mapping desired axis names to dicts with axis properties. The axis property dict can contain the following keys: "unit" (str): optional, unit of the axis, defaults to "m" "range" (float, float): optional, min/max of the axis, defaults to (-0.1, 0.1) "choices" (dict): optional, alternative to ranges, these are the choices of the axis "speed" (float, float): optional, allowable range of speeds, defaults to (0., 10.) """ # Create desired VA's if vas: for vaname, vaprop in vas.items(): # Guess an appropriate VA type based on the initial value and the presence of range or choices try: value = vaprop["value"] except AttributeError: # TODO: support "short-cut" by using a choice or range raise AttributeError( f"VA {vaname}, does not have a 'value' key.") if "choices" in vaprop: if "range" in vaprop: raise ValueError( f"VA {vaname}, has both a range and choice, only one is possible." ) # Always keep it simple as "VAEnumerated", it fits any type. vaclass = model.VAEnumerated # The "choices" argument can be either a dict or a set. # However, YAML, doesn't supports set. So we accept list, # and convert to a set. if isinstance(vaprop["choices"], list): vaprop["choices"] = set(vaprop["choices"]) elif isinstance(value, str): if "range" in vaprop: raise ValueError("String doesn't support range") vaclass = model.StringVA elif isinstance(value, bool): if "range" in vaprop: raise ValueError("Boolean doesn't support range") vaclass = model.BooleanVA elif isinstance(value, float): if "range" in vaprop: vaclass = model.FloatContinuous else: vaclass = model.FloatVA elif isinstance(value, int): if "range" in vaprop: vaclass = model.IntContinuous else: vaclass = model.IntVA elif isinstance(value, Iterable): # It's a little tricky because YAML only supports lists. # So we guess a ListVA for the basic type (which is the most full-feature), # and if there is a range, use TupleContinuous, as List doesn't # support a range. if "range" in vaprop: vaclass = model.TupleContinuous else: vaclass = model.ListVA else: raise ValueError( f"VA {vaname}, has unsupported value type {value.__class__.__name__}." ) va = vaclass(**vaprop) setattr(self, vaname, va) # Create desired axes axes_def = {} if axes: self._position = {} init_speed = {} for axisname, axisprop in axes.items(): init_speed[axisname] = 1.0 # we are fast! if "range" not in axisprop and "choices" not in axisprop: # if no range nor choices are defined axisprop["range"] = (-0.1, 0.1) # use the default range if "speed" not in axisprop: axisprop["speed"] = (0., 10.) # default speed axes_def[axisname] = model.Axis(**axisprop) if "range" in axisprop: self._position[axisname] = ( axisprop["range"][0] + axisprop["range"][1]) / 2 # start at the centre else: self._position[axisname] = next(iter( axisprop["choices"])) # start at an arbitrary value 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.speed = model.MultiSpeedVA(init_speed, (0., 10.), "m/s") model.Actuator.__init__(self, name, role, axes=axes_def, **kwargs) if hasattr(self, "position"): self._updatePosition()