def update_acquisition_time(self): if self._ellipsis_animator: # cancel if there is an ellipsis animator updating the status message self._ellipsis_animator.cancel() self._ellipsis_animator = None # Don't update estimated time if acquisition is running (as we are # sharing the label with the estimated time-to-completion). if self._main_data_model.is_acquiring.value: return lvl = None # icon status shown if self._main_data_model.is_preparing.value: txt = u"Optical path is being reconfigured…" self._ellipsis_animator = EllipsisAnimator(txt, self.lbl_acqestimate) self._ellipsis_animator.start() lvl = logging.INFO elif self._roa.value == UNDEFINED_ROI: # TODO: update the default text to be the same txt = u"Region of acquisition needs to be selected" lvl = logging.WARN else: streams = self._tab_data_model.acquisitionStreams acq_time = acq.estimateTime(streams) acq_time = math.ceil(acq_time) # round a bit pessimistic txt = u"Estimated time is {}." txt = txt.format(units.readable_time(acq_time)) logging.debug("Updating status message %s, with level %s", txt, lvl) self.lbl_acqestimate.SetLabel(txt) self._show_status_icons(lvl)
def update_acquisition_time(self, _=None): lvl = None # icon status shown if not self._tab_data_model.is_calib_done.value: lvl = logging.WARN txt = "System is not calibrated." elif not self._main_data_model.active_scintillators.value: lvl = logging.WARN txt = "No scintillator loaded (go to Chamber tab)." elif not self._tab_data_model.selected_scintillators.value: lvl = logging.WARN txt = "No scintillator selected for overview acquisition." else: acq_time = 0 # Add up the acquisition time of all the selected scintillators for num in self._tab_data_model.selected_scintillators.value: center = self._tab_data_model.main.scintillator_positions[num] sz = self._tab_data_model.main.scintillator_size coords = (center[0] - sz[0] / 2, center[1] - sz[1] / 2, center[0] + sz[0] / 2, center[1] + sz[1] / 2) acq_time += fastem.estimateTiledAcquisitionTime(self._tab_data_model.streams.value[0], self._main_data_model.stage, coords) acq_time = math.ceil(acq_time) # round a bit pessimistic txt = u"Estimated time is {}." txt = txt.format(units.readable_time(acq_time)) logging.debug("Updating status message %s, with level %s", txt, lvl) self._set_status_message(txt, lvl)
def main(args): """ Handles the command line arguments args is the list of arguments passed return (int): value to return to the OS as program exit code """ ebeam = model.getComponent(role="e-beam") while ebeam.resolution.value != (1, 1): input("Please select spot mode and pick a point and press Enter...") wls = getNumber("Starting wavelength (in nm): ") * 1e-9 wle = getNumber("Ending wavelength (in nm): ") * 1e-9 nbp = getNumber("Number of wavelengths to acquire: ") dt = getNumber("Dwell time (in ms): ") * 1e-3 exp_time = nbp * (dt + 0.05) # 50 ms to change wavelength print("Expected duration: %s" % (units.readable_time(math.ceil(exp_time)), )) filename = input("Filename to store the spectrum: ") if "." not in filename: # No extension -> force hdf5 filename += ".h5" print("Press Ctrl+C to cancel the acquisition") try: acquire_spec(wls, wle, int(nbp), dt, filename) except Exception: logging.exception("Unexpected error while performing action.") return 127 return 0
def _update_progress(self): """ Update the progression controls """ now = time.time() past = now - self._start left = max(0, self._end - now) prev_left = self._prev_left # Avoid back and forth estimation (but at least every 10 s) can_update = True if prev_left is not None and self._last_update + 10 > now: # Don't update gauge if ratio reduces (a bit) try: ratio = past / (past + left) prev_ratio = self._bar.Value / self._bar.Range if 1 > prev_ratio / ratio > 1.1: # decrease < 10 % can_update = False except ZeroDivisionError: pass # Or if the time left in absolute value slightly increases (< 5s) if 0 < left - prev_left < 5: can_update = False if not can_update: logging.debug("Not updating progress as new estimation is %g s left " "vs old %g s, and current ratio %g vs old %g.", left, prev_left, ratio * 100, prev_ratio * 100) return else: self._last_update = now # progress bar: past / past+left logging.debug("updating the progress bar to %f/%f", past, past + left) self._bar.Range = 100 * (past + left) self._bar.Value = 100 * past if self._future.done(): # make really sure we don't update the text after the future is over return # Time left text self._prev_left = left left = math.ceil(left) # pessimistic if left > 2: lbl_txt = u"%s" % units.readable_time(left, full=self._full_text) else: # don't be too precise lbl_txt = u"a few seconds" if self._full_text: lbl_txt += u" left" if self._label is None: self._bar.SetToolTipString(lbl_txt) else: # TODO: if the text is too big for the label, rewrite with full=False # we could try to rely on IsEllipsized() (which requires support for # wxST_ELLIPSIZE_END in xrc) or dc.GetTextExtend() self._label.SetLabel(lbl_txt) self._label.Parent.Layout()
def _update_calibration_controls(self, text=None, button_state=True): """ Update the calibration panel controls to be ready for the next calibration. :param text: (None or str) A (error) message to display instead of the estimated acquisition time. :param button_state: (bool) Enabled or disable button depending on state. Default is enabled. """ self.button.Enable(button_state) # enable/disable button # TODO disable ROC overlay, so it cannot be moved while calibrating! if self._tab_data.is_calibrating.value: self.button.SetLabel("Cancel") # indicate canceling is possible self.gauge.Show() # show progress bar else: self.button.SetLabel( "Calibrate" ) # change button label back to ready for calibration self.gauge.Hide() # hide progress bar if text is not None: self.label.SetLabel(text) else: duration = self.estimate_calibration_time() self.label.SetLabel(units.readable_time(duration, full=False)) self.button.Parent.Layout()
def main(args): """ Handles the command line arguments args is the list of arguments passed return (int): value to return to the OS as program exit code """ ebeam = model.getComponent(role="e-beam") while ebeam.resolution.value != (1, 1): raw_input("Please select spot mode and pick a point and press Enter...") wls = getNumber("Starting wavelength (in nm): ") * 1e-9 wle = getNumber("Ending wavelength (in nm): ") * 1e-9 nbp = getNumber("Number of wavelengths to acquire: ") dt = getNumber("Dwell time (in ms): ") * 1e-3 exp_time = nbp * (dt + 0.05) # 50 ms to change wavelength print("Expected duration: %s" % (units.readable_time(math.ceil(exp_time)),)) filename = raw_input("Filename to store the spectrum: ") if "." not in filename: # No extension -> force hdf5 filename += ".h5" print("Press Ctrl+C to cancel the acquisition") try: acquire_spec(wls, wle, int(nbp), dt, filename) except Exception: logging.exception("Unexpected error while performing action.") return 127 return 0
def update_acquisition_time(self): """ Must be called in the main GUI thread. """ if self.acquiring: return if not self.area: logging.debug( "Unknown acquisition area, cannot estimate acquisition time") return streams = self.get_acq_streams() if not streams: acq_time = 0 else: zlevels = self._get_zstack_levels() focus_mtd = FocusingMethod.MAX_INTENSITY_PROJECTION if zlevels else FocusingMethod.NONE acq_time = stitching.estimateTiledAcquisitionTime( streams, self._main_data_model.stage, self.area, self.overlap, zlevels=zlevels, focusing_method=focus_mtd) txt = "The estimated acquisition time is {}." txt = txt.format(units.readable_time(acq_time)) self.lbl_acqestimate.SetLabel(txt)
def _update_est_time(self, unused): """ Compute and displays the estimated time for the auto centering """ et = self._main_data_model.ccd.exposureTime.value t = align.spot.estimateAlignmentTime(et) t = math.ceil(t) # round a bit pessimistic txt = u"~ %s" % units.readable_time(t, full=False) self._main_frame.lbl_auto_center.Label = txt
def _update_est_time(self, _): """ Compute and displays the estimated time for the auto centering """ et = self._main_data_model.ccd.exposureTime.value t = align.spot.estimateAlignmentTime(et) t = math.ceil(t) # round a bit pessimistic txt = u"~ %s" % units.readable_time(t, full=False) self._tab_panel.lbl_auto_center.Label = txt
def update_acquisition_time(self): streams = self.get_acq_streams() if streams: acq_time = acq.estimateTime(streams) acq_time = math.ceil(acq_time) # round a bit pessimisticly txt = "The estimated acquisition time is {}." txt = txt.format(units.readable_time(acq_time)) else: txt = "No streams present." self.lbl_acqestimate.SetLabel(txt)
def _update_est_time(self): """ Compute and displays the estimated time for the fine alignment """ if self._tab_data_model.tool.value == guimod.TOOL_SPOT: dt = self._main_data_model.fineAlignDwellTime.value t = align.find_overlay.estimateOverlayTime(dt, self.OVRL_REPETITION) t = math.ceil(t) # round a bit pessimistic txt = u"~ %s" % units.readable_time(t, full=False) else: txt = u"" self._tab_panel.lbl_fine_align.Label = txt
def test_readable_time(self): # (input) (expected output) values = [((1.0,), "1 second"), ((0,), "0 second"), ((3601,), "1 hour and 1 second"), ((12.350,), "12 seconds and 350 ms"), ((3 * 24 * 60 * 60 + 12 * 60,), "3 days and 12 minutes"), ] for (i, eo) in values: o = units.readable_time(*i) self.assertEquals(o, eo, u"%s is '%s' while expected '%s'" % (i, o, eo))
def _update_progress(self): if self._start is None: # no info yet return now = time.time() past = now - self._start left = max(0, self._end - now) self._prev_left, prev_left = left, self._prev_left # progress bar: past / past+left can_update = True try: ratio = past / (past + left) # Don't update gauge if ratio reduces prev_ratio = self._bar.Value / self._bar.Range logging.debug("current ratio %g, old ratio %g", ratio * 100, prev_ratio * 100) if (prev_left is not None and prev_ratio - 0.1 < ratio < prev_ratio): can_update = False except ZeroDivisionError: pass if can_update: logging.debug("updating the progress bar to %f/%f", past, past + left) self._bar.Range = 100 * (past + left) self._bar.Value = 100 * past if self._future.done(): # make really sure we don't update the text after the future is over return # Time left left = math.ceil(left) # pessimistic # Avoid back and forth estimation => don't increase unless really huge (> 5s) if (prev_left is not None and 0 < left - prev_left < 5): logging.debug( "No updating progress bar as new estimation is %g s " "while the previous was only %g s", left, prev_left) return if left > 2: lbl_txt = "%s left." % units.readable_time(left) else: # don't be too precise lbl_txt = "a few seconds left." if self._label is None: self._bar.SetToolTipString(lbl_txt) else: self._label.SetLabel(lbl_txt)
def update_acquisition_time(self): streams = self._view.getStreams() if streams: if self.chkbox_fine_align.Value: streams.append(self._ovrl_stream) acq_time = acq.estimateTime(streams) acq_time = math.ceil(acq_time) # round a bit pessimisticly txt = "The estimated acquisition time is {}." txt = txt.format(units.readable_time(acq_time)) else: txt = "No streams present." self.lbl_acqestimate.SetLabel(txt)
def update_acquisition_time(self): if self._roa.value == UNDEFINED_ROI: # TODO: update the default text to be the same txt = "Region of acquisition needs to be selected" else: streams = self._tab_data_model.acquisitionView.getStreams() acq_time = acq.estimateTime(streams) acq_time = math.ceil(acq_time) # round a bit pessimistic txt = "Estimated time is {}." txt = txt.format(units.readable_time(acq_time)) self.lbl_acqestimate.SetLabel(txt)
def update_acquisition_time(self): streams = self._view.getStreams() if streams: if self.chkbox_fine_align.Value: streams.append(self._ovrl_stream) acq_time = acq.estimateTime(streams) acq_time = math.ceil(acq_time) # round a bit pessimistically txt = "The estimated acquisition time is {}." txt = txt.format(units.readable_time(acq_time)) else: txt = "No streams present." self.lbl_acqestimate.SetLabel(txt)
def _update_progress(self): if self._start is None: # no info yet return now = time.time() past = now - self._start left = max(0, self._end - now) self._prev_left, prev_left = left, self._prev_left # progress bar: past / past+left can_update = True try: ratio = past / (past + left) # Don't update gauge if ratio reduces prev_ratio = self._bar.Value / self._bar.Range logging.debug("current ratio %g, old ratio %g", ratio * 100, prev_ratio * 100) if (prev_left is not None and prev_ratio - 0.1 < ratio < prev_ratio): can_update = False except ZeroDivisionError: pass if can_update: logging.debug("updating the progress bar to %f/%f", past, past + left) self._bar.Range = 100 * (past + left) self._bar.Value = 100 * past if self._future.done(): # make really sure we don't update the text after the future is over return # Time left left = math.ceil(left) # pessimistic # Avoid back and forth estimation => don't increase unless really huge (> 5s) if (prev_left is not None and 0 < left - prev_left < 5): logging.debug("No updating progress bar as new estimation is %g s " "while the previous was only %g s", left, prev_left) return if left > 2: lbl_txt = "%s left." % units.readable_time(left) else: # don't be too precise lbl_txt = "a few seconds left." if self._label is None: self._bar.SetToolTipString(lbl_txt) else: self._label.SetLabel(lbl_txt)
def update_acquisition_time(self): """ Must be called in the main GUI thread. """ streams = self.get_acq_streams() if streams: acq_time = acqmng.estimateTime(streams) acq_time = math.ceil(acq_time) # round a bit pessimisticly txt = "The estimated acquisition time is {}." txt = txt.format(units.readable_time(acq_time)) else: txt = "No streams present." self.lbl_acqestimate.SetLabel(txt)
def update_acquisition_time(self, acq_time=999): """ Must be called in the main GUI thread. """ if not self.acquiring: streams = self.get_acq_streams() if not streams: acq_time = 0 else: acq_time = stitching.estimateTiledAcquisitionTime(streams, self._main_data_model.stage, self.area, self.overlap, zlevels=self._get_zstack_levels()) txt = "The estimated acquisition time is {}." txt = txt.format(units.readable_time(acq_time)) self.lbl_acqestimate.SetLabel(txt)
def update_acquisition_time(self): # Update path (in case it's already the next day) self.path = datetime.today().strftime('%Y-%m-%d') self._tab_panel.txt_destination.SetValue(self.path) lvl = None # icon status shown if not self._tab_data_model.is_calib_1_done.value \ or not self._tab_data_model.is_calib_2_done.value \ or not self._tab_data_model.is_calib_3_done.value: lvl = logging.WARN txt = "System is not calibrated." elif self.roa_count == 0: lvl = logging.WARN txt = "No region of acquisition selected." elif self._get_undefined_calibrations_2(): lvl = logging.WARN txt = "Calibration regions %s missing." % (", ".join( str(c) for c in self._get_undefined_calibrations_2()), ) elif self._get_undefined_calibrations_3(): lvl = logging.WARN txt = "Calibration regions %s missing." % (", ".join( str(c) for c in self._get_undefined_calibrations_3()), ) else: # Don't update estimated time if acquisition is running (as we are # sharing the label with the estimated time-to-completion). if self._main_data_model.is_acquiring.value: return # Display acquisition time projects = self._tab_data_model.projects.value acq_time = 0 for p in projects: for roa in p.roas.value: acq_time += estimate_acquisition_time( roa, [ Calibrations.OPTICAL_AUTOFOCUS, Calibrations.IMAGE_TRANSLATION_PREALIGN ]) acq_time = math.ceil(acq_time) # round a bit pessimistic txt = u"Estimated time is {}." txt = txt.format(units.readable_time(acq_time)) logging.debug("Updating status message %s, with level %s", txt, lvl) self.lbl_acqestimate.SetLabel(txt) self._show_status_icons(lvl)
def acquire(self, fn): self.save_hw_settings() # it's not possible to keep in memory all the CCD images, so we save # them one by one in separate files (fn-ccd-XXXX.tiff) fn_base, fn_ext = os.path.splitext(fn) try: cycles = 1 anchor = self.anchor logging.info("Target ROI is [{:.3f},{:.3f},{:.3f},{:.3f}]".format( *self.roi)) rep = self.calc_rep(self.roi) # returns nr of SR pixels in x,y rep = self.check_gridpitch(rep, self.gridpitch) roi = self.update_roi(self.roi, rep) logging.info( "Updated ROI to [{:.3f},{:.3f},{:.3f},{:.3f}], in order to fit integer number of SR spots" .format(*roi)) spots = self.calc_xy_pos(roi, rep) # spots are defined shape = spots.shape[0:2] logging.info("Will scan %d x %d pixels.", shape[1], shape[0]) logging.info("Using %d x %d gridscans.", self.gridpitch[0], self.gridpitch[1]) dur = self.estimate_acq_time(shape) logging.info("Estimated acquisition time: %s", units.readable_time(round(dur))) # Let's go! logging.info("Acquiring full image 0") self.acquire_and_save_optical_survey(fn, "fullBefore") logging.info("Starting with bleaching a border around the ROI") sem_border = self.bleach_borders(roi) self.save_data(sem_border, "%s-SEM_bleached_border%s" % (fn_base, fn_ext)) ccd_roi = self.sem_roi_to_ccd(roi) ccd_roi = [ ccd_roi[0] - MARGIN_ACQ, ccd_roi[1] - MARGIN_ACQ, ccd_roi[2] + MARGIN_ACQ, ccd_roi[3] + MARGIN_ACQ ] ccd_roi_idx = ( slice(ccd_roi[1], ccd_roi[3] + 1), slice(ccd_roi[0], ccd_roi[2] + 1) ) # + 1 because we want to include the corners of the ROI self.configure_ccd(ccd_roi) self.configure_sem_for_tile() # start with the original fluorescence count (no bleaching) ccd_data = self.get_fluo_image() ccd_data_to_save = ccd_data[ccd_roi_idx] # Set up the drift correction (using the dwell time used for overview) if anchor: logging.info("Starting with pre-exposing the anchor region") de = drift.AnchoredEstimator(self.ebeam, self.sed, anchor, self.dtsem) for ii in range(13): de.acquire() de = drift.AnchoredEstimator(self.ebeam, self.sed, anchor, self.dtsem) px_iter = de.estimateCorrectionPeriod(self.dperiod, 1.0, self.gridpitch) de.acquire() # original anchor region self.save_data( de.raw[-1], "%s%02d-driftAnchor-%05d%s" % (fn_base, 0, 0, fn_ext)) self.driftlog = [(0, 0)] self.drifttime = [time.time()] next_dc = px_iter.next() for ii in range(cycles): # TODO: fix this super-arbitrary dwell time change if ii >= 1: self.ebeam.dwellTime.value = 2 * self.dt n = 0 sem_data = [] # save the fluorescence without bleaching (or end of previous cycle) self.save_data(ccd_data_to_save, "%s%02d-ccd-%05d%s" % (fn_base, ii, n, fn_ext)) for g in numpy.ndindex(self.gridpitch): n += 1 spotssubset = spots[g[0]::self.gridpitch[0], g[1]::self.gridpitch[1], :] subsetshape = spotssubset.shape[0:2] dur_frame = self.estimate_acq_time_gridscan(subsetshape) overhead_est = 1 * dur_frame + 0.1 self.ccd.exposureTime.value = dur_frame + overhead_est logging.info( "Setting exposuretime for spotsimage to: %s (includes %s overhead)", units.readable_time((dur_frame + overhead_est)), units.readable_time((overhead_est))) self.ccd_acq_complete.clear() self.ccd.data.subscribe(self.on_ccd_data) time.sleep(0.2) logging.info( "Bleaching pixels (%d,%d) + (%d,%d)*(0 -> %d, 0 -> %d)", g[1], g[0], self.gridpitch[1], self.gridpitch[0], subsetshape[1] - 1, subsetshape[0] - 1) for i in numpy.ndindex(subsetshape): bl_subset = self.bleach_spot(spotssubset[i].tolist()) sem_data.append(bl_subset) self.ccd_acq_complete.wait() if self.ccd_acq_complete.is_set(): logging.info("SEM bleaching took longer than expected") spotsimage_to_save = self._spotsimage[ccd_roi_idx] self.save_data( spotsimage_to_save, "%s%02d-spots-%05d%s" % (fn_base, ii, n, fn_ext)) ccd_data = self.get_fluo_image() # ccd_data_to_save = ccd_data ccd_data_to_save = ccd_data[ccd_roi_idx] self.save_data( ccd_data_to_save, "%s%02d-ccd-%05d%s" % (fn_base, ii, n, fn_ext)) if anchor: # Check whether the drift-correction needs to take place if n >= next_dc: de.acquire() # take a new d = de.estimate() self.drift = (self.drift[0] + d[0], self.drift[1] + d[1]) logging.info( "Drift estimated to {:.1f}, {:.1f} px".format( *self.drift)) next_dc = n + px_iter.next() self.save_data( de.raw[-1], "%s%02d-driftAnchor-%05d%s" % (fn_base, ii, n, fn_ext)) self.drifttime.append(time.time()) self.driftlog.append(self.drift) # Reconstruct the complete images logging.info("Reconstructing SEM image from tiles") sem_array = numpy.array( sem_data) # put everything in a big array sem_final = self.assemble_tiles(shape, sem_array, roi, self.gridpitch) sem_final.metadata[model.MD_DWELL_TIME] = self.dt sem_final.metadata[model.MD_DESCRIPTION] = "SEM" self.save_data( sem_final, "%s%02d_SEM_during_scan%s" % (fn_base, ii, fn_ext)) # acquire a full image again after bleaching logging.info("Acquiring full image 1") self.acquire_and_save_optical_survey(fn, "fullAfter") if anchor: de.acquire() # take a new d = de.estimate() self.drift = (self.drift[0] + d[0], self.drift[1] + d[1]) logging.info( "Drift estimated to {:.1f}, {:.1f} px".format(*self.drift)) self.save_data(de.raw[-1], "%s-driftAnchor-final%s" % (fn_base, fn_ext)) # take the SEM image again with specified dwell time and step size logging.info("Acquiring SEM survey") sem_survey_data = self.acquire_sem_survey(roi) sem_survey_data.metadata[model.MD_DESCRIPTION] = "SEM survey" self.save_data(sem_survey_data, "%s_SEM_survey%s" % (fn_base, fn_ext)) finally: self.resume_hw_settings() self.light.power.value = self.light.power.range[ 0] # makes sure light won't stay on
def value_formatter(value): value_ctrl.SetValue(readable_time(value, full=False))
def update_calibration_time(self, time): txt = "Time remaining: {}" txt = txt.format(units.readable_time(time)) self.time_txt.SetLabel(txt)
def acquire(self, fn): self.save_hw_settings() # it's not possible to keep in memory all the CCD images, so we save # them one by one in separate files (fn-ccd-XXXX.h5) fn_base, fn_ext = os.path.splitext(fn) try: spots = self.calc_xy_pos(self.roi, self.pxs) shape = spots.shape[0:2] logging.info("Will scan %d x %d pixels.", shape[1], shape[0]) ccd_roi = self.sem_roi_to_ccd(self.roi) self.configure_ccd(ccd_roi) self.configure_sem_for_tile() dur = self.estimate_acq_time(shape) logging.info("Estimated acquisition time: %s", units.readable_time(round(dur))) # TODO: acquire a "Optical survey" image? # Let's go! sem_data = [] # start with the original fluorescence count (no bleaching) n = 0 ccd_data = self.get_fluo_image() self.save_data(ccd_data, "%s-ccd-%05d%s" % (fn_base, n, fn_ext)) ccd_count = [self.ccd_image_to_count(ccd_data, ccd_roi)] try: # TODO: support drift correction (cf ar_spectral_ph) for i in numpy.ndindex(shape): logging.info("Acquiring pixel %d,%d", i[1], i[0]) sem_data.append(self.bleach_spot(spots[i].tolist())) ccd_data = self.get_fluo_image() n += 1 self.save_data(ccd_data, "%s-ccd-%05d%s" % (fn_base, n, fn_ext)) ccd_count.append(self.ccd_image_to_count( ccd_data, ccd_roi)) # TODO: acquire a "SEM survey" image? # Reconstruct the complete images logging.info("Reconstructing final images") sem_array = numpy.array( sem_data) # put everything in a big array sem_final = self.assemble_tiles(shape, sem_array, self.roi, self.pxs) sem_final.metadata[model.MD_DWELL_TIME] = self.dt sem_final.metadata[model.MD_DESCRIPTION] = "SEM" # compute the diff ccd_count = numpy.array(ccd_count) # force to be one big array ccd_diff = ccd_count[0:-1] - ccd_count[1:] ccd_diff.shape += (1, 1 ) # add info that each element is one pixel ccd_final = self.assemble_tiles(shape, ccd_diff, self.roi, self.pxs) ccd_md = self.ccd.getMetadata() ccd_final.metadata[model.MD_IN_WL] = ccd_md[model.MD_IN_WL] ccd_final.metadata[model.MD_DESCRIPTION] = "Light diff" # ccd_data = model.DataArray(ccd_data) # ccd_data.metadata[model.MD_EXP_TIME] = self.ccd.exposureTime.value # ccd_data.metadata[model.MD_DESCRIPTION] = "Raw CCD intensity" except Exception: # TODO: try to save the data as is raise # Save the data data = [sem_final, ccd_final] self.save_data(data, fn) finally: self.resume_hw_settings()
def _update_progress(self): """ Update the progression controls """ now = time.time() past = now - self._start left = max(0, self._end - now) prev_left = self._prev_left # Avoid back and forth estimation (but at least every 10 s) can_update = True if prev_left is not None and self._last_update + 10 > now: # Don't update gauge if ratio reduces (a bit) try: ratio = past / (past + left) prev_ratio = self._bar.Value / self._bar.Range if 1 > prev_ratio / ratio > 1.1: # decrease < 10 % can_update = False except ZeroDivisionError: pass # Or if the time left in absolute value slightly increases (< 5s) if 0 < left - prev_left < 5: can_update = False if not can_update: logging.debug( "Not updating progress as new estimation is %g s left " "vs old %g s, and current ratio %g vs old %g.", left, prev_left, ratio * 100, prev_ratio * 100) return else: self._last_update = now # progress bar: past / past+left # logging.debug("updating the progress bar to %f/%f", past, past + left) self._bar.Range = 100 * (past + left) self._bar.Value = 100 * past if self._future.done(): # Make sure we don't update the lbl_txt after the future is over as # it might be used to display other information return # Time left text self._prev_left = left left = math.ceil(left) # pessimistic if left > 2: lbl_txt = u"%s" % units.readable_time(left, full=self._full_text) else: # don't be too precise lbl_txt = u"a few seconds" if self._full_text: lbl_txt += u" left" if self._label is None: self._bar.SetToolTipString(lbl_txt) else: # TODO: if the text is too big for the label, rewrite with full=False # we could try to rely on IsEllipsized() (which requires support for # wxST_ELLIPSIZE_END in xrc) or dc.GetTextExtend() self._label.SetLabel(lbl_txt) self._label.Parent.Layout()
def acquire(self, fn): self.save_hw_settings() # it's not possible to keep in memory all the CCD images, so we save # them one by one in separate files (fn-ccd-XXXX.h5) fn_base, fn_ext = os.path.splitext(fn) try: spots = self.calc_xy_pos(self.roi, self.pxs) shape = spots.shape[0:2] logging.info("Will scan %d x %d pixels.", shape[1], shape[0]) ccd_roi = self.sem_roi_to_ccd(self.roi) self.configure_ccd(ccd_roi) self.configure_sem_for_tile() dur = self.estimate_acq_time(shape) logging.info("Estimated acquisition time: %s", units.readable_time(round(dur))) # TODO: acquire a "Optical survey" image? # Let's go! sem_data = [] # start with the original fluorescence count (no bleaching) n = 0 ccd_data = self.get_fluo_image() self.save_data(ccd_data, "%s-ccd-%05d%s" % (fn_base, n, fn_ext)) ccd_count = [self.ccd_image_to_count(ccd_data, ccd_roi)] try: # TODO: support drift correction (cf ar_spectral_ph) for i in numpy.ndindex(shape): logging.info("Acquiring pixel %d,%d", i[1], i[0]) sem_data.append(self.bleach_spot(spots[i].tolist())) ccd_data = self.get_fluo_image() n += 1 self.save_data(ccd_data, "%s-ccd-%05d%s" % (fn_base, n, fn_ext)) ccd_count.append(self.ccd_image_to_count(ccd_data, ccd_roi)) # TODO: acquire a "SEM survey" image? # Reconstruct the complete images logging.info("Reconstructing final images") sem_array = numpy.array(sem_data) # put everything in a big array sem_final = self.assemble_tiles(shape, sem_array, self.roi, self.pxs) sem_final.metadata[model.MD_DWELL_TIME] = self.dt sem_final.metadata[model.MD_DESCRIPTION] = "SEM" # compute the diff ccd_count = numpy.array(ccd_count) # force to be one big array ccd_diff = ccd_count[0:-1] - ccd_count[1:] ccd_diff.shape += (1, 1) # add info that each element is one pixel ccd_final = self.assemble_tiles(shape, ccd_diff, self.roi, self.pxs) ccd_md = self.ccd.getMetadata() ccd_final.metadata[model.MD_IN_WL] = ccd_md[model.MD_IN_WL] ccd_final.metadata[model.MD_DESCRIPTION] = "Light diff" # ccd_data = model.DataArray(ccd_data) # ccd_data.metadata[model.MD_EXP_TIME] = self.ccd.exposureTime.value # ccd_data.metadata[model.MD_DESCRIPTION] = "Raw CCD intensity" except Exception: # TODO: try to save the data as is raise # Save the data data = [sem_final, ccd_final] self.save_data(data, fn) finally: self.resume_hw_settings()