def test_status_with_name(hw): from ophyd.status import DeviceStatus st = DeviceStatus(device=hw.det) pbar = ProgressBar([st]) st._finished() st = DeviceStatus(device=hw.det) pbar = ProgressBar([st]) assert pbar.delay_draw == 0.2 time.sleep(0.25) st._finished()
class HxnTriggeringScaler(HxnModalBase, StruckScaler): def __init__(self, prefix, *, scan_type_triggers=None, **kwargs): super().__init__(prefix, **kwargs) if scan_type_triggers is None: scan_type_triggers = {'step': [], 'fly': [], } self.scan_type_triggers = dict(scan_type_triggers) # Scaler 1 should be in output mode 1 to properly trigger self.stage_sigs[self.output_mode] = 'Mode 1' # Ensure that the scaler isn't counting in mcs mode for any reason self.stage_sigs[self.stop_all] = 1 # Ensure that the scaler isn't counting self.stage_sigs[self.count] = 0 self.external_signals = [self.erase_start, self.start_all, self.input_mode, self.channel_advance, self.nuse_all, self.preset_real, self.dwell] def mode_internal(self): super().mode_internal() settings = self.mode_settings # ensure that no external signals are in the stage sigs list: for ext_sig in self.external_signals: if ext_sig in self.stage_sigs: del self.stage_sigs[ext_sig] scan_type = settings.scan_type.get() triggers = self.scan_type_triggers[scan_type] settings.triggers.put(list(triggers)) self.stop_all.put(1, wait=True) self.count.put(0, wait=True) self.stage_sigs[self.preset_time] = self.count_time.get() def mode_external(self): super().mode_external() if self.preset_time in self.stage_sigs: del self.stage_sigs[self.preset_time] self.stage_sigs[self.preset_real] = 0.0 self.stage_sigs[self.dwell] = 0.0 self.stage_sigs[self.channel_advance] = 'External' self.stage_sigs[self.input_mode] = 'Mode 2' self.stage_sigs[self.nuse_all] = self.mode_settings.total_points.get() self.stage_sigs[self.erase_start] = 1 self.stage_sigs.move_to_end(self.erase_start) def trigger(self): if self._staged != Staged.yes: raise RuntimeError("This detector is not ready to trigger." "Call the stage() method before triggering.") mode = self.mode_settings.mode.get() mode_trigger = getattr(self, 'trigger_{}'.format(mode)) return mode_trigger() def trigger_internal(self): return super().trigger() def trigger_external(self): self._status = DeviceStatus(self) self._status._finished() return self._status
class ContinuousAcquisitionTrigger(BlueskyInterface): """ This trigger mixin class records images when it is triggered. It expects the detector to *already* be acquiring, continously. """ def __init__(self, *args, plugin_name=None, image_name=None, **kwargs): if plugin_name is None: raise ValueError("plugin name is a required keyword argument") super().__init__(*args, **kwargs) self._plugin = getattr(self, plugin_name) if image_name is None: image_name = '_'.join([self.name, 'image']) self._plugin.stage_sigs[self._plugin.auto_save] = 'No' self.cam.stage_sigs[self.cam.image_mode] = 'Continuous' self._plugin.stage_sigs[self._plugin.file_write_mode] = 'Capture' self._image_name = image_name self._status = None self._num_captured_signal = self._plugin.num_captured self._num_captured_signal.subscribe(self._num_captured_changed) self._save_started = False def stage(self): if self.cam.acquire.get() != 1: raise RuntimeError("The ContinuousAcuqisitionTrigger expects " "the detector to already be acquiring.") return super().stage() # put logic to look up proper dark frame # die if none is found def trigger(self): "Trigger one acquisition." if not self._staged: raise RuntimeError("This detector is not ready to trigger." "Call the stage() method before triggering.") self._save_started = False self._status = DeviceStatus(self) self._desired_number_of_sets = self.number_of_sets.get() self._plugin.num_capture.put(self._desired_number_of_sets) self.dispatch(self._image_name, ttime.time()) # reset the proc buffer, this needs to be generalized self.proc.reset_filter.put(1) self._plugin.capture.put(1) # Now the TIFF plugin is capturing. return self._status def _num_captured_changed(self, value=None, old_value=None, **kwargs): "This is called when the 'acquire' signal changes." if self._status is None: return if value == self._desired_number_of_sets: # This is run on a thread, so exceptions might pass silently. # Print and reraise so they are at least noticed. try: self.tiff.write_file.put(1) except Exception as e: print(e) raise self._save_started = True if value == 0 and self._save_started: self._status._finished() self._status = None self._save_started = False
class DCMFlyer(Device): """DCM flyer with HC10E counter board :PV fly_motor : monochromator theta1 :PV fly_motor_speed : monochromator speed [deg/sec] :PV fly_motor_stop : Stop monochromator theta :PV fly_motor_done_move : Done moving when value is '1', '0' : moving :PV scaler_mode : change mode. '0' : normal mode, '1' : fly(trigger) mode :PV encoder_steps : Flyer will accumulate counts during specified encoder steps :PV scaler_preset : set to '0' will result in measured values to reset :PV scaler_reset : reset array waveform :PV enc_waveform : encoder waveform :PV I0_waveform : I0 waveform :PV It_waveform : It waveform :PV If_waveform : If waveform :PV Ir_waveform : Ir waveform """ fly_motor = Cpt(EpicsSignal, pv_names['DCM']["mono_theta"]) fly_motor_speed = Cpt(EpicsSignal, pv_names['DCM']["mono_theta_speed"]) fly_motor_stop = Cpt(EpicsSignal, pv_names['DCM']["mono_theta_stop"]) fly_motor_done_move = Cpt(EpicsSignalRO, pv_names['DCM']["mono_theta_dmov"]) fly_motor_eres = Cpt(EpicsSignalRO, pv_names['DCM']["mono_enc_resolution"]) scaler_mode = Cpt(EpicsSignal, pv_names['Scaler']["HC10E_Mode"]) encoder_steps = Cpt(EpicsSignal, pv_names['Scaler']["HC10E_TrigStep"]) scaler_preset = Cpt(EpicsSignal, pv_names['Scaler']["HC10E_Preset"]) scaler_reset = Cpt(EpicsSignal, pv_names['Scaler']["HC10E_Reset"]) enc_waveform = Cpt(EpicsSignalRO, pv_names['Scaler']["HC10E_ENC_WF"]) I0_waveform = Cpt(EpicsSignalRO, pv_names['Scaler']["HC10E_I0_WF"]) It_waveform = Cpt(EpicsSignalRO, pv_names['Scaler']["HC10E_It_WF"]) If_waveform = Cpt(EpicsSignalRO, pv_names['Scaler']["HC10E_If_WF"]) Ir_waveform = Cpt(EpicsSignalRO, pv_names['Scaler']["HC10E_Ir_WF"]) def __init__(self, *args, target_energy=None, speed=None, encoder_steps=None, stream_names=None, **kwargs): super().__init__(*args, **kwargs) self.complete_status = None self._acquiring = False self._paused = False self.stream_names = stream_names self._collected_data = None self._start_energy = 8333 # Flyer motor target position if target_energy is None: self._target_energy = 9300 else: self._target_energy = target_energy # Flyer motor speed self._speed = speed # Encoder step size for accumulating counts self._encoder_step_counts = encoder_steps # Number of scan points to read self._num_of_counts = int(100) def energyToTheta(self, energy): _th = np.rad2deg(np.arcsin(_hc / (2. * _si_111 * energy))) return _th def pause(self): # Stop motor motion self.fly_motor_stop.put(1, wait=True) def resume(self): # Resume without erasing _th = self.energyToTheta(self._target_energy) self.fly_motor.put(_th, wait=True) def setStartEnergy(self, energy): self._start_energy = energy def setTargetEnergy(self, energy): self._target_energy = energy def setSpeed(self, speed): """Set Scan Speed""" self._speed = speed def setEncSteps(self, steps): self._encoder_step_counts = steps def setNumOfCounts(self, counts): self._num_of_counts = int(counts) def checkMotor(self): """check motor motion on a separated thread""" # Wait for completion while True: if self.fly_motor_done_move.get() == 0: # logger.error("fly_motor : {}".format(self.fly_motor_done_move.get())) ttime.sleep(0.1) else: # logger.error("fly_motor : {}".format(self.fly_motor_done_move.get())) break # logger.error("Done fly") # After the wait, we declare success self._acquiring = False self.complete_status._finished(success=True) def kickoff(self): '''Start collection Returns ------- DeviceStatus This will be set to done when acquisition has begun ''' # Put scaler in fly mode # self.scaler_mode.put(1, wait=True) # Set monochromator speed self.fly_motor_speed.put(self._speed, wait=True) # Set encoder step size for accumulating counts self.encoder_steps.put(self._encoder_step_counts, wait=True) # Reset scaler array waveform self.scaler_reset.put(1, wait=True) # Reset scaler counter self.scaler_preset.put(0, wait=True) # Wait For HC10E scaler reset ttime.sleep(.2) # Indicators self._start_time = ttime.time() self._acquiring = True self._paused = False # Put scaler in fly mode self.scaler_mode.put(1, wait=True) # Start motor motion to target_position asynchronously _th = self.energyToTheta(self._target_energy) self.fly_motor.put(_th, wait=False) ttime.sleep(0.2) thread = threading.Thread(target=self.checkMotor, daemon=True) thread.start() # make status object, Indicate flying has started self.kickoff_status = DeviceStatus(self) self.kickoff_status._finished(success=True) self.complete_status = DeviceStatus(self) return self.kickoff_status def complete(self): '''Wait for flying to be complete''' if self.complete_status is None: raise RuntimeError('No collection in progress') return self.complete_status def describe_collect(self): d = dict(source="HC10E", dtype="number", shape=(1, )) return {'primary': {"ENC": d, "I0": d, "It": d, "If": d, "Ir": d}} def collect(self): # Put scaler in normal mode self.scaler_mode.put(0, wait=False) # '''Retrieve all collected data''' if self._acquiring: raise RuntimeError('Acquisition still in progress. Call complete()' ' first.') self.complete_status = None # Retrive waveforms from epics PVs ENC = self.enc_waveform.get() if isinstance(ENC, type(None)): ENC = self.enc_waveform.get() I0 = self.I0_waveform.get() if isinstance(I0, type(None)): I0 = self.I0_waveform.get() It = self.It_waveform.get() if isinstance(It, type(None)): It = self.It_waveform.get() If = self.If_waveform.get() if isinstance(If, type(None)): If = self.If_waveform.get() Ir = self.Ir_waveform.get() if isinstance(Ir, type(None)): Ir = self.Ir_waveform.get() if self._num_of_counts > len(ENC): self._num_of_counts = len(ENC) # logger.error("ENC : {}".format(ENC)) # logger.error("num_of_counts : {}".format(self._num_of_counts)) # for idx in range(len(ENC)): for idx in range(int(self._num_of_counts)): t = ttime.time() enc = ENC[idx] _i0 = I0[idx] _it = It[idx] _if = If[idx] _ir = Ir[idx] d = dict(time=t, data=dict(ENC=enc, I0=_i0, It=_it, If=_if, Ir=_ir), timestamps=dict(ENC=t, I0=t, It=t, If=t, Ir=t)) yield d
class HxnXspressTrigger(HxnModalBase, BlueskyInterface): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._status = None self._acquisition_signal = self.settings.acquire self._abs_trigger_count = 0 def unstage(self): ret = super().unstage() try: self._acquisition_signal.clear_sub(self._acquire_changed) except KeyError: pass return ret def _acquire_changed(self, value=None, old_value=None, **kwargs): "This is called when the 'acquire' signal changes." if self._status is None: return if (old_value == 1) and (value == 0): # Negative-going edge means an acquisition just finished. self._status._finished() def mode_internal(self): self._abs_trigger_count = 0 self.stage_sigs[self.external_trig] = False self.stage_sigs[self.settings.acquire_time] = self.count_time.get() self._acquisition_signal.subscribe(self._acquire_changed) def mode_external(self): ms = self.mode_settings # NOTE: these are used in Xspress3Filestore.stage self.stage_sigs[self.external_trig] = True self.stage_sigs[self.total_points] = ms.total_points.get() self.stage_sigs[self.spectra_per_point] = 1 self.stage_sigs[self.settings.acquire_time] = 0.001 # NOTE: these are taken care of in Xspress3Filestore # self.stage_sigs[self.settings.trigger_mode] = 'TTL Veto Only' # self.stage_sigs[self.settings.num_images] = total_capture def _dispatch_channels(self, trigger_time): self._abs_trigger_count += 1 channels = self._channels.values() for sn in self.read_attrs: ch = getattr(self, sn) if ch in channels: self.dispatch(ch.name, trigger_time) def trigger_internal(self): if self._staged != Staged.yes: raise RuntimeError("not staged") self._status = DeviceStatus(self) self.settings.erase.put(1) self._acquisition_signal.put(1, wait=False) self._dispatch_channels(trigger_time=time.time()) return self._status def trigger_external(self): if self._staged != Staged.yes: raise RuntimeError("not staged") self._status = DeviceStatus(self) self._status._finished() if self.mode_settings.scan_type.get() != 'fly': self._dispatch_channels(trigger_time=time.time()) # fly-scans take care of dispatching on their own return self._status def stage(self): staged = super().stage() mode = self.mode_settings.mode.get() if mode == 'external': # In external triggering mode, the devices is only triggered once # at stage self.settings.erase.put(1, wait=True) self._acquisition_signal.put(1, wait=False) return staged