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
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()
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()
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
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
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
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
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
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
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()
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
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
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
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
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
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
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)
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
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
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
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
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
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
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)
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
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()
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()
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