def __init__(self): ## Maps axis to the handlers for that axis, sorted by their range of # motion. self.axisToHandlers = depot.getSortedStageMovers() ## XXX: We have a single index for all axis, even though each ## axis may have a different number of stages. While we don't ## refactor this assumption, we just make copies of the movers ## with the most precise movement (issues #413 and #415) self.n_stages = max([len(s) for s in self.axisToHandlers.values()]) for axis, stages in self.axisToHandlers.items(): stages.extend([stages[-1]] * (self.n_stages - len(stages))) ## Indicates which stage handler is currently under control. self.curHandlerIndex = 0 ## Maps Site unique IDs to Site instances. self.idToSite = {} ## Maps handler names to events indicating if those handlers # have stopped moving. self.nameToStoppedEvent = {} events.subscribe("stage mover", self.onMotion) events.subscribe("stage stopped", self.onStop) ## Device-speficic primitives to draw on the macrostage. self.primitives = set() for h in depot.getHandlersOfType(depot.STAGE_POSITIONER): ps = h.getPrimitives() if ps: self.primitives.update(ps) self.primitives.discard(None)
def __init__(self): ## Maps axis to the handlers for that axis, sorted by their range of # motion. self.axisToHandlers = depot.getSortedStageMovers() if set(self.axisToHandlers.keys()) != {0, 1, 2}: raise ValueError('stage mover requires 3 axis: X, Y, and Z') # FIXME: we should have sensible defaults. self._saved_top = userConfig.getValue('savedTop', default=3010.0) self._saved_bottom = userConfig.getValue('savedBottom', default=3000.0) ## XXX: We have a single index for all axis, even though each ## axis may have a different number of stages. While we don't ## refactor this assumption, we just make copies of the movers ## with the most precise movement (issues #413 and #415) self.n_stages = max([len(s) for s in self.axisToHandlers.values()]) for axis, stages in self.axisToHandlers.items(): stages.extend([stages[-1]] * (self.n_stages - len(stages))) ## Indicates which stage handler is currently under control. self.curHandlerIndex = 0 ## Maps Site unique IDs to Site instances. self.idToSite = {} # Compute the hard motion limits for each axis as the # summation of all limits for handlers on that axis. hard_limits = [None] * 3 for axis in range(3): lower = 0.0 upper = 0.0 # We need set() to avoid duplicated handlers, and we might # have duplicated handlers because of the hack to meet # cockpit requirements that all axis have the same number # of handlers (see comments on issue #413). for handler in set(self.axisToHandlers[axis]): handler_limits = handler.getHardLimits() lower += handler_limits[0] upper += handler_limits[1] hard_limits[axis] = (lower, upper) # Use a tuple to prevent changes to it, and assemble it like # this to enable static code analysis. self._hard_limits = (hard_limits[0], hard_limits[1], hard_limits[2]) ## Maps handler names to events indicating if those handlers # have stopped moving. self.nameToStoppedEvent = {} events.subscribe(events.STAGE_MOVER, self.onMotion) events.subscribe(events.STAGE_STOPPED, self.onStop)
def prepareHandlers(self): # Store the pre-experiment altitude. self.initialAltitude = cockpit.interfaces.stageMover.getPosition()[-1] # Ensure that we're the only ones moving things around. cockpit.interfaces.stageMover.waitForStop() # TODO: Handling multiple movers on an axis is broken. Do not proceed if # anything but the innermost Z mover is selected. Needs a proper fix. if (cockpit.interfaces.stageMover.mover.curHandlerIndex < len(depot.getSortedStageMovers()[2]) - 1): wx.MessageBox("Wrong axis mover selected.") raise Exception("Wrong axis mover selected.") # Prepare our position. cockpit.interfaces.stageMover.goToZ(self.altBottom, shouldBlock=True) self.zStart = cockpit.interfaces.stageMover.getAllPositions()[-1][-1] events.publish('prepare for experiment', self) # Prepare cameras. for camera in self.cameras: # We set the expsoure time here. This needs to be set before # the action table is generated, since the action table # uses camera.getExposureTime to figure out timings. exposureTime = float(self.getExposureTimeForCamera(camera)) camera.setExposureTime(exposureTime)
def __init__(self): ## Maps axis to the handlers for that axis, sorted by their range of # motion. self.axisToHandlers = depot.getSortedStageMovers() ## XXX: We have a single index for all axis, even though each ## axis may have a different number of stages. While we don't ## refactor this assumption, we just make copies of the movers ## with the most precise movement (issues #413 and #415) self.n_stages = max([len(s) for s in self.axisToHandlers.values()]) for axis, stages in self.axisToHandlers.items(): stages.extend([stages[-1]] * (self.n_stages - len(stages))) ## Indicates which stage handler is currently under control. self.curHandlerIndex = 0 ## Maps Site unique IDs to Site instances. self.idToSite = {} ## Maps handler names to events indicating if those handlers # have stopped moving. self.nameToStoppedEvent = {} events.subscribe(events.STAGE_MOVER, self.onMotion) events.subscribe(events.STAGE_STOPPED, self.onStop)
def runExperiment(self): # Returns True to close dialog box, None or False otherwise. self.saveSettings() # Find the Z mover with the smallest range of motion, assumed # to be our experiment mover. mover = depot.getSortedStageMovers()[2][-1] # Only use active cameras and enabled lights. # Must do list(filter) because we will iterate over the list # many times. cameras = list( filter(lambda c: c.getIsEnabled(), depot.getHandlersOfType(depot.CAMERA))) if not cameras: wx.MessageDialog( self, message= "No cameras are enabled, so the experiment cannot be run.", style=wx.ICON_EXCLAMATION | wx.STAY_ON_TOP | wx.OK).ShowModal() return True exposureSettings = [] if self.shouldExposeSimultaneously.GetValue(): # A single exposure event with all cameras and lights. lightTimePairs = [] for i, light in enumerate(self.allLights): if (self.allLights[i].getIsEnabled() and self.lightExposureTimes[i].GetValue()): lightTimePairs.append( (light, guiUtils.tryParseNum(self.lightExposureTimes[i], decimal.Decimal))) exposureSettings = [(cameras, lightTimePairs)] else: # A separate exposure for each camera. for camera in cameras: cameraSettings = self.cameraToExposureTimes[camera] settings = [] for i, light in enumerate(self.allLights): if not light.getIsEnabled(): continue timeControl = cameraSettings[i] if timeControl.GetValue(): settings.append( (light, guiUtils.tryParseNum(timeControl, decimal.Decimal))) exposureSettings.append(([camera], settings)) altitude = cockpit.interfaces.stageMover.getPositionForAxis(2) # Default to "current is bottom" altBottom = altitude zHeight = guiUtils.tryParseNum(self.stackHeight, float) if self.zPositionMode.GetStringSelection() == 'Current is center': altBottom = altitude - zHeight / 2 elif self.zPositionMode.GetStringSelection() == 'Use saved top/bottom': altBottom = cockpit.interfaces.stageMover.mover.SavedBottom zHeight = cockpit.interfaces.stageMover.mover.SavedTop - altBottom sliceHeight = guiUtils.tryParseNum(self.sliceHeight, float) if zHeight == 0: # 2D mode. zHeight = 1e-6 sliceHeight = 1e-6 try: savePath = self.filepath_panel.GetPath() except Exception: cockpit.gui.ExceptionBox("Failed to get filename for data.", parent=self) return True params = { 'numReps': guiUtils.tryParseNum(self.numReps), 'repDuration': guiUtils.tryParseNum(self.repDuration, float), 'zPositioner': mover, 'altBottom': altBottom, 'zHeight': zHeight, 'sliceHeight': sliceHeight, 'exposureSettings': exposureSettings, 'savePath': savePath } experimentType = self.experimentType.GetStringSelection() module = self.experimentStringToModule[experimentType] if module in self.experimentModuleToPanel: # Add on the special parameters needed by this experiment type. params = self.experimentModuleToPanel[module].augmentParams(params) self.runner = module.EXPERIMENT_CLASS(**params) return self.runner.run()
def __init__(self): ## Maps axis to the handlers for that axis, sorted by their range of # motion. self.axisToHandlers = depot.getSortedStageMovers() if set(self.axisToHandlers.keys()) != {0, 1, 2}: raise ValueError('stage mover requires 3 axis: X, Y, and Z') # FIXME: we should have sensible defaults (see issue #638). self._saved_top = userConfig.getValue('savedTop', default=3010.0) self._saved_bottom = userConfig.getValue('savedBottom', default=3000.0) ## XXX: We have a single index for all axis, even though each ## axis may have a different number of stages. While we don't ## refactor this assumption, we just make copies of the movers ## with the most precise movement (issues #413 and #415) self.n_stages = max([len(s) for s in self.axisToHandlers.values()]) for axis, stages in self.axisToHandlers.items(): stages.extend([stages[-1]] * (self.n_stages - len(stages))) ## Indicates which stage handler is currently under control. self.curHandlerIndex = 0 ## Maps Site unique IDs to Site instances. self.idToSite = {} # Compute the hard motion limits for each axis as the # summation of all limits for handlers on that axis. hard_limits = [None] * 3 for axis in range(3): lower = 0.0 upper = 0.0 # We need set() to avoid duplicated handlers, and we might # have duplicated handlers because of the hack to meet # cockpit requirements that all axis have the same number # of handlers (see comments on issue #413). for handler in set(self.axisToHandlers[axis]): handler_limits = handler.getHardLimits() lower += handler_limits[0] upper += handler_limits[1] hard_limits[axis] = (lower, upper) # Use a tuple to prevent changes to it, and assemble it like # this to enable static code analysis. self._hard_limits = (hard_limits[0], hard_limits[1], hard_limits[2]) # Compute the initial step sizes. We have different step # sizes for each handler index which maybe doesn't make sense # anymore but comes from the time when it were the handlers # themselves that kept track of step size. self._step_sizes = [ ] # type: typing.List[typing.Tuple[float, float, float]] for stage_index in range(self.n_stages): default_step_sizes = [] for axis in (0, 1, 2): limits = self.axisToHandlers[axis][stage_index].getHardLimits() step_size = SensiblePreviousStepSize( (limits[1] - limits[0]) / 100.0) default_step_sizes.append(step_size) # Default is 1/100 of the axis length but in rectangular # stages that will lead to xy with different step sizes so # use the min of the two. min_xy = min(default_step_sizes[0], default_step_sizes[1]) self._step_sizes.append((min_xy, min_xy, default_step_sizes[2])) ## Maps handler names to events indicating if those handlers # have stopped moving. self.nameToStoppedEvent = {} events.subscribe(events.STAGE_MOVER, self.onMotion) events.subscribe(events.STAGE_STOPPED, self.onStop)