def _plan(self): yield from bps.open_run() # stash numcapture and shutter_enabled num_capture = yield from bps.rd(self.device.hdf5.num_capture) shutter_enabled = yield from bps.rd(self.device.dg1.shutter_enabled) # set to 1 temporarily self.device.hdf5.num_capture.put(1) # Restage to ensure that dark frames goes into a separate file. yield from bps.stage(self.device) yield from bps.mv(self.device.dg1.shutter_enabled, 2) # The `group` parameter passed to trigger MUST start with # bluesky-darkframes-trigger. yield from bps.trigger_and_read([self.device], name='dark') # Restage. yield from bps.unstage(self.device) # restore numcapture and shutter_enabled yield from bps.mv(self.device.hdf5.num_capture, num_capture) yield from bps.mv(self.device.dg1.shutter_enabled, shutter_enabled) # Dark frames finished, moving on to data yield from bps.stage(self.device) status = yield from bps.trigger(self.device, group='primary-trigger') while not status.done: yield from bps.trigger_and_read(self.async_poll_devices, name='labview') yield from bps.sleep(1) yield from bps.create('primary') yield from bps.read(self.device) yield from bps.save() yield from bps.unstage(self.device)
def moveE(energy): args_list = [] args_list.append((mono.energy, energy)) if undulator.downstream.tracking is True: target_energy = undulator.downstream.offset + energy current_energy = undulator.downstream.energy.get( ) + undulator.downstream.deadband if current_energy < target_energy: args_list[0] += (undulator.downstream.energy, target_energy + undulator.downstream.backlash) args_list[0] += (undulator.downstream.start_button, 1) args_list.append((undulator.downstream.energy, target_energy)) args_list[-1] += (undulator.downstream.start_button, 1) else: args_list[0] += (undulator.downstream.energy, target_energy) args_list[0] += (undulator.downstream.start_button, 1) stage(mono) for args in args_list: yield from mv(*args)
def dark_plan(): yield from bps.mv(shutter, 'closed') yield from bps.unstage(det) yield from bps.stage(det) yield from bps.trigger(det, group='darkframe-trigger') yield from bps.wait('darkframe-trigger') snapshot = bluesky_darkframes.SnapshotDevice(det) yield from bps.unstage(det) yield from bps.stage(det) yield from bps.mv(shutter, 'open') return snapshot
def dark_plan(detector): # Restage to ensure that dark frames goes into a separate file. yield from bps.unstage(detector) yield from bps.stage(detector) yield from bps.mv(shutter, 'closed') # The `group` parameter passed to trigger MUST start with # bluesky-darkframes-trigger. yield from bps.trigger(detector, group='bluesky-darkframes-trigger') yield from bps.wait('bluesky-darkframes-trigger') snapshot = bluesky_darkframes.SnapshotDevice(detector) yield from bps.mv(shutter, 'open') # Restage. yield from bps.unstage(detector) yield from bps.stage(detector) return snapshot
def set_and_fly(filepaths, flyers, sleeptime=10): ''' Fly on flyers with file prefix for a certain sleep time. fileprefix: file prefix sleeptime : sleep time to let flyer run for I've written this manually for now. ''' # set the file paths for filepath, flyer in zip(filepaths, flyers): yield from bps.abs_set(flyer.filepath, filepath) yield from bps.open_run() for flyer in flyers: yield from bps.stage(flyer) grp = str(uuid4()) for flyer in flyers: yield from bps.kickoff(flyer, group=grp, wait=False) yield from bps.wait(group=grp) yield from bps.sleep(sleeptime) for flyer in flyers: yield from bps.complete(flyer, group=grp, wait=False) for flyer in flyers: yield from bps.collect(flyer) for flyer in flyers: yield from bps.unstage(flyer) yield from bps.close_run()
def insert_dark_frame(force_read, msg=None): # Acquire a fresh Snapshot if we need one, or retrieve a cached one. state = {} for signal in self.locked_signals: reading = yield from bluesky.plan_stubs.read(signal) # Restructure # {'data_key': {'value': <value>, 'timestamp': <timestamp>}, ...} # into (('data_key', <value>) ...). values_only = tuple( (k, v['value']) for k, v in reading.items()) state[signal.name] = values_only if self._current_state != state: self._current_state = state snapshot_changed = True else: snapshot_changed = False try: snapshot = self.get_snapshot(state) except NoMatchingSnapshot: logger.info(f"Taking a new dark frame for state=%r", state) snapshot = yield from self.dark_plan() self.add_snapshot(snapshot, state) if snapshot_changed or force_read: logger.info(f"Creating a 'dark' Event for state=%r", state) self._current_snapshot.set_snaphsot(snapshot) # Read the Snapshot into the 'dark' Event stream. yield from bps.stage(self._current_snapshot) yield from bps.trigger_and_read([self._current_snapshot], name=self.stream_name) yield from bps.unstage(self._current_snapshot) self._latch = False if msg is not None: return (yield msg)
def insert_take_dark(msg): nonlocal need_dark qualified_dark_uid = _validate_dark(expire_time=glbl["dk_window"]) area_det = xpd_configuration["area_det"] if (not need_dark) and (not qualified_dark_uid): need_dark = True if need_dark and ( not qualified_dark_uid) and msg.command == "open_run" and ( "dark_frame" not in msg.kwargs): # We are about to start a new 'run' (e.g., a count or a scan). # Insert a dark frame run first. need_dark = False # Annoying detail: the detector was probably already staged. # Unstage it (if it wasn't staged, nothing will happen) and # then take_dark() and then re-stage it. return ( bpp.pchain( bps.unstage(area_det), take_dark(), bps.stage(area_det), bpp.single_gen(msg), open_shutter_stub(), ), None, ) elif msg.command == "open_run" and "dark_frame" not in msg.kwargs: return ( bpp.pchain(bpp.single_gen(msg), open_shutter_stub()), None, ) else: # do nothing if (not need_dark) return None, None
def dark_plan(self, detector): """The plan to take dark.""" # Restage to ensure that dark frames goes into a separate file. yield from bps.unstage(detector) yield from bps.stage(detector) yield from bps.mv(self.shutter, self.shutter_close) # The `group` parameter passed to trigger MUST start with # bluesky-darkframes-trigger. yield from bps.trigger(detector, group='bluesky-darkframes-trigger') yield from bps.wait('bluesky-darkframes-trigger') snapshot = SnapshotDevice(detector) yield from bps.mv(self.shutter, self.shutter_open) # Restage. yield from bps.unstage(detector) yield from bps.stage(detector) return snapshot
def xpdacq_ramp_count(motor: typing.Any, value: typing.Any, inner_plan: typing.Callable, take_pre_data=True, timeout=None, period=None, md=None) -> typing.Generator: """ Take data while ramping one or more motors. Parameters ---------- inner_plan : The plan to repeat in loop. It returns a generator inner_plan(). motor : A positioner to ramp up. value: A value to ramp up to. timeout : float, optional If not None, the maximum time the ramp can run. In seconds take_pre_data: Bool, optional If True, add a pre data at beginning period : float, optional If not None, take data no faster than this. If None, take data as fast as possible If running the inner plan takes longer than `period` than take data with no dead time. In seconds. md : dict The metadata of this plan. """ for detector in detectors: yield from bps.stage(detector) def go_plan(): status, = yield from bps.mv(motor, value) return status yield from bp.ramp_plan(go_plan(), motor, inner_plan, take_pre_data=take_pre_data, timeout=timeout, period=period, md=md) for detector in detectors: yield from bps.unstage(detector)
def __single_shot(self, gasdelay=0.05, shotdelay=10.0, record=True, use_l3t=False, controls=[], end_run=True): logging.debug("Calling __single_shot with the folling parameters:") logging.debug("gasdelay: {}".format(gasdelay)) logging.debug("shotdelay: {}".format(shotdelay)) logging.debug("record: {}".format(record)) logging.debug("use_l3t: {}".format(use_l3t)) logging.debug("controls: {}".format(controls)) logging.debug("end_run: {}".format(end_run)) nshots = 1 yield from bps.configure(daq, begin_sleep=2, record=record, use_l3t=use_l3t, controls=controls) yield from bps.configure(daq, events=nshots) # Add sequencer, DAQ to detectors for shots dets = [daq, seq] for det in dets: yield from bps.stage(det) # Setup sequencer for requested rate sync_mark = int(self._sync_markers[self._rate]) seq.sync_marker.put(sync_mark) seq.play_mode.put(0) # Run sequence once # Determine the different sequences needed gdelay = int(gasdelay*120) # 120 beam delays/second sdelay = int(shotdelay*120) # 120 beam delays/second slow_cam_seq = [[167, 0, 0, 0]] gas_jet_seq = [[177, 0, 0, 0], [176, gdelay, 0, 0], [169, 0, 0, 0], [0, sdelay, 0, 0]] s = slow_cam_seq + gas_jet_seq logging.debug("Sequence: {}".format(s)) # Get exposure time in beam deltas from number of shots exposure = nshots * (int(shotdelay/120.0) + int(gasdelay/120.0)) logging.debug("Exposure time: {}".format(exposure*120.0)) # Stage and add in slow cameras *after* daq is staged and configured slowcams = SlowCameras() # The camera delay and number of 'during' shots are the same in this case (I think) config = {'slowcamdelay': exposure, 'during': exposure} dets.append(slowcams) # Add this in to auto-unstage later slowcams.stage(config) seq.sequence.put_seq(s) yield from bps.trigger_and_read(dets) # If this is the last move in the scan, check cleanup settings if end_run: daq.end_run()
def manual_count(det=eiger1m_single): detectors = [det] for det in detectors: yield from stage(det) yield from open_run() print("All slow setup code has been run. " "Type RE.resume() when ready to acquire.") yield from pause() yield from trigger_and_read(detectors) yield from close_run() for det in detectors: yield from unstage(det)
def insert_reference_to_dark_frame(msg): if msg.command == 'open_run': return ( bluesky.preprocessors.pchain( bluesky.preprocessors.single_gen(msg), bps.stage(self.dark_frame_cache), bps.trigger_and_read([self.dark_frame_cache], name='dark'), bps.unstage(self.dark_frame_cache) ), None, ) else: return None, None
def filter_opt_count(det, target_count=100000, md={}): """ filter_opt_count OPtimize counts using filters Assumes mu=0.2, x = [0.89, 2.52, 3.83, 10.87] I = I_o \exp(-mu*x) Only takes one detector, since we are optimizing based on it alone target is mean+2std """ dc = DocumentCache() token = yield from bps.subscribe('all', dc) yield from bps.stage(det) md = {} yield from bps.open_run(md=md) # BlueskyRun object allows interaction with documents similar to db.v2, # but documents are in memory run = BlueskyRun(dc) yield from bps.trigger_and_read([det, filter1, filter2, filter3, filter4]) data = run.primary.read()['pilatus300k_image'] mean = data[-1].mean().values.item() # xarray.DataArray methods std = data[-1].std().values.item() # xarray.DataArray methods curr_counts = mean + 2 * std # gather filter information and solve filter_status = [ round(filter1.get() / 5), round(filter2.get() / 5), round(filter3.get() / 5), round(filter4.get() / 5) ] print(filter_status) filter_status = [not e for e in filter_status] new_filters = solve_filter_setup(filter_status, curr_counts, target_count) # invert again to reflect filter status new_filters = [not e for e in new_filters] print(new_filters) # set new filters and read. For some reason hangs on bps.mv when going high filter1.put(new_filters[0] * 4.9) filter2.put(new_filters[1] * 4.9) filter3.put(new_filters[2] * 4.9) filter4.put(new_filters[3] * 4.9) yield from bps.trigger_and_read([det, filter1, filter2, filter3, filter4]) # close out run yield from bps.close_run() yield from bps.unsubscribe(token) yield from bps.unstage(det)
def tail(): # Acquire a fresh Snapshot if we need one, or retrieve a cached one. state = {} for signal in self.locked_signals: reading = yield bluesky.plan_stubs.read(signal) state[signal.name] = reading try: snapshot = self.get_snapshot(state) except NoMatchingSnapshot: snapshot = yield from self.dark_plan() self.add_snapshot(snapshot, state) # Read the Snapshot into the 'dark' Event stream. yield from bps.stage(snapshot) yield from bps.trigger_and_read([snapshot], name=self.stream_name) yield from bps.unstage(snapshot)
def plan(): yield from bps.open_run() yield from bps.stage(det) yield from bps.mv(det.exposure_time, 0.01) yield from bps.trigger_and_read([det]) # should prompt new dark Event yield from bps.trigger_and_read([det]) yield from bps.mv(det.exposure_time, 0.02) yield from bps.trigger_and_read([det]) # should prompt new dark Event yield from bps.trigger_and_read([det]) yield from bps.mv(det.exposure_time, 0.01) yield from bps.trigger_and_read([det]) # should prompt new dark Event yield from bps.trigger_and_read([det]) yield from bps.trigger_and_read([det]) yield from bps.unstage(det) yield from bps.close_run()
def insert_dark_frame(force_read, msg=None): # Acquire a fresh Snapshot if we need one, or retrieve a cached one. state = {} for signal in self.locked_signals: reading = yield from bluesky.plan_stubs.read(signal) # Restructure # {'data_key': {'value': <value>, 'timestamp': <timestamp>}, ...} # into (('data_key', <value>) ...). values_only = tuple( (k, v['value']) for k, v in reading.items()) state[signal.name] = values_only try: snapshot = self.get_snapshot(state) except NoMatchingSnapshot: # If we are here, we either haven't taken a reading when the # locked_signals were in this state, or the last such reading # we took has aged out of the cache. We have to trigger the # hardware and get a fresh snapshot. logger.info("Taking a new %r reading for state=%r", self.stream_name, state) snapshot = yield from self._partialed_dark_plan() self.add_snapshot(snapshot, state) # If the Snapshot is the same as the one we most recently inserted, # then we don't need to create a new Event. The previous Event # still holds. snapshot_changed = snapshot is not self._current_snapshot.get_snapshot( ) if snapshot_changed or force_read: logger.info("Creating a %r Event for state=%r", self.stream_name, state) self._current_snapshot.set_snaphsot(snapshot) # Read the Snapshot. This does not actually trigger hardware, # but it goes through all the bluesky steps to generate new # Event. # The reason we handle self._current_snapshot here instead of # snapshot itself is the bluesky RunEngine notices if you give # it a different object than you had given it earlier. Thus, # bluesky will always see the "Device" self._current_snapshot # here, and it will be satisfied. yield from bps.stage(self._current_snapshot) yield from trigger_and_read([self._current_snapshot], name=self.stream_name, group=short_uid(GROUP_PREFIX)) yield from bps.unstage(self._current_snapshot) self._latch = False if msg is not None: return (yield msg)
def _pe_acquisition_plan(): for det in dets: if images_per_set is not None: yield from bps.mov(det.images_per_set, images_per_set) for det in dets: yield from bps.stage(det) yield from bps.sleep(1) # close fast shutter, now take a dark # yield from bps.mov(fs, 0) yield from bpp.trigger_and_read(dets, name='dark') # open fast shutter # yield from bps.mov(fs, 1) yield from bpp.trigger_and_read(dets, name='primary') for det in dets: yield from bps.unstage(det)
def tail(): # Acquire a fresh Snapshot if we need one, or retrieve a cached one. state = {} for signal in self.locked_signals: reading = yield from bluesky.plan_stubs.read(signal) # Restructure # {'data_key': {'value': <value>, 'timestamp': <timestamp>}, ...} # into (('data_key', <value>) ...). values_only = tuple( (k, v['value']) for k, v in reading.items()) state[signal.name] = values_only try: snapshot = self.get_snapshot(state) except NoMatchingSnapshot: snapshot = yield from self.dark_plan() self.add_snapshot(snapshot, state) # Read the Snapshot into the 'dark' Event stream. yield from bps.stage(snapshot) yield from bps.trigger_and_read([snapshot], name=self.stream_name) yield from bps.unstage(snapshot)
def dark_plan(detector): # stash numcapture and shutter_enabled num_capture = yield from bps.rd(detector.hdf5.num_capture) shutter_enabled = yield from bps.rd(detector.dg1.shutter_enabled) # set to 1 temporarily detector.hdf5.num_capture.put(1) # Restage to ensure that dark frames goes into a separate file. yield from bps.unstage(detector) yield from bps.stage(detector) yield from bps.mv(detector.dg1.shutter_enabled, 2) # The `group` parameter passed to trigger MUST start with # bluesky-darkframes-trigger. yield from bps.trigger(detector, group='bluesky-darkframes-trigger') yield from bps.wait('bluesky-darkframes-trigger') snapshot = bluesky_darkframes.SnapshotDevice(detector) # Restage. yield from bps.unstage(detector) # restore numcapture and shutter_enabled yield from bps.mv(detector.hdf5.num_capture, num_capture) yield from bps.mv(detector.dg1.shutter_enabled, shutter_enabled) return snapshot
def max_pixel_count(dets, sat_count=60000, md={}): """max_pixel_count Adjust acquisition time based on max pixel count Assume each det in dets has an attribute det.max_count. Assume counts are linear with time. Scale acquisition time to make det.max_count.get()=sat_count """ for det in dets: yield from bps.stage(det) yield from bps.trigger_and_read(det) curr_acq_time = det.cam.acquire_time.get() # =================== BIG IF, DOES THIS EXIST curr_max_counts = det.max_count.get() # ============================================ new_acq_time = round(sat_count / curr_max_counts * curr_acquire_time, 2) yield from bps.mv(det.cam.acquire_time, new_acq_time) # run standard count plan with new acquire times yield from bp.count(dets, md=md)
def _single_shot_plan(self, record=True, use_l3t=False, controls=[], end_run=True): """Definition of plan for taking laser shots with the MEC laser.""" # TODO: Add attenuator control logging.debug("Generating shot plan using _shot_plan.") logging.debug("_shot_plan config:") logging.debug("{}".format(self._config)) logging.debug("Record: {}".format(record)) logging.debug("use_l3t: {}".format(use_l3t)) logging.debug("controls: {}".format(controls)) # Make sure that any updates to configuration are applied self.configure(self._config) # Setup the daq based on config total_shots = 1 print("Configured for {} total shots.".format(total_shots)) logging.debug("Total shots: {}".format(total_shots)) yield from bps.configure(daq, begin_sleep=2, record=record, use_l3t=use_l3t, controls=controls) # Add sequencer, DAQ to detectors for shots dets = [daq, seq] for det in dets: yield from bps.stage(det) # Check for slow cameras, stage if requested if self._config['slowcam']: from .slowcams import SlowCameras self._slowcams = SlowCameras() dets.append(self._slowcams) # Add this in to auto-unstage later yield from bps.stage(self._slowcams) # Setup the pulse picker for single shots in flip flop mode pp.flipflop(wait=True) # Setup sequencer for requested rate sync_mark = int(self._sync_markers[self._config['rate']]) seq.sync_marker.put(sync_mark) seq.play_mode.put(0) # Run sequence once # Dual (FSL + NSL + XFEL) shots shots = total_shots logging.debug("Configuring for {} dual shots".format(shots)) yield from bps.configure(daq, events=shots) # Preshot dark, so use preshot laser marker dual_seq = self._seq.dualDuringSequence() seq.sequence.put_seq(dual_seq) # Number of shots is determined by sequencer, so just trigger/read print("Taking {} shots shots ... ".format(shots)) yield from bps.trigger_and_read(dets) for det in dets: yield from bps.unstage(det) if end_run: daq.end_run()
def pe_count( filename="", exposure=1, num_images: int = 1, num_dark_images: int = 1, num_repetitions: int = 5, delay=60, ): year = "2020" # RE.md["year"] cycle = "C2" # RE.md["cycle"] proposal = "67890" # RE.md["PROPOSAL"] # write_path_template = 'Z:\\data\\pe1_data\\%Y\\%m\\%d\\' # write_path_template = f"Z:\\users\\{year}\\{cycle}\\{proposal}XRD\\" # file_path = datetime.now().strftime(write_path_template) # filename = filename + str(uuid.uuid4())[:6] # this is an example of what would be used at the beamline pe_detector.tiff_writer.resource_root_path = PureWindowsPath( f"Z:\\users\\") pe_detector.tiff_writer.relative_write_path = PureWindowsPath( f"{year}\\{cycle}\\{proposal}XRD\\") # for testing pe_detector.tiff_writer.resource_root_path = Path("/tmp/") pe_detector.tiff_writer.relative_write_path = Path( f"perkin_elmer/detector/{year}/{cycle}/XRD{proposal}" # remove "XRD" from the end? ) # start the run yield from bps.open_run() # stage the detector yield from bps.stage(pe_detector) yield from bps.mv(pe_detector.tiff_writer.file_number, 1) tiff_full_file_path = (pe_detector.tiff_writer.resource_root_path / pe_detector.tiff_writer.relative_write_path) print(f"tiff_full_file_path: {str(tiff_full_file_path)}") yield from bps.mv(pe_detector.tiff_writer.file_path, str(tiff_full_file_path)) for repetition_index in range(int(num_repetitions)): print("\n") print( "<<<<<<<<<<<<<<<<< Doing repetition {} out of {} >>>>>>>>>>>>>>>>>" .format(repetition_index + 1, num_repetitions)) # TiffWriter or similar plugin should do this yield from bps.mv(pe_detector.tiff_writer.file_name, filename + str(uuid.uuid4())) if num_dark_images > 0: # originally used pe_detector.num_dark_images # but this is really pe_num_offset_frames yield from bps.mv(pe_detector.cam.pe_num_offset_frames, num_dark_images) yield from bps.mv( pe_detector.cam.image_mode, PerkinElmerCamera.PerkinElmerImageMode.AVERAGE, ) # yield from bps.mv(fast_shutter, "Close") yield from bps.sleep(0.5) yield from bps.mv(pe_detector.tiff_writer.file_write_mode, NDFile.FileWriteMode.SINGLE) # acquire a "dark frame" pe_acquire_offset_status = SubscriptionStatus( pe_detector.cam.pe_acquire_offset, high_to_low_pe_acquire_offset) yield from bps.abs_set( pe_detector.cam.pe_acquire_offset, PerkinElmerCamera.AcquireOffset.ACQUIRE, wait=False, ) yield Msg("wait_for_status", None, pe_acquire_offset_status) yield from bps.mv(pe_detector.tiff_writer.write_file, NDFile.WriteFile.WRITE) # yield from bps.mv( # pe1.cam.image_mode, # NewPerkinElmerDetector.ImageMode.MULTIPLE # ) yield from bps.mv( pe_detector.cam.image_mode, PerkinElmerCamera.PerkinElmerImageMode.AVERAGE, ) yield from bps.mv(pe_detector.cam.acquire_time, exposure) yield from bps.mv(pe_detector.cam.num_images, num_images) # yield from bps.mv(fast_shutter, "Open") yield from bps.sleep(0.5) ## Below 'Capture' mode is used with 'Multiple' image_mode # yield from bps.mv(pe1.tiff_writer.file_write_mode, 'Capture') ## Below 'Single' mode is used with 'Average' image_mode yield from bps.mv( pe_detector.tiff_writer.file_write_mode, NDFile.FileWriteMode.SINGLE, # "Single" ) ## Uncomment 'capture' bit settings when used in 'Capture' mode # yield from bps.mv(pe1.tiff_writer.capture, 1) # this was the old way to initiate the acquisition # yield from bps.mv(pe_detector, "acquire_light") yield from bps.trigger_and_read([pe_detector], name="primary") # can TiffWriter or similar plugin do this? ##Below write_file is needed when used in 'Average' mode yield from bps.mv( pe_detector.tiff_writer.write_file, NDFile.WriteFile.WRITE # 1 ) yield from bps.sleep(delay) # unstage the detector yield from bps.unstage(pe_detector) # end the run yield from bps.close_run()
def _single_shot_plan(self, record=True, use_l3t=False, controls=[], end_run=True): """Definition of plan for taking laser shots with the MEC laser.""" # TODO: Add attenuator control logging.debug("Generating shot plan using _shot_plan.") logging.debug("_shot_plan config:") logging.debug("{}".format(self._config)) logging.debug("Record: {}".format(record)) logging.debug("use_l3t: {}".format(use_l3t)) logging.debug("controls: {}".format(controls)) # Make sure that any updates to configuration are applied self.configure(self._config) # Check number of shots for long pulse laser if self._config['laser'] == 'longpulse': lpl_shots = self._config['preo'] + self._config['during'] + \ self._config['posto'] if lpl_shots > 1: m = ("Cannot shoot the long pulse laser more than once in a " "sequence! Please reduce the number of optical shots " "requested to 1!") raise Exception(m) # Setup the daq based on config total_shots = self._config['predark'] + self._config['prex'] + \ self._config['preo'] + self._config['postdark'] + \ self._config['postx'] + self._config['posto'] + \ self._config['during'] print("Configured for {} total shots.".format(total_shots)) logging.debug("Total shots: {}".format(total_shots)) yield from bps.configure(daq, begin_sleep=2, record=record, use_l3t=use_l3t, controls=controls) # Add sequencer, DAQ to detectors for shots dets = [daq, seq] for det in dets: yield from bps.stage(det) # Check for slow cameras, stage if requested if self._config['slowcam']: from .slowcams import SlowCameras self._slowcams = SlowCameras() dets.append(self._slowcams) # Add this in to auto-unstage later yield from bps.stage(self._slowcams) # Setup the pulse picker for single shots in flip flop mode #pp.flipflop(wait=True) # Setup sequencer for requested rate sync_mark = int(self._sync_markers[self._config['rate']]) seq.sync_marker.put(sync_mark) seq.play_mode.put(0) # Run sequence once # Dark (no optical laser, no XFEL) shots if self._config['predark'] > 0: # Get number of predark shots shots = self._config['predark'] logging.debug("Configuring for {} predark shots".format(shots)) yield from bps.configure(daq, events=shots) # Preshot dark, so use preshot laser marker pre_dark_seq = self._seq.darkSequence(shots, preshot=True) seq.sequence.put_seq(pre_dark_seq) # Number of shots is determined by sequencer, so just trigger/read print("Taking {} predark shots ... ".format( self._config['predark'])) yield from bps.trigger_and_read(dets) # Pre-xray (no optical laser, XFEL only) shots if self._config['prex'] > 0: # Get number of prex shots shots = self._config['prex'] logging.debug("Configuring for {} prex shots".format(shots)) yield from bps.configure(daq, events=shots) # Preshot x-ray only shots, so use preshot laser marker prex_seq = self._seq.darkXraySequence(shots, preshot=True) seq.sequence.put_seq(prex_seq) # Number of shots is determined by sequencer, so just trigger/read print("Taking {} prex shots ... ".format(shots)) yield from bps.trigger_and_read(dets) # Pre-optical (optical laser only, no XFEL) shots if self._config['preo'] > 0: # Get number of preo shots shots = self._config['preo'] logging.debug("Configuring for {} preo shots".format(shots)) yield from bps.configure(daq, events=shots) # Optical only shot, with defined laser preo_seq = self._seq.opticalSequence(shots, self._config['laser'],\ preshot=True) seq.sequence.put_seq(preo_seq) # Number of shots is determined by sequencer, so just take 1 count print("Taking {} preo shots ... ".format(shots)) yield from bps.trigger_and_read(dets) # 'During' (optical laser + XFEL) shots if self._config['during'] > 0: # Get number of during shots shots = self._config['during'] logging.debug("Configuring for {} during shots".format(shots)) yield from bps.configure(daq, events=shots) # During shot, with defined laser during_seq = self._seq.duringSequence(shots, self._config['laser']) seq.sequence.put_seq(during_seq) # Number of shots is determined by sequencer, so just take 1 count print("Taking {} during shots ... ".format(shots)) yield from bps.trigger_and_read(dets) # Post-optical (optical laser only, no XFEL) shots if self._config['posto'] > 0: # Get number of post optical shots shots = self._config['posto'] logging.debug("Configuring for {} posto shots".format(shots)) yield from bps.configure(daq, events=shots) # Optical only shot, with defined laser posto_seq = self._seq.opticalSequence(shots, self._config['laser'],\ preshot=False) seq.sequence.put_seq(posto_seq) # Number of shots is determined by sequencer, so just take 1 count print("Taking {} posto shots ... ".format(shots)) yield from bps.trigger_and_read(dets) # Post-xray (no optical laser, XFEL only) shots if self._config['postx'] > 0: # Get number of postx shots shots = self._config['postx'] logging.debug("Configuring for {} postx shots".format(shots)) yield from bps.configure(daq, events=shots) # Postshot x-ray only shots, so use postshot laser marker postx_seq = self._seq.darkXraySequence(shots, preshot=False) seq.sequence.put_seq(postx_seq) # Number of shots is determined by sequencer, so just take 1 count print("Taking {} postx shots ... ".format(shots)) yield from bps.trigger_and_read(dets) # Dark (no optical laser, no XFEL) shots if self._config['postdark'] > 0: # Get number of postdark shots shots = self._config['postdark'] logging.debug("Configuring for {} postdark shots".format(shots)) yield from bps.configure(daq, events=shots) # Postshot dark, so use postshot laser marker post_dark_seq = self._seq.darkSequence(shots, preshot=False) seq.sequence.put_seq(post_dark_seq) # Number of shots is determined by sequencer, so just take 1 count print("Taking {} postdark shots ... ".format(shots)) yield from bps.trigger_and_read(dets) for det in dets: yield from bps.unstage(det) if end_run: daq.end_run()
def drop_daq_msg(msg): if msg.command == 'stage': return (yield from bps.stage(_Dummy())) if msg.command == 'unstage': return (yield from bps.unstage(_Dummy()))
def take_image(self): yield from bps.stage(self) yield from bps.trigger(self, wait=True) yield from bps.unstage(self)
def plan(): yield from open_run() yield from stage(m) yield from unstage(m) yield from close_run()
def __jet_scan(self, motor1, m1start, m1end, m1step, motor2, m2start, m2end, m2step, gasdelay=0.05, shotdelay=10.0, record=True, use_l3t=False, controls=[], end_run=True, carriage_return=True): """ Scan for the LU60 gas jet experiment. Parameters: ----------- motor1 : motor The first motor on which to run the scan. m1start : float The position to start the scan for motor1. The motor will travel to this position prior to beginning the scan. m1end : float The position to end the scan on for motor1. m1steps : float The number of steps for motor 1 motor2 : motor The second motor on which to run the scan. m2start : float The position to start the scan for motor2. The motor will travel to this position prior to beginning the scan. m2end : float The position to end the scan on for motor 2. m2steps : float The number of steps for motor 2. gasdelay : float (default: 0.05) The number of seconds to wait for the gas jet to be ready after the trigger. shotdelay : float (default: 10.0) The number of seconds to wait between shots. This is empirically derived, and is used to allow the chamber pressure to equillibrate following a gas jet puff. record : bool (default: True) Option to record the scan in the DAQ (or not). use_l3t : bool (default: False) Option to use a level 3 trigger (or not) in the scan. controls : list (default: []) Optional list of devices to add to the DAQ data stream. Devices added in this way will have their device.position or device.value quantities added to the scan. end_run : bool (default: True) Option to end the run after the scan. This will cause a new run to be initiated during the next scan. """ logging.debug("Calling __jet_scan with the folling parameters:") logging.debug("motor1: {}".format(motor1)) logging.debug("m1start: {}".format(m1start)) logging.debug("m1end: {}".format(m1end)) logging.debug("m1step: {}".format(m1step)) logging.debug("motor2: {}".format(motor2)) logging.debug("m2start: {}".format(m2start)) logging.debug("m2end: {}".format(m2end)) logging.debug("m2step: {}".format(m2step)) logging.debug("gasdelay: {}".format(gasdelay)) logging.debug("shotdelay: {}".format(shotdelay)) logging.debug("record: {}".format(record)) logging.debug("use_l3t: {}".format(use_l3t)) logging.debug("controls: {}".format(controls)) logging.debug("end_run: {}".format(end_run)) nshots = m1steps * m2steps logging.debug("nsteps: {}".format(nsteps)) print("Configured scan for {} steps...".format(nsteps)) if ((nsteps * 4) + 1) > 2048: raise ValueError("The number of steps cannot be greater than 2048!") yield from bps.configure(daq, begin_sleep=2, record=record, use_l3t=use_l3t, controls=controls) # Add sequencer, DAQ to detectors for shots dets = [daq, seq] for det in dets: yield from bps.stage(det) # Setup sequencer for requested rate sync_mark = int(self._sync_markers[self._config['rate']]) seq.sync_marker.put(sync_mark) seq.play_mode.put(0) # Run sequence once # TODO: determine the different sequences needed. gdelay = int(gasdelay*120) # 120 beam delays/second sdelay = int(shotdelay*120) # 120 beam delays/second slow_cam_seq = [[167, 0, 0, 0]] gas_jet_seq = [[177, 0, 0, 0], [176, gdelay, 0, 0], [169, 0, 0, 0], [0, sdelay, 0, 0]] # TODO: Configure the slow cameras # Get exposure time in beam deltas from number of shots exposure = nshots * (int(shotdelay/120.0) + int(gasdelay/120.0)) logging.debug("Exposure time: {}".format(exposure)) # Stage and add in slow cameras *after* daq is staged and configured slowcams = SlowCameras() # The camera delay and number of 'during' shots are the same in this case config = {'slowcamdelay': exposure, 'during': exposure} dets.append(slowcams) # Add this in to auto-unstage later slowcams.stage(config) m1_step_size = (m1_end-m1_start)/(m1_steps-1) logging.debug("m1 step size: {}".format(m1_step_size)) m2_step_size = (m2_end-m2_start)/(m2_steps-1) logging.debug("m2 step size: {}".format(m2_step_size)) for i in range(m2_steps): new_m2 = m2_start+m2_step_size*i logging.debug("Moving motor2 to {}".format(new_m2)) yield from bps.mv(motor2, new_m2) for j in range(m1_steps): new_m1 = m1_start+m1_step_size*j logging.debug("Moving motor1 to {}".format(new_m1)) yield from bps.mv(motor1, new_m1) # If this is the first shot, use slow cam in sequence if (i == 0) and (j == 0): s = slow_cam_seq + gas_jet_seq else: s = gas_jet_seq # TODO: set this up to run only if the sequence is different? # Do many puts to the test EVG program cause problems? seq.sequence.put_seq(s) # If this is the last move in the scan, check cleanup settings if (i == (m1_steps-1)) and (j == (m2_steps -1)): if carriage_return: # Then go back to start yield from bps.mv(motor1, m1_start) yield from bps.mv(motor2, m2_start) if end_run: daq.end_run()