diff --git a/.ci/bl-specific.sh b/.ci/bl-specific.sh index cf87896..134b8a4 100644 --- a/.ci/bl-specific.sh +++ b/.ci/bl-specific.sh @@ -2,4 +2,17 @@ # cp -v <...> ~/.ipython/profile_${TEST_PROFILE}/ -conda install -y -c ${CONDA_CHANNEL_NAME} 28-id-1-pdf-collection +# xpdacq is already installed in the 'collection-2021-1.2' conda env. +if [ "$CONDA_ENV_NAME" == "collection-2021-1.0" ]; then + conda install -y -c ${CONDA_CHANNEL_NAME} xpdacq +fi + +mkdir -v -p ~/.config/acq/ +mkdir -v -p ~/user_data/config_base/yml/ +sudo mkdir -v -p /mnt/data/bnl/xpdacq_special/data/xpdConfig/ +sudo chown -Rv $USER: /mnt/data/bnl/xpdacq_special/data/xpdConfig/ + +cp -v .ci/pdf.yml ~/.config/acq/ +cp -v .ci/glbl.yml ~/user_data/config_base/yml/ +cp -v .ci/xpd_beamline_config.yml /mnt/data/bnl/xpdacq_special/data/xpdConfig/ + diff --git a/.ci/glbl.yml b/.ci/glbl.yml new file mode 100644 index 0000000..5db2bb9 --- /dev/null +++ b/.ci/glbl.yml @@ -0,0 +1,158 @@ +_dark_dict_list: +- acq_time: 5 + exposure: 5 + timestamp: 1614460063.2800422 + uid: 37d192fb-df2c-44a9-b41b-2a05c9751247 +- acq_time: 5 + exposure: 5 + timestamp: 1614460242.3911414 + uid: cf374ae7-2ed5-4e5d-9563-f4841a3759e9 +- acq_time: 5 + exposure: 5 + timestamp: 1614460464.3035522 + uid: 5fc90d2e-ef96-4ca7-9207-ae72121923d0 +- acq_time: 5 + exposure: !!python/object/apply:numpy.core.multiarray.scalar + - &id001 !!python/object/apply:numpy.dtype + args: + - f8 + - false + - true + state: !!python/tuple + - 3 + - < + - null + - null + - null + - -1 + - -1 + - 0 + - !!binary | + AAAAAAAAFEA= + timestamp: 1614460566.1485345 + uid: 12c2f3ca-b459-4180-a12e-2b2d4b6d5aa8 +- acq_time: 5 + exposure: !!python/object/apply:numpy.core.multiarray.scalar + - *id001 + - !!binary | + AAAAAAAAFEA= + timestamp: 1614464054.0055833 + uid: 5bf51ebe-6439-4815-a9bb-0c824fd3afe8 +- acq_time: 5 + exposure: !!python/object/apply:numpy.core.multiarray.scalar + - *id001 + - !!binary | + AAAAAAAAFEA= + timestamp: 1614464263.5876548 + uid: 25d95820-b20f-4d37-901d-6c96c86462a1 +- acq_time: 5 + exposure: !!python/object/apply:numpy.core.multiarray.scalar + - *id001 + - !!binary | + AAAAAAAAFEA= + timestamp: 1614464433.3411603 + uid: bb969c1c-2e41-4914-91db-3440b576c752 +- acq_time: 5 + exposure: !!python/object/apply:numpy.core.multiarray.scalar + - *id001 + - !!binary | + AAAAAAAAFEA= + timestamp: 1614464443.6444564 + uid: 319ccd2f-7483-459c-96ac-e308b150006e +_exclude_dir: +- /mnt/data/bnl/xpdacq_special/data/user_data +- /mnt/data/bnl/xpdacq_special/data/xpdConfig +- /mnt/data/bnl/xpdacq_special/data/user_data/config_base/yml +_export_tar_dir: +- /mnt/data/bnl/xpdacq_special/data/user_data/config_base +- /mnt/data/bnl/xpdacq_special/data/user_data/userScripts +all_folders: &id002 +- /mnt/data/bnl/xpdacq_special/data/user_data +- /mnt/data/bnl/xpdacq_special/data/xpdConfig +- /mnt/data/bnl/xpdacq_special/data/user_data/config_base/yml +- /mnt/data/bnl/xpdacq_special/data/user_data/config_base +- /mnt/data/bnl/xpdacq_special/data/user_data/config_base/yml/samples +- /mnt/data/bnl/xpdacq_special/data/user_data/config_base/yml/scanplans +- /mnt/data/bnl/xpdacq_special/data/user_data/tiff_base +- /mnt/data/bnl/xpdacq_special/data/user_data/userScripts +- /mnt/data/bnl/xpdacq_special/data/user_data/Import +- /mnt/data/bnl/xpdacq_special/data/user_data/userAnalysis +allfolders: *id002 +archive_base_dir: /mnt/data/bnl/xpdacq_special/archive/.userbeamtimearchive +archive_base_dir_name: .userbeamtimearchive +archive_dir: /mnt/data/bnl/xpdacq_special/archive/.userbeamtimearchive/2021 +archive_root_dir: /mnt/data/bnl/xpdacq_special/archive +auto_dark: true +auto_load_calib: true +base: /mnt/data/bnl/xpdacq_special/data +base_dir: /mnt/data/bnl/xpdacq_special/data +beamline_host_name: +- jupiter +beamline_id: 28-ID-1 +blconfig_dir: /mnt/data/bnl/xpdacq_special/data/xpdConfig +blconfig_dir_name: xpdConfig +blconfig_name: xpd_beamline_config.yml +blconfig_path: /mnt/data/bnl/xpdacq_special/data/xpdConfig/xpd_beamline_config.yml +bt_dir: /mnt/data/bnl/xpdacq_special/data/user_data/config_base/yml +calib_config_name: xpdAcq_calib_info.yml +config_base: /mnt/data/bnl/xpdacq_special/data/user_data/config_base +dark_field_key: sc_dk_field_uid +dark_window: 0.1 +det_image_field: &id003 +- pe1c_image +- pe2c_image +- dexela_image +- dexela +diffraction_dets: +- pe1c +- pe1 +- pe2c +- pe2 +- dexela_image +- dexela +dk_window: 0.1 +exp_broker_name: pdf +exp_hash_uid: f4be92ca-79c1-49ae-9bcd-59c7a8185aa3 +facility: NSLS-II +frame_acq_time: 0.1 +frame_acquire_time: 0.1 +glbl_yaml_name: glbl.yml +glbl_yaml_path: /mnt/data/bnl/xpdacq_special/data/user_data/config_base/yml/glbl.yml +group: XPD +home: /mnt/data/bnl/xpdacq_special/data/user_data +home_dir: /mnt/data/bnl/xpdacq_special/data/user_data +home_dir_name: user_data +image_field: pe1c_image +image_fields: *id003 +import_dir: /mnt/data/bnl/xpdacq_special/data/user_data/Import +inbound_proxy_address: xf28id1-ca1:5577 +is_simulation: false +mask_kwargs: + alpha: 3.0 + bs_width: 13 + edge: 30 + lower_thresh: 0.0 + tri_offset: 13 + v_asym: 0 +name: glbl +outbound_proxy_address: xf28id1-ca1:5578 +owner: PDF +radiogram_dets: +- blackfly_det +radiograph_names: +- blackfly_det +sample_dir: /mnt/data/bnl/xpdacq_special/data/user_data/config_base/yml/samples +scanplan_dir: /mnt/data/bnl/xpdacq_special/data/user_data/config_base/yml/scanplans +shutter_conf: + close: 0 + open: 1 +shutter_control: true +shutter_sleep: 0 +simulation: false +tiff_base: /mnt/data/bnl/xpdacq_special/data/user_data/tiff_base +user_backup_dir_name: '2021' +userscript_dir: /mnt/data/bnl/xpdacq_special/data/user_data/userScripts +usrAnalysis_dir: /mnt/data/bnl/xpdacq_special/data/user_data/userAnalysis +usrScript_dir: /mnt/data/bnl/xpdacq_special/data/user_data/userScripts +xpdconfig: /mnt/data/bnl/xpdacq_special/data/xpdConfig +yaml_dir: /mnt/data/bnl/xpdacq_special/data/user_data/config_base/yml diff --git a/.ci/pdf.yml b/.ci/pdf.yml new file mode 100644 index 0000000..68f84b0 --- /dev/null +++ b/.ci/pdf.yml @@ -0,0 +1,35 @@ +archive_base_dir_name: .userbeamtimearchive +archive_root_dir: /mnt/data/bnl/xpdacq_special/archive +base_dir: /mnt/data/bnl/xpdacq_special/data +beamline_host_name: [jupiter] +beamline_id: 28-ID-1 +blconfig_dir_name: xpdConfig +blconfig_name: xpd_beamline_config.yml +calib_config_name: xpdAcq_calib_info.yml +dark_window: 0.1 +facility: NSLS-II +frame_acquire_time: 0.1 +glbl_yaml_name: glbl.yml +group: XPD +home_dir_name: user_data +image_field: pe1c_image +owner: PDF +simulation: false +shutter_conf: {close: 0, open: 1} +mask_kwargs: + edge: 30 + lower_thresh: 0.0 + bs_width: 13 + tri_offset: 13 + v_asym: 0 + alpha: 3.0 +dark_field_key : sc_dk_field_uid +det_image_field : pe1_image +exp_broker_name: pdf +outbound_proxy_address: 'xf28id1-ca1:5578' +inbound_proxy_address: 'xf28id1-ca1:5577' +shutter_sleep: 0 +diffraction_dets: ['pe1c', 'pe1', 'pe2c', 'pe2','dexela_image', 'dexela'] +radiograph_names : ['blackfly_det'] +radiogram_dets: ['blackfly_det'] +image_fields: ['pe1c_image', 'pe2c_image', 'dexela_image', 'dexela'] diff --git a/.ci/xpd_beamline_config.yml b/.ci/xpd_beamline_config.yml new file mode 100644 index 0000000..f3fa7ed --- /dev/null +++ b/.ci/xpd_beamline_config.yml @@ -0,0 +1,4 @@ +Verification time: '2021-01-09 17:45:59' +Verified by: AUTO VERIFIED IN TEST +hadtoedit: false +is_pytest: false diff --git a/.gitignore b/.gitignore index db2b8df..75ae658 100644 --- a/.gitignore +++ b/.gitignore @@ -86,3 +86,5 @@ db/ static/ history.sqlite Link\ to\ startup + +.vscode/ diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d04fcca..cc97932 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -3,10 +3,13 @@ resources: - repository: templates type: github name: NSLS-II/profile-collection-ci - # ref: refs/heads/ # for future testings on a branch of NSLS-II/profile-collection-ci + ref: refs/heads/main endpoint: github jobs: -- template: azure-linux.yml@templates # Template reference - parameters: - beamline_acronym: PDF + - template: collection-2021-1.0.yml@templates + parameters: + beamline_acronym: PDF + - template: collection-2021-1.2.yml@templates + parameters: + beamline_acronym: PDF diff --git a/env_vars/client_side_qserver_extra b/env_vars/client_side_qserver_extra new file mode 100644 index 0000000..b38b524 --- /dev/null +++ b/env_vars/client_side_qserver_extra @@ -0,0 +1,7 @@ +conda activate 2021-3.1-py37 +OVERLAY=/nsls2/data/pdf/shared/config/bluesky_overlays/2021-3.1-py37 +PATH=$OVERLAY/bin:$PATH +PYTHONPATH=$OVERLAY/lib/python3.7/site-packages:$PYTHONPATH +export PATH +export PYTHONPATH +export BS_ENV=/nsls2/data/pdf/shared/config/profile_collection \ No newline at end of file diff --git a/env_vars/qserver_extra b/env_vars/qserver_extra new file mode 100644 index 0000000..f914178 --- /dev/null +++ b/env_vars/qserver_extra @@ -0,0 +1,2 @@ +export PYTHONPATH=/home/xf28id1/bluesky_overlays/lib/python3.9/site-packages/ +export QSERVER_STARTUP_DIR=/nsls2/data/pdf/shared/config/profile_collection/startup diff --git a/scripts/ramp_ioc.py b/scripts/ramp_ioc.py new file mode 100644 index 0000000..7c077ec --- /dev/null +++ b/scripts/ramp_ioc.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +from textwrap import dedent + +from caproto.server import PVGroup, ioc_arg_parser, pvproperty, run + + +class SimpleIOC(PVGroup): + """ + An IOC with three uncoupled read/writable PVs + + Scalar PVs + ---------- + A (int) + B (float) + + Vectors PVs + ----------- + C (vector of int) + """ + + done = pvproperty( + value=0, + doc="An integer to track if the ramp should be done.", + name="RampDone-Cmd", + ) + delta = pvproperty(value=0.1, doc="The delta of the ramp rate.", name="RampDelta") + take = pvproperty(value=0, doc="If XRD data should be taken", name="TakeXRD-Cmd",) + + +if __name__ == "__main__": + ioc_options, run_options = ioc_arg_parser( + default_prefix="OvenRampControl:", desc=dedent(SimpleIOC.__doc__) + ) + ioc = SimpleIOC(**ioc_options) + run(ioc.pvdb, **run_options) diff --git a/scripts/robo_dan.py b/scripts/robo_dan.py new file mode 100644 index 0000000..84d9f6c --- /dev/null +++ b/scripts/robo_dan.py @@ -0,0 +1,48 @@ +from ophyd import Device, Component as Cpt, EpicsSignal +import time +import datetime + + +class RampControl(Device): + delta = Cpt(EpicsSignal, "RampDelta") + done = Cpt(EpicsSignal, "RampDone-Cmd") + take_xrd = Cpt(EpicsSignal, "TakeXRD-Cmd") + + +temperature = EpicsSignal("XF:28ID1-ES{LS336:1-Chan:C}T-I") +ramp_control = RampControl("OvenRampControl:", name="ramp_control") +power_rbv = EpicsSignal("XF:28ID1-ES{LS336:1-Out:3}Out:Man-RB") +power_sp = EpicsSignal("XF:28ID1-ES{LS336:1-Out:3}Out:Man-SP") + +print(f"{datetime.datetime.now()} Good morning! Robo-dan going to work!") + +while True: + T = temperature.get() + if T is not None and T > 1025: + break + time.sleep(60) + print(f"{datetime.datetime.now()} temperature at {T:.2f}, keep going!") + +print(f"{datetime.datetime.now()} temperature at {T}, Done!!") + +ramp_control.delta.put(0) +print(f"{datetime.datetime.now()} holding for 5 minutes") +time.sleep(60 * 5) + +print(f"{datetime.datetime.now()} starting cooling") +ramp_control.delta.put(-2.5) + +while True: + p = power_rbv.get() + print(f"{datetime.datetime.now()} power currently at {p}, still cooling") + if p < 1: + break + time.sleep(3 * 60) + +time.sleep(5 * 60) +print(f"{datetime.datetime.now()} power low, declare done") +ramp_control.done.put(1) + +time.sleep(5 * 60) +print(f"{datetime.datetime.now()} putting power to 0 just in case") +power_sp.put(0) diff --git a/startup/00-base.py b/startup/00-base.py index 755cf13..9156e75 100644 --- a/startup/00-base.py +++ b/startup/00-base.py @@ -1,3 +1,53 @@ +import xpdacq.xpdacq +xpdacq.xpdacq._inject_calibration_md = lambda msg: msg +xpdacq.xpdacq._inject_calibration_md = lambda msg: msg + + +try: + ############################################################################### + # TODO: remove this block once https://github.com/bluesky/ophyd/pull/959 is + # merged/released. + from datetime import datetime + from ophyd.signal import EpicsSignalBase, EpicsSignal, DEFAULT_CONNECTION_TIMEOUT + + def print_now(): + return datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M:%S.%f") + + def wait_for_connection_base(self, timeout=DEFAULT_CONNECTION_TIMEOUT): + """Wait for the underlying signals to initialize or connect""" + if timeout is DEFAULT_CONNECTION_TIMEOUT: + timeout = self.connection_timeout + # print(f'{print_now()}: waiting for {self.name} to connect within {timeout:.4f} s...') + start = time.time() + try: + self._ensure_connected(self._read_pv, timeout=timeout) + # print(f'{print_now()}: waited for {self.name} to connect for {time.time() - start:.4f} s.') + except TimeoutError: + if self._destroyed: + raise DestroyedError("Signal has been destroyed") + raise + + def wait_for_connection(self, timeout=DEFAULT_CONNECTION_TIMEOUT): + """Wait for the underlying signals to initialize or connect""" + if timeout is DEFAULT_CONNECTION_TIMEOUT: + timeout = self.connection_timeout + # print(f'{print_now()}: waiting for {self.name} to connect within {timeout:.4f} s...') + start = time.time() + self._ensure_connected(self._read_pv, self._write_pv, timeout=timeout) + # print(f'{print_now()}: waited for {self.name} to connect for {time.time() - start:.4f} s.') + + EpicsSignalBase.wait_for_connection = wait_for_connection_base + EpicsSignal.wait_for_connection = wait_for_connection + ############################################################################### + + from ophyd.signal import EpicsSignalBase + + # EpicsSignalBase.set_default_timeout(timeout=10, connection_timeout=10) # old style + EpicsSignalBase.set_defaults(timeout=10, connection_timeout=10) # new style + +except ImportError: + pass + # Make ophyd listen to pyepics. import logging import matplotlib.pyplot @@ -9,20 +59,23 @@ from ophyd.signal import EpicsSignalBase # from Tom Caswell to fix the 'None bug' - whatever that is. DO 7/9/2021 -EpicsSignalBase.set_defaults(timeout=10, connection_timeout=10) +EpicsSignalBase.set_defaults(timeout=10, connection_timeout=1) # See docstring for nslsii.configure_base() for more details # this command takes away much of the boilerplate for settting up a profile # (such as setting up best effort callbacks etc) nslsii.configure_base( get_ipython().user_ns, - 'pdf', + "pdf", pbar=True, bec=True, magics=True, mpl=False, - # publish_documents_to_kafka=True + publish_documents_with_kafka=True ) +del one_1d_step +del one_nd_step +del one_shot from pathlib import Path @@ -54,19 +107,16 @@ def _dump(obj): "Encode as msgpack using numpy-aware encoder." # See https://github.com/msgpack/msgpack-python#string-and-binary-type # for more on use_bin_type. - return msgpack.packb( - obj, - default=msgpack_numpy.encode, - use_bin_type=True) + return msgpack.packb(obj, default=msgpack_numpy.encode, use_bin_type=True) @staticmethod def _load(file): - return msgpack.unpackb( - file, - object_hook=msgpack_numpy.decode, - raw=False) + return msgpack.unpackb(file, object_hook=msgpack_numpy.decode, raw=False) + -runengine_metadata_dir = appdirs.user_data_dir(appname="bluesky") / Path("runengine-metadata") +runengine_metadata_dir = appdirs.user_data_dir(appname="bluesky") / Path( + "runengine-metadata" +) # PersistentDict will create the directory if it does not exist RE.md = PersistentDict(runengine_metadata_dir) @@ -78,32 +128,25 @@ def _load(file): # At the end of every run, verify that files were saved and # print a confirmation message. -#from bluesky.callbacks.broker import verify_files_saved, post_run +# from bluesky.callbacks.broker import verify_files_saved, post_run # RE.subscribe(post_run(verify_files_saved, db), 'stop') # RE.msg_hook = ts_msg_hook -########## New logging 8/24/2020 -import logging -#logging.getLogger('ophyd').handlers[0].setLevel('WARNING') -logger = logging.getLogger('ophyd') -logger.setLevel('WARNING') - -########### +RE.md["facility"] = "NSLS-II" +RE.md["group"] = "PDF" +RE.md["beamline_id"] = "28-ID-1" +RE.md["cycle"] = "2018-1" -RE.md['facility'] = 'NSLS-II' -RE.md['group'] = 'PDF' -RE.md['beamline_id'] = '28-ID-1' -RE.md['cycle'] = '2018-1' def get_user_info(): - ''' This function prompts the user for basic info and - adds it to RE.md. + """This function prompts the user for basic info and + adds it to RE.md. - All data in RE.md gets saved in each start document for each run. + All data in RE.md gets saved in each start document for each run. - ''' + """ print("Please enter the following information for your scan") @@ -111,9 +154,10 @@ def get_user_info(): prop_ID = input("Enter Proposal ID: ") wavelength = input("Enter wavelength: ") - RE.md['PI Name'] = PI_name - RE.md['Proposal ID'] = prop_ID - RE.md['wavelength'] = wavelength + RE.md["PI Name"] = PI_name + RE.md["Proposal ID"] = prop_ID + RE.md["wavelength"] = wavelength + # get_user_info() @@ -122,11 +166,11 @@ def get_user_info(): def which_pvs(cls=None): - ''' returns list of all existing pv's. - cls : class, optional - the class of PV's to search for - defaults to [Device, Signal] - ''' + """returns list of all existing pv's. + cls : class, optional + the class of PV's to search for + defaults to [Device, Signal] + """ if cls is None: cls = [Device, Signal] user_ns = get_ipython().user_ns @@ -146,7 +190,7 @@ def which_pvs(cls=None): def print_all_pvs(): cols = ["Python name", "Ophyd Name"] print("{:20s} \t {:20s}".format(*cols)) - print("="*40) + print("=" * 40) obj_list = which_pvs() for name, obj in obj_list: print("{:20s} \t {:20s}".format(name, obj.name)) @@ -161,7 +205,7 @@ def print_all_pvs(): def print_all_pv_values(): cols = ["Python name", "Time stamp", "Value"] print("{:40s} \t {:20s} \t\t\t {:20s}".format(*cols)) - print("="*120) + print("=" * 120) obj_list = which_pvs() for name, obj in obj_list: try: @@ -170,4 +214,8 @@ def print_all_pv_values(): pass for key, val in ret.items(): - print("{:40s} \t {:20s} \t {}".format(key, time.ctime(val['timestamp']), val['value'])) + print( + "{:40s} \t {:20s} \t {}".format( + key, time.ctime(val["timestamp"]), val["value"] + ) + ) diff --git a/startup/10-machine.py b/startup/10-machine.py index 9295e6d..354408f 100644 --- a/startup/10-machine.py +++ b/startup/10-machine.py @@ -1 +1 @@ -ring_current = EpicsSignalRO('SR:OPS-BI{DCCT:1}I:Real-I', name='ring_current') +ring_current = EpicsSignalRO("SR:OPS-BI{DCCT:1}I:Real-I", name="ring_current") diff --git a/startup/11-temperature-controller.py b/startup/11-temperature-controller.py index 5682d52..6b8e5c5 100644 --- a/startup/11-temperature-controller.py +++ b/startup/11-temperature-controller.py @@ -9,11 +9,12 @@ from nslsii.temperature_controllers import Eurotherm + class CS700TemperatureController(PVPositioner): - readback = C(EpicsSignalRO, 'T-I') - setpoint = C(EpicsSignal, 'T-SP') - done = C(EpicsSignalRO, 'Cmd-Busy') - stop_signal = C(EpicsSignal, 'Cmd-Cmd') + readback = C(EpicsSignalRO, "T-I") + setpoint = C(EpicsSignal, "T-SP") + done = C(EpicsSignalRO, "Cmd-Busy") + stop_signal = C(EpicsSignal, "Cmd-Cmd") def set(self, *args, timeout=None, **kwargs): return super().set(*args, timeout=timeout, **kwargs) @@ -26,6 +27,7 @@ def trigger(self): status._finished() return status + # To allow for sample temperature equilibration time, increase # the `settle_time` parameter (units: seconds). """ @@ -42,54 +44,68 @@ def trigger(self): # eurotherm.timeout.set(1200) # eurotherm.equilibrium_time.set(10) # commented by MA + class Eurotherm(EpicsSignalPositioner): - def set(self, *args, **kwargs): - return super().set(*args, timeout=100000, **kwargs) + def set(self, *args, **kwargs): + return super().set(*args, timeout=100000, **kwargs) + + +eurotherm = Eurotherm( + "XF:28ID1-ES:1{Env:04}T-I", + write_pv="XF:28ID1-ES:1{Env:04}T-SP", + tolerance=5, + name="eurotherm", +) -eurotherm = Eurotherm('XF:28ID1-ES:1{Env:04}T-I', write_pv='XF:28ID1-ES:1{Env:04}T-SP', tolerance = 5, name='eurotherm') class CryoStream(Device): # readback - T = Cpt(EpicsSignalRO, 'T-I') + T = Cpt(EpicsSignalRO, "T-I") # setpoint - setpoint = Cpt(EpicsSignal, read_pv="T-RB", - write_pv="T-SP", - add_prefix=('suffix', 'read_pv', 'write_pv')) + setpoint = Cpt( + EpicsSignal, + read_pv="T-RB", + write_pv="T-SP", + add_prefix=("suffix", "read_pv", "write_pv"), + ) # heater power level - heater = Cpt(EpicsSignal, ':HTR1') + heater = Cpt(EpicsSignal, ":HTR1") # configuration - dead_band = Cpt(EpicsSignal, 'T:AtSP-SP', string=True) - heater_range = Cpt(EpicsSignal, ':HTR1:Range', string=True) + dead_band = Cpt(EpicsSignal, "T:AtSP-SP", string=True) + heater_range = Cpt(EpicsSignal, ":HTR1:Range", string=True) # don't know what this is? - #scan = Cpt(EpicsSignal, ':read.SCAN', string=True) - mode = Cpt(EpicsSignal, ':OUT1:Mode', string=True) - cntrl = Cpt(EpicsSignal, ':OUT1:Cntrl', string=True) + # scan = Cpt(EpicsSignal, ':read.SCAN', string=True) + mode = Cpt(EpicsSignal, ":OUT1:Mode", string=True) + cntrl = Cpt(EpicsSignal, ":OUT1:Cntrl", string=True) # trigger signal - trig = Cpt(EpicsSignal, ':read.PROC') + trig = Cpt(EpicsSignal, ":read.PROC") - #def trigger(self): - #self.trig.put(1, wait=True) - #return DeviceStatus(self, done=True, success=True) + # def trigger(self): + # self.trig.put(1, wait=True) + # return DeviceStatus(self, done=True, success=True) - def __init__(self, *args, read_attrs=None, - configuration_attrs=None, **kwargs): + def __init__(self, *args, read_attrs=None, configuration_attrs=None, **kwargs): if read_attrs is None: - read_attrs = ['T', 'setpoint'] - #if configuration_attrs is None: - #configuration_attrs = ['heater_range', 'dead_band', - #'mode', 'cntrl'] - super().__init__(*args, read_attrs=read_attrs, - configuration_attrs=configuration_attrs, - **kwargs) + read_attrs = ["T", "setpoint"] + # if configuration_attrs is None: + # configuration_attrs = ['heater_range', 'dead_band', + #'mode', 'cntrl'] + super().__init__( + *args, + read_attrs=read_attrs, + configuration_attrs=configuration_attrs, + **kwargs + ) self._target = None self._sts = None def _sts_mon(self, value, **kwargs): - if (self._target is None or - np.abs(self._target - value) < float(self.dead_band.get())): + if self._target is None or np.abs(self._target - value) < float( + self.dead_band.get() + ): self.T.clear_sub(self._sts_mon) - #self.scan.put('Passive', wait=True) + # self.scan.put('Passive', wait=True) if self._sts is not None: self._sts._finished() self._sts = None @@ -97,9 +113,9 @@ def _sts_mon(self, value, **kwargs): def set(self, val): self._target = val - self.setpoint.put(val)#, wait=True) + self.setpoint.put(val) # , wait=True) sts = self._sts = DeviceStatus(self) - #self.scan.put('.2 second') + # self.scan.put('.2 second') self.T.subscribe(self._sts_mon) return sts @@ -110,55 +126,60 @@ def stop(self, *, success=False): self._sts._finished(success=success) self._sts = None self._target = None - #self.scan.put('Passive', wait=True) + # self.scan.put('Passive', wait=True) # TODO: uncomment later once the device is available -cryostream = CryoStream('XF:28ID1-ES:1{Env:01}', name='cryostream') +cryostream = CryoStream("XF:28ID1-ES:1{Env:01}", name="cryostream") class CryoStat1(Device): # readback - T = Cpt(EpicsSignalRO, ':IN1') + T = Cpt(EpicsSignalRO, ":IN1") # setpoint - setpoint = Cpt(EpicsSignal, read_pv=":OUT1:SP_RBV", - write_pv=":OUT1:SP", - add_prefix=('suffix', 'read_pv', 'write_pv')) + setpoint = Cpt( + EpicsSignal, + read_pv=":OUT1:SP_RBV", + write_pv=":OUT1:SP", + add_prefix=("suffix", "read_pv", "write_pv"), + ) # heater power level - heater = Cpt(EpicsSignal, ':HTR1') + heater = Cpt(EpicsSignal, ":HTR1") # configuration - dead_band = Cpt(AttributeSignal, attr='_dead_band') - heater_range = Cpt(EpicsSignal, ':HTR1:Range', string=True) - scan = Cpt(EpicsSignal, ':read.SCAN', string=True) - mode = Cpt(EpicsSignal, ':OUT1:Mode', string=True) - cntrl = Cpt(EpicsSignal, ':OUT1:Cntrl', string=True) + dead_band = Cpt(AttributeSignal, attr="_dead_band") + heater_range = Cpt(EpicsSignal, ":HTR1:Range", string=True) + scan = Cpt(EpicsSignal, ":read.SCAN", string=True) + mode = Cpt(EpicsSignal, ":OUT1:Mode", string=True) + cntrl = Cpt(EpicsSignal, ":OUT1:Cntrl", string=True) # trigger signal - trig = Cpt(EpicsSignal, ':read.PROC') + trig = Cpt(EpicsSignal, ":read.PROC") def trigger(self): self.trig.put(1, wait=True) return DeviceStatus(self, done=True, success=True) - def __init__(self, *args, dead_band, read_attrs=None, - configuration_attrs=None, **kwargs): + def __init__( + self, *args, dead_band, read_attrs=None, configuration_attrs=None, **kwargs + ): if read_attrs is None: - read_attrs = ['T', 'setpoint'] + read_attrs = ["T", "setpoint"] if configuration_attrs is None: - configuration_attrs = ['heater_range', 'dead_band', - 'mode', 'cntrl'] - super().__init__(*args, read_attrs=read_attrs, - configuration_attrs=configuration_attrs, - **kwargs) + configuration_attrs = ["heater_range", "dead_band", "mode", "cntrl"] + super().__init__( + *args, + read_attrs=read_attrs, + configuration_attrs=configuration_attrs, + **kwargs + ) self._target = None self._dead_band = dead_band self._sts = None def _sts_mon(self, value, **kwargs): - if (self._target is None or - np.abs(self._target - value) < self._dead_band): + if self._target is None or np.abs(self._target - value) < self._dead_band: self.T.clear_sub(self._sts_mon) - self.scan.put('Passive', wait=True) + self.scan.put("Passive", wait=True) if self._sts is not None: self._sts._finished() self._sts = None @@ -168,7 +189,7 @@ def set(self, val): self._target = val self.setpoint.put(val, wait=True) sts = self._sts = DeviceStatus(self) - self.scan.put('.2 second') + self.scan.put(".2 second") self.T.subscribe(self._sts_mon) return sts @@ -179,50 +200,56 @@ def stop(self, *, success=False): self._sts._finished(success=success) self._sts = None self._target = None - self.scan.put('Passive', wait=True) + self.scan.put("Passive", wait=True) + class CryoStat2(Device): # readback - T = Cpt(EpicsSignalRO, ':IN2') + T = Cpt(EpicsSignalRO, ":IN2") # setpoint - setpoint = Cpt(EpicsSignal, read_pv=":OUT2:SP_RBV", - write_pv=":OUT2:SP", - add_prefix=('suffix', 'read_pv', 'write_pv')) + setpoint = Cpt( + EpicsSignal, + read_pv=":OUT2:SP_RBV", + write_pv=":OUT2:SP", + add_prefix=("suffix", "read_pv", "write_pv"), + ) # heater power level - heater = Cpt(EpicsSignal, ':HTR2') + heater = Cpt(EpicsSignal, ":HTR2") # configuration - dead_band = Cpt(AttributeSignal, attr='_dead_band') - heater_range = Cpt(EpicsSignal, ':HTR2:Range', string=True) - scan = Cpt(EpicsSignal, ':read.SCAN', string=True) - mode = Cpt(EpicsSignal, ':OUT2:Mode', string=True) - cntrl = Cpt(EpicsSignal, ':OUT2:Cntrl', string=True) + dead_band = Cpt(AttributeSignal, attr="_dead_band") + heater_range = Cpt(EpicsSignal, ":HTR2:Range", string=True) + scan = Cpt(EpicsSignal, ":read.SCAN", string=True) + mode = Cpt(EpicsSignal, ":OUT2:Mode", string=True) + cntrl = Cpt(EpicsSignal, ":OUT2:Cntrl", string=True) # trigger signal - trig = Cpt(EpicsSignal, ':read.PROC') + trig = Cpt(EpicsSignal, ":read.PROC") def trigger(self): self.trig.put(1, wait=True) return DeviceStatus(self, done=True, success=True) - def __init__(self, *args, dead_band, read_attrs=None, - configuration_attrs=None, **kwargs): + def __init__( + self, *args, dead_band, read_attrs=None, configuration_attrs=None, **kwargs + ): if read_attrs is None: - read_attrs = ['T', 'setpoint'] + read_attrs = ["T", "setpoint"] if configuration_attrs is None: - configuration_attrs = ['heater_range', 'dead_band', - 'mode', 'cntrl'] - super().__init__(*args, read_attrs=read_attrs, - configuration_attrs=configuration_attrs, - **kwargs) + configuration_attrs = ["heater_range", "dead_band", "mode", "cntrl"] + super().__init__( + *args, + read_attrs=read_attrs, + configuration_attrs=configuration_attrs, + **kwargs + ) self._target = None self._dead_band = dead_band self._sts = None def _sts_mon(self, value, **kwargs): - if (self._target is None or - np.abs(self._target - value) < self._dead_band): + if self._target is None or np.abs(self._target - value) < self._dead_band: self.T.clear_sub(self._sts_mon) - self.scan.put('Passive', wait=True) + self.scan.put("Passive", wait=True) if self._sts is not None: self._sts._finished() self._sts = None @@ -232,7 +259,7 @@ def set(self, val): self._target = val self.setpoint.put(val, wait=True) sts = self._sts = DeviceStatus(self) - self.scan.put('.2 second') + self.scan.put(".2 second") self.T.subscribe(self._sts_mon) return sts @@ -243,22 +270,23 @@ def stop(self, *, success=False): self._sts._finished(success=success) self._sts = None self._target = None - self.scan.put('Passive', wait=True) + self.scan.put("Passive", wait=True) -cryostat1 = CryoStat1('XF:28ID1-ES1:LS335:{CryoStat}', name='cryostat1', dead_band=1) -cryostat2 = CryoStat2('XF:28ID1-ES1:LS335:{CryoStat}', name='cryostat2', dead_band=1) + +cryostat1 = CryoStat1("XF:28ID1-ES1:LS335:{CryoStat}", name="cryostat1", dead_band=1) +cryostat2 = CryoStat2("XF:28ID1-ES1:LS335:{CryoStat}", name="cryostat2", dead_band=1) # TODO : PV needs to be fixed for done signal # (doesn't work on ramp down) class LinkamFurnace(PVPositioner): - readback = C(EpicsSignalRO, 'TEMP') - setpoint = C(EpicsSignal, 'RAMP:LIMIT:SET') - done = C(EpicsSignalRO, 'STATUS') - stop_signal = C(EpicsSignal, 'RAMP:CTRL:SET') + readback = C(EpicsSignalRO, "TEMP") + setpoint = C(EpicsSignal, "RAMP:LIMIT:SET") + done = C(EpicsSignalRO, "STATUS") + stop_signal = C(EpicsSignal, "RAMP:CTRL:SET") temperature = C(EpicsSignal, "TEMP") def set(self, *args, timeout=None, **kwargs): - + return super().set(*args, timeout=timeout, **kwargs) def trigger(self): @@ -269,35 +297,42 @@ def trigger(self): status._finished() return status + # To allow for sample temperature equilibration time, increase # the `settle_time` parameter (units: seconds). -linkam_furnace = LinkamFurnace('XF:28ID1-ES{LINKAM}:', name='cs700', - settle_time=0) +linkam_furnace = LinkamFurnace("XF:28ID1-ES{LINKAM}:", name="cs700", settle_time=0) linkam_furnace.done_value = 3 linkam_furnace.stop_value = 0 linkam_furnace.setpoint.kind = "normal" linkam_furnace.readback.kind = "normal" -linkam_furnace.readback.name = 'temperature' -linkam_furnace.setpoint.name = 'temperature_setpoint' +linkam_furnace.readback.name = "temperature" +linkam_furnace.setpoint.name = "temperature_setpoint" ## MA class Magnet(PVPositioner): - readback = Cpt(EpicsSignalRO, 'IMAG') - setpoint = Cpt(EpicsSignal, 'SETIPRG') - done = Cpt(EpicsSignalRO, 'SETI-Done1') + readback = Cpt(EpicsSignalRO, "IMAG") + setpoint = Cpt(EpicsSignal, "SETIPRG") + done = Cpt(EpicsSignalRO, "SETI-Done1") + -magnet = Magnet('XF:28ID1-ES{LS625:1}:', name='magnet') -magnet.done_value =0 +magnet = Magnet("XF:28ID1-ES{LS625:1}:", name="magnet") +magnet.done_value = 0 # #########control voltage on eurotherm directly -eurovolt = EpicsSignal('XF:28ID1-ES:1{Env:04}Out-SP', name='eurovolt') +eurovolt = EpicsSignal("XF:28ID1-ES:1{Env:04}Out-SP", name="eurovolt") from collections import deque -from ophyd import (EpicsMotor, PVPositioner, PVPositionerPC, - EpicsSignal, EpicsSignalRO, Device) +from ophyd import ( + EpicsMotor, + PVPositioner, + PVPositionerPC, + EpicsSignal, + EpicsSignalRO, + Device, +) from ophyd import Component as Cpt from ophyd import FormattedComponent as FmtCpt from ophyd import DynamicDeviceComponent as DDC @@ -305,48 +340,55 @@ class Magnet(PVPositioner): class Lakeshore336Setpoint(PVPositioner): - readback = Cpt(EpicsSignalRO, 'T-RB') - setpoint = Cpt(EpicsSignal, 'T-SP') - done = Cpt(EpicsSignalRO, 'Sts:Ramp-Sts') - ramp_enabled = Cpt(EpicsSignal, 'Enbl:Ramp-Sel') - ramp_rate = Cpt(EpicsSignal, 'Val:Ramp-SP') - p_gain = Cpt(EpicsSignal, 'Gain:P-RB', write_pv='Gain:P-SP') - i_gain = Cpt(EpicsSignal, 'Gain:I-RB', write_pv='Gain:I-SP') - d_gain = Cpt(EpicsSignal, 'Gain:D-RB', write_pv='Gain:D-SP') + readback = Cpt(EpicsSignalRO, "T-RB") + setpoint = Cpt(EpicsSignal, "T-SP") + done = Cpt(EpicsSignalRO, "Sts:Ramp-Sts") + ramp_enabled = Cpt(EpicsSignal, "Enbl:Ramp-Sel") + ramp_rate = Cpt(EpicsSignal, "Val:Ramp-SP") + p_gain = Cpt(EpicsSignal, "Gain:P-RB", write_pv="Gain:P-SP") + i_gain = Cpt(EpicsSignal, "Gain:I-RB", write_pv="Gain:I-SP") + d_gain = Cpt(EpicsSignal, "Gain:D-RB", write_pv="Gain:D-SP") done_value = 0 class Lakeshore336Channel(Device): - T = Cpt(EpicsSignalRO, 'T-I') - V = Cpt(EpicsSignalRO, 'Val:Sens-I') - status = Cpt(EpicsSignalRO, 'T-Sts') + T = Cpt(EpicsSignalRO, "T-I") + V = Cpt(EpicsSignalRO, "Val:Sens-I") + status = Cpt(EpicsSignalRO, "T-Sts") def _temp_fields(chans, **kwargs): defn = OrderedDict() for c in chans: - suffix = '-Chan:{}}}'.format(c) + suffix = "-Chan:{}}}".format(c) defn[c] = (Lakeshore336Channel, suffix, kwargs) return defn class Lakeshore336(Device): - temp = DDC(_temp_fields(['A','B','C','D'])) - out1 = Cpt(Lakeshore336Setpoint, '-Out:1}') - out2 = Cpt(Lakeshore336Setpoint, '-Out:2}') - out3 = Cpt(Lakeshore336Setpoint, '-Out:3}') - out4 = Cpt(Lakeshore336Setpoint, '-Out:4}') + temp = DDC(_temp_fields(["A", "B", "C", "D"])) + out1 = Cpt(Lakeshore336Setpoint, "-Out:1}") + out2 = Cpt(Lakeshore336Setpoint, "-Out:2}") + out3 = Cpt(Lakeshore336Setpoint, "-Out:3}") + out4 = Cpt(Lakeshore336Setpoint, "-Out:4}") -lakeshore336 = Lakeshore336('XF:28ID1-ES{LS336:1' , name='lakeshore336') +lakeshore336 = Lakeshore336("XF:28ID1-ES{LS336:1", name="lakeshore336") -hotairblower=Eurotherm('XF:28ID1-ES:1{Env:05}LOOP1:PV:RBV', - write_pv='XF:28ID1-ES:1{Env:05}LOOP1:SP', - tolerance=1,name='hotairblower') +hotairblower = Eurotherm( + "XF:28ID1-ES:1{Env:05}LOOP1:PV:RBV", + write_pv="XF:28ID1-ES:1{Env:05}LOOP1:SP", + tolerance=1, + name="hotairblower", +) -#older hot air blower -#hotairblower=Eurotherm('XF:28ID1-ES:1{Env:03}T-I', +# older hot air blower +# hotairblower=Eurotherm('XF:28ID1-ES:1{Env:03}T-I', # write_pv='XF:28ID1-ES:1{Env:03}T-SP', # tolerance=1,name='hotairblower') -sorensen850_manual = EpicsSignal('XF:28ID1-ES{LS336:1-Out:3}Out:Man-RB', write_pv='XF:28ID1-ES{LS336:1-Out:3}Out:Man-SP', name='sorensen850_manual') +sorensen850_manual = EpicsSignal( + "XF:28ID1-ES{LS336:1-Out:3}Out:Man-RB", + write_pv="XF:28ID1-ES{LS336:1-Out:3}Out:Man-SP", + name="sorensen850_manual", +) diff --git a/startup/11-temperature-controller_py_save.bak b/startup/11-temperature-controller_py_save.bak index 188f551..de47570 100644 --- a/startup/11-temperature-controller_py_save.bak +++ b/startup/11-temperature-controller_py_save.bak @@ -9,10 +9,10 @@ from ophyd import PVPositioner class CS700TemperatureController(PVPositioner): - readback = C(EpicsSignalRO, 'T-I') - setpoint = C(EpicsSignal, 'T-SP') - done = C(EpicsSignalRO, 'Cmd-Busy') - stop_signal = C(EpicsSignal, 'Cmd-Cmd') + readback = C(EpicsSignalRO, "T-I") + setpoint = C(EpicsSignal, "T-SP") + done = C(EpicsSignalRO, "Cmd-Busy") + stop_signal = C(EpicsSignal, "Cmd-Cmd") def set(self, *args, timeout=None, **kwargs): return super().set(*args, timeout=timeout, **kwargs) @@ -25,6 +25,7 @@ class CS700TemperatureController(PVPositioner): status._finished() return status + # To allow for sample temperature equilibration time, increase # the `settle_time` parameter (units: seconds). """ @@ -38,59 +39,70 @@ cs700.setpoint.name = 'temperature_setpoint' # TODO: add later once available + class Eurotherm(EpicsSignalPositioner): def set(self, *args, **kwargs): # override #@!$(#$ hard-coded timeouts return super().set(*args, timeout=1000000, **kwargs) -eurotherm = Eurotherm('XF:28ID1-ES:1{Env:04}T-I', - write_pv='XF:28ID1-ES:1{Env:04}T-SP', - tolerance=1, name='eurotherm') + +eurotherm = Eurotherm( + "XF:28ID1-ES:1{Env:04}T-I", + write_pv="XF:28ID1-ES:1{Env:04}T-SP", + tolerance=1, + name="eurotherm", +) eurotherm.settle_time = 120 class CryoStream(Device): # readback - T = Cpt(EpicsSignalRO, 'T-I') + T = Cpt(EpicsSignalRO, "T-I") # setpoint - setpoint = Cpt(EpicsSignal, read_pv="T-RB", - write_pv="T-SP", - add_prefix=('suffix', 'read_pv', 'write_pv')) + setpoint = Cpt( + EpicsSignal, + read_pv="T-RB", + write_pv="T-SP", + add_prefix=("suffix", "read_pv", "write_pv"), + ) # heater power level - heater = Cpt(EpicsSignal, ':HTR1') + heater = Cpt(EpicsSignal, ":HTR1") # configuration - dead_band = Cpt(EpicsSignal, 'T:AtSP-SP', string=True) - heater_range = Cpt(EpicsSignal, ':HTR1:Range', string=True) + dead_band = Cpt(EpicsSignal, "T:AtSP-SP", string=True) + heater_range = Cpt(EpicsSignal, ":HTR1:Range", string=True) # don't know what this is? - #scan = Cpt(EpicsSignal, ':read.SCAN', string=True) - mode = Cpt(EpicsSignal, ':OUT1:Mode', string=True) - cntrl = Cpt(EpicsSignal, ':OUT1:Cntrl', string=True) + # scan = Cpt(EpicsSignal, ':read.SCAN', string=True) + mode = Cpt(EpicsSignal, ":OUT1:Mode", string=True) + cntrl = Cpt(EpicsSignal, ":OUT1:Cntrl", string=True) # trigger signal - trig = Cpt(EpicsSignal, ':read.PROC') + trig = Cpt(EpicsSignal, ":read.PROC") - #def trigger(self): - #self.trig.put(1, wait=True) - #return DeviceStatus(self, done=True, success=True) + # def trigger(self): + # self.trig.put(1, wait=True) + # return DeviceStatus(self, done=True, success=True) - def __init__(self, *args, read_attrs=None, - configuration_attrs=None, **kwargs): + def __init__(self, *args, read_attrs=None, configuration_attrs=None, **kwargs): if read_attrs is None: - read_attrs = ['T', 'setpoint'] - #if configuration_attrs is None: - #configuration_attrs = ['heater_range', 'dead_band', - #'mode', 'cntrl'] - super().__init__(*args, read_attrs=read_attrs, - configuration_attrs=configuration_attrs, - **kwargs) + read_attrs = ["T", "setpoint"] + # if configuration_attrs is None: + # configuration_attrs = ['heater_range', 'dead_band', + #'mode', 'cntrl'] + super().__init__( + *args, + read_attrs=read_attrs, + configuration_attrs=configuration_attrs, + **kwargs + ) self._target = None self._sts = None def _sts_mon(self, value, **kwargs): - if (self._target is None or - np.abs(self._target - value) < float(self.dead_band.get())): + if self._target is None or np.abs(self._target - value) < float( + self.dead_band.get() + ): self.T.clear_sub(self._sts_mon) - #self.scan.put('Passive', wait=True) + # self.scan.put('Passive', wait=True) if self._sts is not None: self._sts._finished() self._sts = None @@ -98,9 +110,9 @@ class CryoStream(Device): def set(self, val): self._target = val - self.setpoint.put(val)#, wait=True) + self.setpoint.put(val) # , wait=True) sts = self._sts = DeviceStatus(self) - #self.scan.put('.2 second') + # self.scan.put('.2 second') self.T.subscribe(self._sts_mon) return sts @@ -111,55 +123,60 @@ class CryoStream(Device): self._sts._finished(success=success) self._sts = None self._target = None - #self.scan.put('Passive', wait=True) + # self.scan.put('Passive', wait=True) # TODO: uncomment later once the device is available -cryostream = CryoStream('XF:28ID1-ES:1{Env:01}', name='cryostream') +cryostream = CryoStream("XF:28ID1-ES:1{Env:01}", name="cryostream") class CryoStat1(Device): # readback - T = Cpt(EpicsSignalRO, ':IN1') + T = Cpt(EpicsSignalRO, ":IN1") # setpoint - setpoint = Cpt(EpicsSignal, read_pv=":OUT1:SP_RBV", - write_pv=":OUT1:SP", - add_prefix=('suffix', 'read_pv', 'write_pv')) + setpoint = Cpt( + EpicsSignal, + read_pv=":OUT1:SP_RBV", + write_pv=":OUT1:SP", + add_prefix=("suffix", "read_pv", "write_pv"), + ) # heater power level - heater = Cpt(EpicsSignal, ':HTR1') + heater = Cpt(EpicsSignal, ":HTR1") # configuration - dead_band = Cpt(AttributeSignal, attr='_dead_band') - heater_range = Cpt(EpicsSignal, ':HTR1:Range', string=True) - scan = Cpt(EpicsSignal, ':read.SCAN', string=True) - mode = Cpt(EpicsSignal, ':OUT1:Mode', string=True) - cntrl = Cpt(EpicsSignal, ':OUT1:Cntrl', string=True) + dead_band = Cpt(AttributeSignal, attr="_dead_band") + heater_range = Cpt(EpicsSignal, ":HTR1:Range", string=True) + scan = Cpt(EpicsSignal, ":read.SCAN", string=True) + mode = Cpt(EpicsSignal, ":OUT1:Mode", string=True) + cntrl = Cpt(EpicsSignal, ":OUT1:Cntrl", string=True) # trigger signal - trig = Cpt(EpicsSignal, ':read.PROC') + trig = Cpt(EpicsSignal, ":read.PROC") def trigger(self): self.trig.put(1, wait=True) return DeviceStatus(self, done=True, success=True) - def __init__(self, *args, dead_band, read_attrs=None, - configuration_attrs=None, **kwargs): + def __init__( + self, *args, dead_band, read_attrs=None, configuration_attrs=None, **kwargs + ): if read_attrs is None: - read_attrs = ['T', 'setpoint'] + read_attrs = ["T", "setpoint"] if configuration_attrs is None: - configuration_attrs = ['heater_range', 'dead_band', - 'mode', 'cntrl'] - super().__init__(*args, read_attrs=read_attrs, - configuration_attrs=configuration_attrs, - **kwargs) + configuration_attrs = ["heater_range", "dead_band", "mode", "cntrl"] + super().__init__( + *args, + read_attrs=read_attrs, + configuration_attrs=configuration_attrs, + **kwargs + ) self._target = None self._dead_band = dead_band self._sts = None def _sts_mon(self, value, **kwargs): - if (self._target is None or - np.abs(self._target - value) < self._dead_band): + if self._target is None or np.abs(self._target - value) < self._dead_band: self.T.clear_sub(self._sts_mon) - self.scan.put('Passive', wait=True) + self.scan.put("Passive", wait=True) if self._sts is not None: self._sts._finished() self._sts = None @@ -169,7 +186,7 @@ class CryoStat1(Device): self._target = val self.setpoint.put(val, wait=True) sts = self._sts = DeviceStatus(self) - self.scan.put('.2 second') + self.scan.put(".2 second") self.T.subscribe(self._sts_mon) return sts @@ -180,50 +197,56 @@ class CryoStat1(Device): self._sts._finished(success=success) self._sts = None self._target = None - self.scan.put('Passive', wait=True) + self.scan.put("Passive", wait=True) + class CryoStat2(Device): # readback - T = Cpt(EpicsSignalRO, ':IN2') + T = Cpt(EpicsSignalRO, ":IN2") # setpoint - setpoint = Cpt(EpicsSignal, read_pv=":OUT2:SP_RBV", - write_pv=":OUT2:SP", - add_prefix=('suffix', 'read_pv', 'write_pv')) + setpoint = Cpt( + EpicsSignal, + read_pv=":OUT2:SP_RBV", + write_pv=":OUT2:SP", + add_prefix=("suffix", "read_pv", "write_pv"), + ) # heater power level - heater = Cpt(EpicsSignal, ':HTR2') + heater = Cpt(EpicsSignal, ":HTR2") # configuration - dead_band = Cpt(AttributeSignal, attr='_dead_band') - heater_range = Cpt(EpicsSignal, ':HTR2:Range', string=True) - scan = Cpt(EpicsSignal, ':read.SCAN', string=True) - mode = Cpt(EpicsSignal, ':OUT2:Mode', string=True) - cntrl = Cpt(EpicsSignal, ':OUT2:Cntrl', string=True) + dead_band = Cpt(AttributeSignal, attr="_dead_band") + heater_range = Cpt(EpicsSignal, ":HTR2:Range", string=True) + scan = Cpt(EpicsSignal, ":read.SCAN", string=True) + mode = Cpt(EpicsSignal, ":OUT2:Mode", string=True) + cntrl = Cpt(EpicsSignal, ":OUT2:Cntrl", string=True) # trigger signal - trig = Cpt(EpicsSignal, ':read.PROC') + trig = Cpt(EpicsSignal, ":read.PROC") def trigger(self): self.trig.put(1, wait=True) return DeviceStatus(self, done=True, success=True) - def __init__(self, *args, dead_band, read_attrs=None, - configuration_attrs=None, **kwargs): + def __init__( + self, *args, dead_band, read_attrs=None, configuration_attrs=None, **kwargs + ): if read_attrs is None: - read_attrs = ['T', 'setpoint'] + read_attrs = ["T", "setpoint"] if configuration_attrs is None: - configuration_attrs = ['heater_range', 'dead_band', - 'mode', 'cntrl'] - super().__init__(*args, read_attrs=read_attrs, - configuration_attrs=configuration_attrs, - **kwargs) + configuration_attrs = ["heater_range", "dead_band", "mode", "cntrl"] + super().__init__( + *args, + read_attrs=read_attrs, + configuration_attrs=configuration_attrs, + **kwargs + ) self._target = None self._dead_band = dead_band self._sts = None def _sts_mon(self, value, **kwargs): - if (self._target is None or - np.abs(self._target - value) < self._dead_band): + if self._target is None or np.abs(self._target - value) < self._dead_band: self.T.clear_sub(self._sts_mon) - self.scan.put('Passive', wait=True) + self.scan.put("Passive", wait=True) if self._sts is not None: self._sts._finished() self._sts = None @@ -233,7 +256,7 @@ class CryoStat2(Device): self._target = val self.setpoint.put(val, wait=True) sts = self._sts = DeviceStatus(self) - self.scan.put('.2 second') + self.scan.put(".2 second") self.T.subscribe(self._sts_mon) return sts @@ -244,22 +267,23 @@ class CryoStat2(Device): self._sts._finished(success=success) self._sts = None self._target = None - self.scan.put('Passive', wait=True) + self.scan.put("Passive", wait=True) -cryostat1 = CryoStat1('XF:28ID1-ES1:LS335:{CryoStat}', name='cryostat1', dead_band=1) -cryostat2 = CryoStat2('XF:28ID1-ES1:LS335:{CryoStat}', name='cryostat2', dead_band=1) + +cryostat1 = CryoStat1("XF:28ID1-ES1:LS335:{CryoStat}", name="cryostat1", dead_band=1) +cryostat2 = CryoStat2("XF:28ID1-ES1:LS335:{CryoStat}", name="cryostat2", dead_band=1) # TODO : PV needs to be fixed for done signal # (doesn't work on ramp down) class LinkamFurnace(PVPositioner): - readback = C(EpicsSignalRO, 'TEMP') - setpoint = C(EpicsSignal, 'RAMP:LIMIT:SET') - done = C(EpicsSignalRO, 'STATUS') - stop_signal = C(EpicsSignal, 'RAMP:CTRL:SET') + readback = C(EpicsSignalRO, "TEMP") + setpoint = C(EpicsSignal, "RAMP:LIMIT:SET") + done = C(EpicsSignalRO, "STATUS") + stop_signal = C(EpicsSignal, "RAMP:CTRL:SET") temperature = C(EpicsSignal, "TEMP") def set(self, *args, timeout=None, **kwargs): - + return super().set(*args, timeout=timeout, **kwargs) def trigger(self): @@ -270,13 +294,13 @@ class LinkamFurnace(PVPositioner): status._finished() return status + # To allow for sample temperature equilibration time, increase # the `settle_time` parameter (units: seconds). -linkam_furnace = LinkamFurnace('XF:28ID1-ES{LINKAM}:', name='cs700', - settle_time=0) +linkam_furnace = LinkamFurnace("XF:28ID1-ES{LINKAM}:", name="cs700", settle_time=0) linkam_furnace.done_value = 3 linkam_furnace.stop_value = 0 linkam_furnace.setpoint.kind = "normal" linkam_furnace.readback.kind = "normal" -linkam_furnace.readback.name = 'temperature' -linkam_furnace.setpoint.name = 'temperature_setpoint' +linkam_furnace.readback.name = "temperature" +linkam_furnace.setpoint.name = "temperature_setpoint" diff --git a/startup/11-temperature-controller_pyes.bak b/startup/11-temperature-controller_pyes.bak index 32446b8..6e86f05 100644 --- a/startup/11-temperature-controller_pyes.bak +++ b/startup/11-temperature-controller_pyes.bak @@ -8,10 +8,10 @@ from ophyd import PVPositioner class CS700TemperatureController(PVPositioner): - readback = C(EpicsSignalRO, 'T-I') - setpoint = C(EpicsSignal, 'T-SP') - done = C(EpicsSignalRO, 'Cmd-Busy') - stop_signal = C(EpicsSignal, 'Cmd-Cmd') + readback = C(EpicsSignalRO, "T-I") + setpoint = C(EpicsSignal, "T-SP") + done = C(EpicsSignalRO, "Cmd-Busy") + stop_signal = C(EpicsSignal, "Cmd-Cmd") def set(self, *args, timeout=None, **kwargs): return super().set(*args, timeout=timeout, **kwargs) @@ -24,6 +24,7 @@ class CS700TemperatureController(PVPositioner): status._finished() return status + # To allow for sample temperature equilibration time, increase # the `settle_time` parameter (units: seconds). """ @@ -47,48 +48,55 @@ eurotherm = Eurotherm('XF:28IDC-ES:1{Env:04}T-I', tolerance= 3, name='eurotherm') """ + class CryoStream(Device): # readback - T = Cpt(EpicsSignalRO, 'T-I') + T = Cpt(EpicsSignalRO, "T-I") # setpoint - setpoint = Cpt(EpicsSignal, read_pv="T-RB", - write_pv="T-SP", - add_prefix=('suffix', 'read_pv', 'write_pv')) + setpoint = Cpt( + EpicsSignal, + read_pv="T-RB", + write_pv="T-SP", + add_prefix=("suffix", "read_pv", "write_pv"), + ) # heater power level - heater = Cpt(EpicsSignal, ':HTR1') + heater = Cpt(EpicsSignal, ":HTR1") # configuration - dead_band = Cpt(EpicsSignal, 'T:AtSP-SP', string=True) - heater_range = Cpt(EpicsSignal, ':HTR1:Range', string=True) + dead_band = Cpt(EpicsSignal, "T:AtSP-SP", string=True) + heater_range = Cpt(EpicsSignal, ":HTR1:Range", string=True) # don't know what this is? - #scan = Cpt(EpicsSignal, ':read.SCAN', string=True) - mode = Cpt(EpicsSignal, ':OUT1:Mode', string=True) - cntrl = Cpt(EpicsSignal, ':OUT1:Cntrl', string=True) + # scan = Cpt(EpicsSignal, ':read.SCAN', string=True) + mode = Cpt(EpicsSignal, ":OUT1:Mode", string=True) + cntrl = Cpt(EpicsSignal, ":OUT1:Cntrl", string=True) # trigger signal - trig = Cpt(EpicsSignal, ':read.PROC') + trig = Cpt(EpicsSignal, ":read.PROC") - #def trigger(self): - #self.trig.put(1, wait=True) - #return DeviceStatus(self, done=True, success=True) + # def trigger(self): + # self.trig.put(1, wait=True) + # return DeviceStatus(self, done=True, success=True) - def __init__(self, *args, read_attrs=None, - configuration_attrs=None, **kwargs): + def __init__(self, *args, read_attrs=None, configuration_attrs=None, **kwargs): if read_attrs is None: - read_attrs = ['T', 'setpoint'] - #if configuration_attrs is None: - #configuration_attrs = ['heater_range', 'dead_band', - #'mode', 'cntrl'] - super().__init__(*args, read_attrs=read_attrs, - configuration_attrs=configuration_attrs, - **kwargs) + read_attrs = ["T", "setpoint"] + # if configuration_attrs is None: + # configuration_attrs = ['heater_range', 'dead_band', + #'mode', 'cntrl'] + super().__init__( + *args, + read_attrs=read_attrs, + configuration_attrs=configuration_attrs, + **kwargs + ) self._target = None self._sts = None def _sts_mon(self, value, **kwargs): - if (self._target is None or - np.abs(self._target - value) < float(self.dead_band.get())): + if self._target is None or np.abs(self._target - value) < float( + self.dead_band.get() + ): self.T.clear_sub(self._sts_mon) - #self.scan.put('Passive', wait=True) + # self.scan.put('Passive', wait=True) if self._sts is not None: self._sts._finished() self._sts = None @@ -96,9 +104,9 @@ class CryoStream(Device): def set(self, val): self._target = val - self.setpoint.put(val)#, wait=True) + self.setpoint.put(val) # , wait=True) sts = self._sts = DeviceStatus(self) - #self.scan.put('.2 second') + # self.scan.put('.2 second') self.T.subscribe(self._sts_mon) return sts @@ -109,55 +117,61 @@ class CryoStream(Device): self._sts._finished(success=success) self._sts = None self._target = None - #self.scan.put('Passive', wait=True) + # self.scan.put('Passive', wait=True) # TODO: uncomment later once the device is available -cryostream = CryoStream('XF:28ID1-ES:1{Env:01}', name='cryostream') +cryostream = CryoStream("XF:28ID1-ES:1{Env:01}", name="cryostream") + class CryoStat(Device): # readback - T = Cpt(EpicsSignalRO, ':IN1') + T = Cpt(EpicsSignalRO, ":IN1") # setpoint - setpoint = Cpt(EpicsSignal, read_pv=":OUT1:SP_RBV", - write_pv=":OUT1:SP", - add_prefix=('suffix', 'read_pv', 'write_pv')) + setpoint = Cpt( + EpicsSignal, + read_pv=":OUT1:SP_RBV", + write_pv=":OUT1:SP", + add_prefix=("suffix", "read_pv", "write_pv"), + ) # heater power level - heater = Cpt(EpicsSignal, ':HTR1') + heater = Cpt(EpicsSignal, ":HTR1") # configuration - dead_band = Cpt(AttributeSignal, attr='_dead_band') - heater_range = Cpt(EpicsSignal, ':HTR1:Range', string=True) - scan = Cpt(EpicsSignal, ':read.SCAN', string=True) - mode = Cpt(EpicsSignal, ':OUT1:Mode', string=True) - cntrl = Cpt(EpicsSignal, ':OUT1:Cntrl', string=True) + dead_band = Cpt(AttributeSignal, attr="_dead_band") + heater_range = Cpt(EpicsSignal, ":HTR1:Range", string=True) + scan = Cpt(EpicsSignal, ":read.SCAN", string=True) + mode = Cpt(EpicsSignal, ":OUT1:Mode", string=True) + cntrl = Cpt(EpicsSignal, ":OUT1:Cntrl", string=True) # trigger signal - trig = Cpt(EpicsSignal, ':read.PROC') + trig = Cpt(EpicsSignal, ":read.PROC") def trigger(self): self.trig.put(1, wait=True) return DeviceStatus(self, done=True, success=True) - def __init__(self, *args, dead_band, read_attrs=None, - configuration_attrs=None, **kwargs): + def __init__( + self, *args, dead_band, read_attrs=None, configuration_attrs=None, **kwargs + ): if read_attrs is None: - read_attrs = ['T', 'setpoint'] + read_attrs = ["T", "setpoint"] if configuration_attrs is None: - configuration_attrs = ['heater_range', 'dead_band', - 'mode', 'cntrl'] - super().__init__(*args, read_attrs=read_attrs, - configuration_attrs=configuration_attrs, - **kwargs) + configuration_attrs = ["heater_range", "dead_band", "mode", "cntrl"] + super().__init__( + *args, + read_attrs=read_attrs, + configuration_attrs=configuration_attrs, + **kwargs + ) self._target = None self._dead_band = dead_band self._sts = None def _sts_mon(self, value, **kwargs): - if (self._target is None or - np.abs(self._target - value) < self._dead_band): + if self._target is None or np.abs(self._target - value) < self._dead_band: self.T.clear_sub(self._sts_mon) - self.scan.put('Passive', wait=True) + self.scan.put("Passive", wait=True) if self._sts is not None: self._sts._finished() self._sts = None @@ -167,7 +181,7 @@ class CryoStat(Device): self._target = val self.setpoint.put(val, wait=True) sts = self._sts = DeviceStatus(self) - self.scan.put('.2 second') + self.scan.put(".2 second") self.T.subscribe(self._sts_mon) return sts @@ -178,22 +192,22 @@ class CryoStat(Device): self._sts._finished(success=success) self._sts = None self._target = None - self.scan.put('Passive', wait=True) + self.scan.put("Passive", wait=True) -cryostat = CryoStat('XF:28ID1-ES1:LS335:{CryoStat}', name='cryostat', dead_band=1) +cryostat = CryoStat("XF:28ID1-ES1:LS335:{CryoStat}", name="cryostat", dead_band=1) # TODO : PV needs to be fixed for done signal # (doesn't work on ramp down) class LinkamFurnace(PVPositioner): - readback = C(EpicsSignalRO, 'TEMP') - setpoint = C(EpicsSignal, 'RAMP:LIMIT:SET') - done = C(EpicsSignalRO, 'STATUS') - stop_signal = C(EpicsSignal, 'RAMP:CTRL:SET') + readback = C(EpicsSignalRO, "TEMP") + setpoint = C(EpicsSignal, "RAMP:LIMIT:SET") + done = C(EpicsSignalRO, "STATUS") + stop_signal = C(EpicsSignal, "RAMP:CTRL:SET") temperature = C(EpicsSignal, "TEMP") def set(self, *args, timeout=None, **kwargs): - + return super().set(*args, timeout=timeout, **kwargs) def trigger(self): @@ -204,13 +218,13 @@ class LinkamFurnace(PVPositioner): status._finished() return status + # To allow for sample temperature equilibration time, increase # the `settle_time` parameter (units: seconds). -linkam_furnace = LinkamFurnace('XF:28ID1-ES{LINKAM}:', name='cs700', - settle_time=0) +linkam_furnace = LinkamFurnace("XF:28ID1-ES{LINKAM}:", name="cs700", settle_time=0) linkam_furnace.done_value = 3 linkam_furnace.stop_value = 0 linkam_furnace.setpoint.kind = "normal" linkam_furnace.readback.kind = "normal" -linkam_furnace.readback.name = 'temperature' -linkam_furnace.setpoint.name = 'temperature_setpoint' +linkam_furnace.readback.name = "temperature" +linkam_furnace.setpoint.name = "temperature_setpoint" diff --git a/startup/12-motors.py b/startup/12-motors.py index f05813c..5d94d0f 100644 --- a/startup/12-motors.py +++ b/startup/12-motors.py @@ -1,84 +1,168 @@ import ophyd from ophyd import (Device, Component as Cpt, EpicsSignal, EpicsSignalRO, EpicsMotor) -from nslsii.devices import TwoButtonShutter +from ophyd.device import DeviceStatus +from nslsii.devices import TwoButtonShutter as _TwoButtonShutter #import nslsii.devices -Det_1_X = EpicsMotor('XF:28ID1B-ES{Det:1-Ax:X}Mtr', name='Det_1_X', labels=['positioners']) -Det_1_Y = EpicsMotor('XF:28ID1B-ES{Det:1-Ax:Y}Mtr', name='Det_1_Y', labels=['positioners']) -Det_1_Z = EpicsMotor('XF:28ID1B-ES{Det:1-Ax:Z}Mtr', name='Det_1_Z', labels=['positioners']) - -Det_2_X = EpicsMotor('XF:28ID1B-ES{Det:2-Ax:X}Mtr', name='Det_2_X', labels=['positioners']) -Det_2_Y = EpicsMotor('XF:28ID1B-ES{Det:2-Ax:Y}Mtr', name='Det_2_Y', labels=['positioners']) -Det_2_Z = EpicsMotor('XF:28ID1B-ES{Det:2-Ax:Z}Mtr', name='Det_2_Z', labels=['positioners']) - -Grid_X = EpicsMotor('XF:28ID1B-ES{Env:1-Ax:X}Mtr', name='Grid_X', labels=['positioners']) -Grid_Y = EpicsMotor('XF:28ID1B-ES{Env:1-Ax:Y}Mtr', name='Grid_Y', labels=['positioners']) -Grid_Z = EpicsMotor('XF:28ID1B-ES{Env:1-Ax:Z}Mtr', name='Grid_Z', labels=['positioners']) +# import nslsii.devices + +Det_1_X = EpicsMotor( + "XF:28ID1B-ES{Det:1-Ax:X}Mtr", name="Det_1_X", labels=["positioners"] +) +Det_1_Y = EpicsMotor( + "XF:28ID1B-ES{Det:1-Ax:Y}Mtr", name="Det_1_Y", labels=["positioners"] +) +Det_1_Z = EpicsMotor( + "XF:28ID1B-ES{Det:1-Ax:Z}Mtr", name="Det_1_Z", labels=["positioners"] +) + +Det_2_X = EpicsMotor( + "XF:28ID1B-ES{Det:2-Ax:X}Mtr", name="Det_2_X", labels=["positioners"] +) +Det_2_Y = EpicsMotor( + "XF:28ID1B-ES{Det:2-Ax:Y}Mtr", name="Det_2_Y", labels=["positioners"] +) +Det_2_Z = EpicsMotor( + "XF:28ID1B-ES{Det:2-Ax:Z}Mtr", name="Det_2_Z", labels=["positioners"] +) + +Grid_X = EpicsMotor( + "XF:28ID1B-ES{Env:1-Ax:X}Mtr", name="Grid_X", labels=["positioners"] +) +Grid_Y = EpicsMotor( + "XF:28ID1B-ES{Env:1-Ax:Y}Mtr", name="Grid_Y", labels=["positioners"] +) +Grid_Z = EpicsMotor( + "XF:28ID1B-ES{Env:1-Ax:Z}Mtr", name="Grid_Z", labels=["positioners"] +) # Beam stop motors class BeamStop(Device): - x = Cpt(EpicsMotor, 'X}Mtr') - y = Cpt(EpicsMotor, 'Y}Mtr') + x = Cpt(EpicsMotor, "X}Mtr") + y = Cpt(EpicsMotor, "Y}Mtr") -BStop1 = BeamStop('XF:28ID1B-ES{BS:1-Ax:', name='BStop1') -BStop2 = BeamStop('XF:28ID1B-ES{BS:2-Ax:', name='BStop2') + +BStop1 = BeamStop("XF:28ID1B-ES{BS:1-Ax:", name="BStop1") +BStop2 = BeamStop("XF:28ID1B-ES{BS:2-Ax:", name="BStop2") # OCM table widget class OCMTable(Device): - ocm_y_upstream = Cpt(EpicsMotor, 'YU}Mtr') - ocm_y_downstream = Cpt(EpicsMotor, 'YD}Mtr') - ocm_x_table = Cpt(EpicsMotor, 'X}Mtr') + ocm_y_upstream = Cpt(EpicsMotor, "YU}Mtr") + ocm_y_downstream = Cpt(EpicsMotor, "YD}Mtr") + ocm_x_table = Cpt(EpicsMotor, "X}Mtr") + -OCM_table = OCMTable('XF:28ID1B-ES{OCM-Ax:', name='OCM_table') +OCM_table = OCMTable("XF:28ID1B-ES{OCM-Ax:", name="OCM_table") -ECS_tel_guide = EpicsMotor('XF:28ID1B-ES{ECS-Ax:X}Mtr', name='ECS_tel_guide') +ECS_tel_guide = EpicsMotor("XF:28ID1B-ES{ECS-Ax:X}Mtr", name="ECS_tel_guide") class ECS(Device): - laser_y = Cpt(EpicsMotor, 'Lsr:1-Ax:Y}Mtr') - reflective_foil_x = Cpt(EpicsMotor, 'Foil:1-Ax:X}Mtr') - filter_wheel_1_phi = Cpt(EpicsMotor, 'Fltr:Whl1-Ax:Phi}Mtr') - filter_wheel_2_phi = Cpt(EpicsMotor, 'Fltr:Whl2-Ax:Phi}Mtr') + laser_y = Cpt(EpicsMotor, "Lsr:1-Ax:Y}Mtr") + reflective_foil_x = Cpt(EpicsMotor, "Foil:1-Ax:X}Mtr") + filter_wheel_1_phi = Cpt(EpicsMotor, "Fltr:Whl1-Ax:Phi}Mtr") + filter_wheel_2_phi = Cpt(EpicsMotor, "Fltr:Whl2-Ax:Phi}Mtr") -ECS_laser_foil_filter = ECS('XF:28ID1B-ES{', name='ECS_laser_foil_filter') +ECS_laser_foil_filter = ECS("XF:28ID1B-ES{", name="ECS_laser_foil_filter") -class FilterBank(Device): - flt1 = Cpt(EpicsSignal, '1}Cmd:Opn-Cmd', string=True) - flt2 = Cpt(EpicsSignal, '2}Cmd:Opn-Cmd', string=True) - flt3 = Cpt(EpicsSignal, '3}Cmd:Opn-Cmd', string=True) - flt4 = Cpt(EpicsSignal, '4}Cmd:Opn-Cmd', string=True) +class FilterBank(Device): + flt1 = Cpt(EpicsSignal, "1}Cmd:Opn-Cmd", string=True) + flt2 = Cpt(EpicsSignal, "2}Cmd:Opn-Cmd", string=True) + flt3 = Cpt(EpicsSignal, "3}Cmd:Opn-Cmd", string=True) + flt4 = Cpt(EpicsSignal, "4}Cmd:Opn-Cmd", string=True) + + + +class TwoButtonShutter(_TwoButtonShutter): + def stop(self): + ... + def set(self, value): + if value == 0: + return super().set('Close') + #super().set('Close') + #status = DeviceStatus(self) + #return status + if value == 1: + return super().set('Open') + # super().set('Open') + # status = DeviceStatus(self) + # return status + + def read(self): #fix for whoever thought it was smart to use 'Not Open' instead of 'Close' - DO + ret = super().read() + val = ret['fb_two_button_shutters_flt1_status']['value'] + if val == 'Not Open': + ret['fb_two_button_shutters_flt1_status']['value'] = 'Close' + return ret + + # def read(self): + # ret = super().read() + # # FIX RET + # return ret class FilterBankTwoButtonShutter(Device): - flt1 = Cpt(TwoButtonShutter, '1}') - flt2 = Cpt(TwoButtonShutter, '2}') - flt3 = Cpt(TwoButtonShutter, '3}') - flt4 = Cpt(TwoButtonShutter, '4}') + flt1 = Cpt(TwoButtonShutter, "1}") + flt2 = Cpt(TwoButtonShutter, "2}") + flt3 = Cpt(TwoButtonShutter, "3}") + flt4 = Cpt(TwoButtonShutter, "4}") -fb = FilterBank('XF:28ID1B-OP{Fltr:', name='fb') -fb_two_button_shutters = FilterBankTwoButtonShutter('XF:28ID1B-OP{Fltr:', name='fb_two_button_shutters') -# Spinner Goniohead motors, add by HZ -Spinnergo_X = EpicsMotor('XF:28ID1B-ES{Stg:Smpl-Ax:X}Mtr', name='Spinnergo_X', labels=['positioners']) -Spinnergo_Y = EpicsMotor('XF:28ID1B-ES{Stg:Smpl-Ax:Y}Mtr', name='Spinnergo_Y', labels=['positioners']) -Spinnergo_Z = EpicsMotor('XF:28ID1B-ES{Stg:Smpl-Ax:Z}Mtr', name='Spinnergo_Z', labels=['positioners']) -Spinnergo_Ry = EpicsMotor('XF:28ID1B-ES{Stg:Smpl-Ax:Ry}Mtr', name='Spinnergo_Ry', labels=['positioners']) +fb = FilterBank("XF:28ID1B-OP{Fltr:", name="fb") +fb_two_button_shutters = FilterBankTwoButtonShutter( + "XF:28ID1B-OP{Fltr:", name="fb_two_button_shutters" +) -Tomo_spinner = EpicsMotor('XF:28ID1B-ES{Smpl:Chngr-Ax:YRot}Mtr', name='Tomo_spinner', labels=['positiioners']) +#trying to make a temporary shutter - DO - 5/18/2022 +#fs = fb_two_button_shutters.flt4 +#if disable this, need to re-enable fs in 15-optics: line 105 - -#ECS diffractometer Added by MA -ECS_Sam_tth = EpicsMotor('XF:28ID1B-ES{ECS-Ax:2Th1}Mtr', name='ECS_Sam_tth', labels=['positioners']) -ECS_An_tth = EpicsMotor('XF:28ID1B-ES{ECS-Ax:2Th2}Mtr', name='ECS_An_tth', labels=['positioners']) -ECS_An_th = EpicsMotor('XF:28ID1B-ES{ECS-Ax:Th2}Mtr', name='ECS_An_th', labels=['positioners']) - -#detector for ECS - DO and MA -ECS_det1 = EpicsSignalRO( 'XF:28IDC-BI:1{IM:1}:C4_1' ,name='ECS_det1') - -#45-degree shifting motor on M6-grid, for use with hot air blower / cryostream with angled sample bracket -broadside45_shifter = EpicsMotor('XF:28ID1B-ES{Smpl:Array-Ax:Horiz}Mtr', name='broadside45_shifter') +# Spinner Goniohead motors, add by HZ +Spinnergo_X = EpicsMotor( + "XF:28ID1B-ES{Stg:Smpl-Ax:X}Mtr", name="Spinnergo_X", labels=["positioners"] +) +Spinnergo_Y = EpicsMotor( + "XF:28ID1B-ES{Stg:Smpl-Ax:Y}Mtr", name="Spinnergo_Y", labels=["positioners"] +) +Spinnergo_Z = EpicsMotor( + "XF:28ID1B-ES{Stg:Smpl-Ax:Z}Mtr", name="Spinnergo_Z", labels=["positioners"] +) +Spinnergo_Ry = EpicsMotor( + "XF:28ID1B-ES{Stg:Smpl-Ax:Ry}Mtr", name="Spinnergo_Ry", labels=["positioners"] +) + +Tomo_spinner = EpicsMotor( + "XF:28ID1B-ES{Smpl:Chngr-Ax:YRot}Mtr", name="Tomo_spinner", labels=["positiioners"] +) + + +# ECS diffractometer Added by MA +ECS_Sam_tth = EpicsMotor( + "XF:28ID1B-ES{ECS-Ax:2Th1}Mtr", name="ECS_Sam_tth", labels=["positioners"] +) +ECS_An_tth = EpicsMotor( + "XF:28ID1B-ES{ECS-Ax:2Th2}Mtr", name="ECS_An_tth", labels=["positioners"] +) +ECS_An_th = EpicsMotor( + "XF:28ID1B-ES{ECS-Ax:Th2}Mtr", name="ECS_An_th", labels=["positioners"] +) + +# detector for ECS - DO and MA +ECS_det1 = EpicsSignalRO("XF:28IDC-BI:1{IM:1}:C4_1", name="ECS_det1") + +# 45-degree shifting motor on M6-grid, for use with hot air blower / cryostream with angled sample bracket +broadside45_shifter = EpicsMotor( + "XF:28ID1B-ES{Smpl:Array-Ax:Horiz}Mtr", name="broadside45_shifter" +) #NOx BOx x/y sample position noxbox_x = EpicsMotor('XF:28ID1B-ES{NOx-Ax:X}Mtr', name='noxbox_x') noxbox_y = EpicsMotor('XF:28ID1B-ES{NOx-Ax:Y}Mtr', name='noxbox_y') + + +#Table X-tages +OT_stage_1_X = EpicsMotor('XF:28ID1-ES{Det-Ax:X1}Mtr', name='OT_stage_1_X', labels=['positioners']) +OT_stage_2_X = EpicsMotor('XF:28ID1-ES{Det-Ax:X2}Mtr', name='OT_stage_2_X', labels=['positioners']) +OT_stage_3_X = EpicsMotor('XF:28ID1-ES{Det-Ax:X3}Mtr', name='OT_stage_3_X', labels=['positioners']) +OT_stage_4_X = EpicsMotor('XF:28ID1-ES{Det-Ax:X4}Mtr', name='OT_stage_4_X', labels=['positioners']) diff --git a/startup/12-sorensen.py b/startup/12-sorensen.py new file mode 100644 index 0000000..ec1adba --- /dev/null +++ b/startup/12-sorensen.py @@ -0,0 +1,908 @@ +from ophyd import EpicsSignal +import numpy as np +import bluesky.plan_stubs as bps +import bluesky.preprocessors as bpp +import time as ttime + + +# This is fixed in ophyd 1.6.2 +def _paranoid_set_and_wait( + signal, val, poll_time=0.01, timeout=10, rtol=None, atol=None +): + """Set a signal to a value and wait until it reads correctly. + + For floating point values, it is strongly recommended to set a tolerance. + If tolerances are unset, the values will be compared exactly. + + Parameters + ---------- + signal : EpicsSignal (or any object with `get` and `put`) + val : object + value to set signal to + poll_time : float, optional + how soon to check whether the value has been successfully set + timeout : float, optional + maximum time to wait for value to be successfully set + rtol : float, optional + allowed relative tolerance between the readback and setpoint values + atol : float, optional + allowed absolute tolerance between the readback and setpoint values + + Raises + ------ + TimeoutError if timeout is exceeded + """ + from bluesky.utils.epics_pvs import _compare_maybe_enum, logger + import time as ttime + + signal.put(val) + expiration_time = ttime.time() + timeout if timeout is not None else None + current_value = signal.get() + + if atol is None and hasattr(signal, "tolerance"): + atol = signal.tolerance + if rtol is None and hasattr(signal, "rtolerance"): + rtol = signal.rtolerance + + try: + enum_strings = signal.enum_strs + except AttributeError: + enum_strings = () + + if atol is not None: + within_str = ["within {!r}".format(atol)] + else: + within_str = [] + + if rtol is not None: + within_str.append("(relative tolerance of {!r})".format(rtol)) + + if within_str: + within_str = " ".join([""] + within_str) + else: + within_str = "" + + while current_value is None or not _compare_maybe_enum( + val, current_value, enum_strings, atol, rtol + ): + logger.debug( + "Waiting for %s to be set from %r to %r%s...", + signal.name, + current_value, + val, + within_str, + ) + ttime.sleep(poll_time) + if poll_time < 0.1: + poll_time *= 2 # logarithmic back-off + current_value = signal.get() + if expiration_time is not None and ttime.time() > expiration_time: + raise TimeoutError( + "Attempted to set %r to value %r and timed " + "out after %r seconds. Current value is %r." + % (signal, val, timeout, current_value) + ) + + +class ParnoidEpicsSignal(EpicsSignal): + def _set_and_wait(self, val): + return _paranoid_set_and_wait( + self, value, timeout=timeout, atol=self.tolerance, rtol=self.rtolerance + ) + + def get(self): + ret = super().get() + for j in range(5): + if ret is not None: + return ret + ttime.sleep(0.1) + ret = super().get() + else: + raise RuntimeError("getting all nones") + + +sorensen850_manual = ParnoidEpicsSignal( + "XF:28ID1-ES{LS336:1-Out:3}Out:Man-RB", + write_pv="XF:28ID1-ES{LS336:1-Out:3}Out:Man-SP", + name="sorensen850_manual", + tolerance=0.1, +) +import uuid +import bluesky.plans as bp + +lakeshore336.read_attrs = ["temp", "temp.C", "temp.C.T"] +lakeshore336.temp.C.T.kind = "hinted" + + +def power_ramp(start, stop, steps, *, exposure, settle_time=0, n_per_hold=1, **kwargs): + ramp_uid = str(uuid.uuid4()) + for p in np.linspace(start, stop, steps): + yield from bps.mv(sorensen850_manual, p) + if settle_time > 0: + yield from bps.sleep(settle_time) + for j in range(n_per_hold): + yield from bpp.baseline_wrapper( + simple_ct( + [pe1c] + [sorensen850_manual, lakeshore336], + md={"ramp_uid": ramp_uid}, + **kwargs, + exposure=exposure, + ), + [lakeshore336, ring_current, sorensen850_manual], + ) + + +from pathlib import Path +import pandas as pd + + +def write_single_calibration_data_to_csv_and_make_tom_sad(uid, path=Path(".")): + h = db[uid] + tbl = h.table() + tbl["delta"] = (tbl.time - tbl.time.iloc[0]).dt.total_seconds() + tbl = tbl.set_index(tbl["delta"]) + + power = tbl["sorensen850_manual"].mean() + T_start = tbl["lakeshore336_temp_C_T"].iloc[0] + T_stop = tbl["lakeshore336_temp_C_T"].iloc[-1] + + out = path / f"power_{power:.2f}-Tstart_{T_start:.2f}-Tstop_{T_stop:.2f}.csv" + tbl[["lakeshore336_temp_C_T"]].to_csv(out) + + return tbl + + +def write_calibration_data_to_csv_and_make_tom_sad( + uid_list, *, fname=None, stream_name="primary" +): + if len(uid_list) and isinstance(uid_list[0], str): + headers = [db[uid] for uid in uid_list] + else: + headers = uid_list + headers = sorted(headers, key=lambda h: h.start["time"]) + + merged_table = pd.concat([h.table(stream_name=stream_name) for h in headers]) + dt = (merged_table["time"] - merged_table["time"].iloc[0]).dt.total_seconds() + dt.name = "delta_time" + merged_table = merged_table.set_index(dt) + + if fname is not None: + merged_table.to_csv(fname) + return merged_table + + +from bluesky.utils import RunEngineControlException + + +def power_calibration_ramp(power_levels, *, hold_time, n_per_hold=10, path): + ramp_uid = str(uuid.uuid4()) + out_uids = [] + + def inner(): + for p in power_levels: + yield from bps.mv(sorensen850_manual, p) + try: + uid = yield from bp.count( + [lakeshore336, sorensen850_manual], + num=n_per_hold, + delay=hold_time / n_per_hold, + md={"ramp_uid": ramp_uid, "purpose": "sorensen calibration"}, + ) + out_uids.append(uid) + except RunEngineControlException: + raise + except Exception as e: + # We want to prioritize this not crashing over night + print(e) + continue + else: + write_calibration_data_to_csv_and_make_tom_sad(out_uids, path) + return out_uids + + def cleanup(): + yield from bps.mv(sorensen850_manual, 0) + + return (yield from bpp.finalize_wrapper(inner(), cleanup)) + + +class RampControl(Device): + delta = Cpt(EpicsSignal, "RampDelta") + done = Cpt(EpicsSignal, "RampDone-Cmd") + take_xrd = Cpt(EpicsSignal, "TakeXRD-Cmd") + + +ramp_control = RampControl("OvenRampControl:", name="ramp_control") + +try: + from bluesky.plan_stubs import rd +except ImportError: + + def rd(obj, *, default_value=0): + """Reads a single-value non-triggered object + + This is a helper plan to get the scalar value out of a Device + (such as an EpicsMotor or a single EpicsSignal). + + For devices that have more than one read key the following rules are used: + + - if exactly 1 field is hinted that value is used + - if no fields are hinted and there is exactly 1 value in the + reading that value is used + - if more than one field is hinted an Exception is raised + - if no fields are hinted and there is more than one key in the reading an + Exception is raised + + The devices is not triggered and this plan does not create any Events + + Parameters + ---------- + obj : Device + The device to be read + + default_value : Any + The value to return when not running in a "live" RunEngine. + This come ups when :: + + ret = yield Msg('read', obj) + assert ret is None + + the plan is passed to `list` or some other iterator that + repeatedly sends `None` into the plan to advance the + generator. + + Returns + ------- + val : Any or None + The "single" value of the device + + """ + hints = getattr(obj, "hints", {}).get("fields", []) + if len(hints) > 1: + msg = ( + f"Your object {obj} ({obj.name}.{getattr(obj, 'dotted_name', '')}) " + f"has {len(hints)} items hinted ({hints}). We do not know how to " + "pick out a single value. Please adjust the hinting by setting the " + "kind of the components of this device or by rd ing one of it's components" + ) + raise ValueError(msg) + elif len(hints) == 0: + hint = None + if hasattr(obj, "read_attrs"): + if len(obj.read_attrs) != 1: + msg = ( + f"Your object {obj} ({obj.name}.{getattr(obj, 'dotted_name', '')}) " + f"and has {len(obj.read_attrs)} read attrs. We do not know how to " + "pick out a single value. Please adjust the hinting/read_attrs by " + "setting the kind of the components of this device or by rd ing one " + "of its components" + ) + + raise ValueError(msg) + # len(hints) == 1 + else: + (hint,) = hints + + ret = yield from read(obj) + + # list-ify mode + if ret is None: + return default_value + + if hint is not None: + return ret[hint]["value"] + + # handle the no hint 1 field case + try: + (data,) = ret.values() + except ValueError as er: + msg = ( + f"Your object {obj} ({obj.name}.{getattr(obj, 'dotted_name', '')}) " + f"and has {len(ret)} read values. We do not know how to pick out a " + "single value. Please adjust the hinting/read_attrs by setting the " + "kind of the components of this device or by rd ing one of its components" + ) + + raise ValueError(msg) from er + else: + return data["value"] + + +from dataclasses import dataclass + + +@dataclass(frozen=True) +class MotorPositions: + beamstop_x: float + beamstop_y: float + detector: float + + +near_positions = MotorPositions( + beamstop_x=-17.02152375, beamstop_y=0.717885, detector=3857.0 +) +far_positions = MotorPositions( + beamstop_x=-16.541525, beamstop_y=0.437885, detector=4973.0 +) + +from xpdacq.beamtime import close_shutter_stub + + +def power_ramp_controlled( + *, + min_power_pct: float = 0, + max_power_pct: float = 1, # max 100 + exposure: float, + n_per_step=1, + beamtime, + xrd_sample_name: str, + pdf_sample_name: str, + near_positions, + far_positions, + diagostic_T_file=None, + ramp_uid=None, +): + """ + Plan to take externally controlled temperature ramps. + + This plan consults two PVs to determine the current ramp rate (delta) and + if enough data has been collected and we should exit (more graceful than ctrl-C). + + At each hold point *n_per_point* sets of xrd and pdf will be taken. The + hold time per temperature will be approximately + + hold_time = (2*exposure + 70)*n_per_point + + Parameters + ---------- + min_power_pct : float + The minimum power (as a perentage) to give the heater + max_power_pct : float + The maxmimum power (as a percentage) to give the heater + exposure : float + Exposure time in seconds for each shot + n_per_step : int, optional + The number of exposures to take at each power step + beamtime : xpdacq.xpdacq.Beamtime + Used to get the sample meta-data + xrd_sample_name : str + Looked up in beamtime to get sample meta-data + pdf_sample_same : str + Looked up in beamtime to get sample meta-data + near_positions, far_positions : MotorPositions + The location of the beamstop and detector for "near" (PDF) and "far" (XRD) + measurements + diagsostic_T_file : Path + If you must. + """ + if ramp_uid is None: + ramp_uid = str(uuid.uuid4()) + xrd_sample = beamtime.samples[xrd_sample_name] + pdf_sample = beamtime.samples[pdf_sample_name] + + detector_motor = Det_1_Z + beam_stop = BStop1 + + baseline_detectors = [ + lakeshore336, + ring_current, + beam_stop, + detector_motor, + Grid_X, + Grid_Y, + Grid_Z, + sorensen850_manual, + ] + main_detectors = [pe1c, sorensen850_manual] + + motor_snap_shot_for_dan = { + k: globals()[k].read() for k in ["Grid_X", "Grid_Y", "Grid_Z"] + } + + def collect_cycle(ramp_phase, delta=0): + # PDF measurement + print("/n/nmoving to PDF distance/n") + yield from bps.mv( + beam_stop.x, + near_positions.beamstop_x, + beam_stop.y, + near_positions.beamstop_y, + detector_motor, + near_positions.detector, + ) + pdf_uid = yield from bpp.baseline_wrapper( + simple_ct( + main_detectors, + md={ + "ramp_uid": ramp_uid, + "ramp_phase": ramp_phase, + **pdf_sample, + **motor_snap_shot_for_dan, + "delta": delta, + }, + exposure=exposure, + ), + baseline_detectors, + ) + yield from close_shutter_stub() + # XRD measurement + print("/n/nmoving to XRD position/n") + take_xrd = yield from rd(ramp_control.take_xrd) + if take_xrd: + yield from bps.mv( + beam_stop.x, + far_positions.beamstop_x, + beam_stop.y, + far_positions.beamstop_y, + detector_motor, + far_positions.detector, + ) + xrd_uid = yield from bpp.baseline_wrapper( + simple_ct( + main_detectors, + md={ + "ramp_uid": ramp_uid, + "ramp_phase": ramp_phase, + **xrd_sample, + **motor_snap_shot_for_dan, + }, + exposure=exposure, + ), + baseline_detectors, + ) + yield from close_shutter_stub() + return [] + + uids = [] + + yield from bps.mv(ramp_control.done, 0) + + p = yield from rd(sorensen850_manual, default_value=min_power_pct) + print(f"starting at power {p}") + yield from bps.mv(sorensen850_manual, p) + + # for reasons TAC does not understand this is returning [None, None] + # suspect it is due to one of the xpdacq wrappers not forwarding returs? + data_uids = yield from collect_cycle("initial") + uids.extend(data_uids) + + done = yield from rd(ramp_control.done, default_value=True) + while not done: + delta = yield from rd(ramp_control.delta) + if delta > 0: + ramp_phase = "rising" + elif delta < 0: + ramp_phase = "falling" + else: + ramp_phase = "holding" + + p = np.clip(p + delta, min_power_pct, max_power_pct) + print(f"\n\n moving to {p} with {delta} step") + + yield from bps.mv(sorensen850_manual, p) + + for j in range(n_per_step): + print( + "\n\ntemperature is currently " + + str(lakeshore336.read()["lakeshore336_temp_C_T"]["value"]) + ) + print("on step " + str(j) + " of " + str(n_per_step)) + data_uids = yield from collect_cycle(ramp_phase, delta) + uids.extend(data_uids) + if diagostic_T_file is not None: + + write_calibration_data_to_csv_and_make_tom_sad( + list(db(ramp_uid=ramp_uid)), + fname=diagostic_T_file, + stream_name="baseline", + ) + done = yield from rd(ramp_control.done, default_value=True) + + uids.append((yield from collect_cycle("final"))) + return uids + + +# TODO reuse the code from above, but copy-paste for not to be sure +# we do not introduce bugs while refactoring. +def power_ramp_sequence( + *, + power_pct_seq, + exposure: float, + n_per_step=1, + beamtime, + xrd_sample_name: str, + pdf_sample_name: str, + near_positions, + far_positions, + diagostic_T_file=None, +): + """ + Plan to take externally controlled temperature ramps. + + This plan consults two PVs to determine the current ramp rate (delta) and + if enough data has been collected and we should exit (more graceful than ctrl-C). + + At each hold point *n_per_point* sets of xrd and pdf will be taken. The + hold time per temperature will be approximately + + hold_time = (2*exposure + 70)*n_per_point + + Parameters + ---------- + power_pct : Iterable[float] + Sequence of power precentages + exposure : float + Exposure time in seconds for each shot + n_per_step : int, optional + The number of exposures to take at each power step + beamtime : xpdacq.xpdacq.Beamtime + Used to get the sample meta-data + xrd_sample_name : str + Looked up in beamtime to get sample meta-data + pdf_sample_same : str + Looked up in beamtime to get sample meta-data + near_positions, far_positions : MotorPositions + The location of the beamstop and detector for "near" (PDF) and "far" (XRD) + measurements + diagsostic_T_file : Path + If you must. + """ + ramp_uid = str(uuid.uuid4()) + xrd_sample = beamtime.samples[xrd_sample_name] + pdf_sample = beamtime.samples[pdf_sample_name] + + detector_motor = Det_1_Z + beam_stop = BStop1 + + baseline_detectors = [ + lakeshore336, + ring_current, + beam_stop, + detector_motor, + Grid_X, + Grid_Y, + Grid_Z, + sorensen850_manual, + ] + main_detectors = [pe1c, sorensen850_manual] + + motor_snap_shot_for_dan = { + k: globals()[k].read() for k in ["Grid_X", "Grid_Y", "Grid_Z"] + } + + def collect_cycle(ramp_phase, delta=0): + # PDF measurement + print("\n\nmoving to PDF distance\n") + yield from bps.mv( + beam_stop.x, + near_positions.beamstop_x, + beam_stop.y, + near_positions.beamstop_y, + detector_motor, + near_positions.detector, + ) + pdf_uid = yield from bpp.baseline_wrapper( + simple_ct( + main_detectors, + md={ + "ramp_uid": ramp_uid, + "ramp_phase": ramp_phase, + **pdf_sample, + **motor_snap_shot_for_dan, + "delta": delta, + }, + exposure=exposure, + ), + baseline_detectors, + ) + yield from close_shutter_stub() + take_xrd = yield from rd(ramp_control.take_xrd) + if take_xrd: + # XRD measurement + print("\n\nmoving to XRD position\n") + yield from bps.mv( + beam_stop.x, + far_positions.beamstop_x, + beam_stop.y, + far_positions.beamstop_y, + detector_motor, + far_positions.detector, + ) + xrd_uid = yield from bpp.baseline_wrapper( + simple_ct( + main_detectors, + md={ + "ramp_uid": ramp_uid, + "ramp_phase": ramp_phase, + **xrd_sample, + **motor_snap_shot_for_dan, + }, + exposure=exposure, + ), + baseline_detectors, + ) + yield from close_shutter_stub() + return [] + + uids = [] + + first_power, power_seq_tail = power_pct_seq + + yield from bps.mv(sorensen850_manual, first_power) + + # for reasons TAC does not understand this is returning [None, None] + # suspect it is due to one of the xpdacq wrappers not forwarding returs? + data_uids = yield from collect_cycle("initial") + uids.extend(data_uids) + + last_power = first_power + for p in power_seq_tail: + delta = p - last_power + last_power = p + if delta > 0: + ramp_phase = "rising" + elif delta < 0: + ramp_phase = "falling" + else: + ramp_phase = "holding" + + print(f"\n\n!!Moving to power {p} with delta {delta}") + yield from bps.mv(sorensen850_manual, p) + + for j in range(n_per_step): + print( + "/n/ntemperature is currently " + + str(lakeshore336.read()["lakeshore336_temp_C_T"]["value"]) + ) + print("on step " + str(j) + " of " + str(n_per_step)) + data_uids = yield from collect_cycle(ramp_phase, delta) + uids.extend(data_uids) + if diagostic_T_file is not None: + + write_calibration_data_to_csv_and_make_tom_sad( + list(db(ramp_uid=ramp_uid)), + fname=diagostic_T_file, + stream_name="baseline", + ) + + uids.extend((yield from collect_cycle("final"))) + return uids + + +# TODO reuse the code from above, but copy-paste for not to be sure +# we do not introduce bugs while refactoring. +def power_ramp_T_threshold( + *, + start_power_pct, + max_temperature, + delta_power, + max_power_pct, + exposure: float, + n_per_step=1, + beamtime, + xrd_sample_name: str, + pdf_sample_name: str, + near_positions, + far_positions, + diagostic_T_file=None, +): + """ + Plan to take externally controlled temperature ramps. + + This plan consults two PVs to determine the current ramp rate (delta) and + if enough data has been collected and we should exit (more graceful than ctrl-C). + + At each hold point *n_per_point* sets of xrd and pdf will be taken. The + hold time per temperature will be approximately + + hold_time = (2*exposure + 70)*n_per_point + + Parameters + ---------- + exposure : float + Exposure time in seconds for each shot + n_per_step : int, optional + The number of exposures to take at each power step + beamtime : xpdacq.xpdacq.Beamtime + Used to get the sample meta-data + xrd_sample_name : str + Looked up in beamtime to get sample meta-data + pdf_sample_same : str + Looked up in beamtime to get sample meta-data + near_positions, far_positions : MotorPositions + The location of the beamstop and detector for "near" (PDF) and "far" (XRD) + measurements + diagsostic_T_file : Path + If you must. + """ + ramp_uid = str(uuid.uuid4()) + xrd_sample = beamtime.samples[xrd_sample_name] + pdf_sample = beamtime.samples[pdf_sample_name] + + detector_motor = Det_1_Z + beam_stop = BStop1 + + baseline_detectors = [ + lakeshore336, + ring_current, + beam_stop, + detector_motor, + Grid_X, + Grid_Y, + Grid_Z, + sorensen850_manual, + ] + main_detectors = [pe1c, sorensen850_manual] + + motor_snap_shot_for_dan = { + k: globals()[k].read() for k in ["Grid_X", "Grid_Y", "Grid_Z"] + } + + def collect_cycle(ramp_phase, delta=0): + # PDF measurement + print("\n\nmoving to PDF distance\n") + yield from bps.mv( + beam_stop.x, + near_positions.beamstop_x, + beam_stop.y, + near_positions.beamstop_y, + detector_motor, + near_positions.detector, + ) + pdf_uid = yield from bpp.baseline_wrapper( + simple_ct( + main_detectors, + md={ + "ramp_uid": ramp_uid, + "ramp_phase": ramp_phase, + **pdf_sample, + **motor_snap_shot_for_dan, + "delta": delta, + }, + exposure=exposure, + ), + baseline_detectors, + ) + yield from close_shutter_stub() + take_xrd = yield from rd(ramp_control.take_xrd) + if take_xrd: + # XRD measurement + print("\n\nmoving to XRD position\n") + yield from bps.mv( + beam_stop.x, + far_positions.beamstop_x, + beam_stop.y, + far_positions.beamstop_y, + detector_motor, + far_positions.detector, + ) + xrd_uid = yield from bpp.baseline_wrapper( + simple_ct( + main_detectors, + md={ + "ramp_uid": ramp_uid, + "ramp_phase": ramp_phase, + **xrd_sample, + **motor_snap_shot_for_dan, + }, + exposure=exposure, + ), + baseline_detectors, + ) + yield from close_shutter_stub() + return [] + + uids = [] + + p = start_power_pct + + yield from bps.mv(sorensen850_manual, p) + + # for reasons TAC does not understand this is returning [None, None] + # suspect it is due to one of the xpdacq wrappers not forwarding returs? + data_uids = yield from collect_cycle("initial") + uids.extend(data_uids) + + reversed = False + + delta = delta_power + while True: + p = np.clip(p + delta, 0, max_power_pct) + T = yield from rd(lakeshore336) + if T > max_temperature and not reversed: + delta = -delta + if delta > 0: + ramp_phase = "rising" + elif delta < 0: + ramp_phase = "falling" + else: + ramp_phase = "holding" + + print(f"\n\n!!Moving to power {p} with delta {delta}") + yield from bps.mv(sorensen850_manual, p) + + for j in range(n_per_step): + print( + "\n\ntemperature is currently " + + str(lakeshore336.read()["lakeshore336_temp_C_T"]["value"]) + ) + print("on step " + str(j) + " of " + str(n_per_step)) + data_uids = yield from collect_cycle(ramp_phase, delta) + uids.extend(data_uids) + if diagostic_T_file is not None: + + write_calibration_data_to_csv_and_make_tom_sad( + list(db(ramp_uid=ramp_uid)), + fname=diagostic_T_file, + stream_name="baseline", + ) + if p <= 0: + break + + uids.extend((yield from collect_cycle("final"))) + return uids + + +def bring_to_temperature(power_supply, thermo, *, out_path): + first_time = None + + def writer_call_back(name, doc): + nonlocal first_time + + if name != "event": + return + if first_time is None: + first_time = doc["time"] + with open(out_path, "a+") as fout: + data = [ + str(doc["data"][k]) + for k in ["sorensen850_manual", "lakeshore336_temp_C_T"] + ] + data_str = ",".join(data) + fout.write(f'{doc["time"] - first_time},{data_str}\n') + + condition_time = 5 * 60 + condition_steps = 15 + sub_condition_time = condition_time / condition_steps + + condition_temperature_step = 50 + + def condition_loop(): + print(f"entering {condition_time}s hold") + for i in range(condition_steps): + print(f" stage {i} / {condition_steps}") + yield from bps.trigger_and_read([power_supply, thermo]) + yield from bps.sleep(sub_condition_time) + yield from bps.trigger_and_read([power_supply, thermo]) + + @bpp.subs_decorator(writer_call_back) + @bpp.run_decorator() + def inner(): + yield from bps.trigger_and_read([power_supply, thermo]) + for p in np.arange(2.5, 30.0001, 0.1): + yield from bps.mv(power_supply, p) + yield from bps.checkpoint() + yield from bps.sleep(5) + yield from bps.trigger_and_read([power_supply, thermo]) + + yield from condition_loop() + + T = yield from rd(thermo) + t_target = T + condition_temperature_step + p_cur = yield from rd(power_supply) + while t_target < 1000: + + while T < t_target: + p_cur += 0.1 + yield from bps.mv(power_supply, p_cur) + yield from bps.checkpoint() + yield from bps.sleep(5) + yield from bps.trigger_and_read([power_supply, thermo]) + T = yield from rd(thermo) + + t_target += condition_temperature_step + + yield from condition_loop() + print(f"new_target {t_target}") + + ret = yield from inner() + return ret diff --git a/startup/13-gas_handling.py b/startup/13-gas_handling.py index 0a62aea..e7ef4a5 100644 --- a/startup/13-gas_handling.py +++ b/startup/13-gas_handling.py @@ -1,25 +1,27 @@ from ophyd import Device, Component as Cpt, EpicsSignal, EpicsSignalRO from ophyd import OrderedDict + class RGA(Device): - mass1 = Cpt(EpicsSignal, 'Mass:MID1-SP') - partial_pressure1 = Cpt(EpicsSignalRO, 'P:MID1-I') - mass2 = Cpt(EpicsSignal, 'Mass:MID2-SP') - partial_pressure2 = Cpt(EpicsSignalRO, 'P:MID2-I') - mass3 = Cpt(EpicsSignal, 'Mass:MID3-SP') - partial_pressure3 = Cpt(EpicsSignalRO, 'P:MID3-I') - mass4 = Cpt(EpicsSignal, 'Mass:MID4-SP') - partial_pressure4 = Cpt(EpicsSignalRO, 'P:MID4-I') - mass5 = Cpt(EpicsSignal, 'Mass:MID5-SP') - partial_pressure5 = Cpt(EpicsSignalRO, 'P:MID5-I') - mass6 = Cpt(EpicsSignal, 'Mass:MID6-SP') - partial_pressure6 = Cpt(EpicsSignalRO, 'P:MID6-I') - mass7 = Cpt(EpicsSignal, 'Mass:MID7-SP') - partial_pressure7 = Cpt(EpicsSignalRO, 'P:MID7-I') - mass8 = Cpt(EpicsSignal, 'Mass:MID8-SP') - partial_pressure8 = Cpt(EpicsSignalRO, 'P:MID8-I') - mass9 = Cpt(EpicsSignal, 'Mass:MID9-SP') - partial_pressure9 = Cpt(EpicsSignalRO, 'P:MID9-I') + mass1 = Cpt(EpicsSignal, "Mass:MID1-SP") + partial_pressure1 = Cpt(EpicsSignalRO, "P:MID1-I") + mass2 = Cpt(EpicsSignal, "Mass:MID2-SP") + partial_pressure2 = Cpt(EpicsSignalRO, "P:MID2-I") + mass3 = Cpt(EpicsSignal, "Mass:MID3-SP") + partial_pressure3 = Cpt(EpicsSignalRO, "P:MID3-I") + mass4 = Cpt(EpicsSignal, "Mass:MID4-SP") + partial_pressure4 = Cpt(EpicsSignalRO, "P:MID4-I") + mass5 = Cpt(EpicsSignal, "Mass:MID5-SP") + partial_pressure5 = Cpt(EpicsSignalRO, "P:MID5-I") + mass6 = Cpt(EpicsSignal, "Mass:MID6-SP") + partial_pressure6 = Cpt(EpicsSignalRO, "P:MID6-I") + mass7 = Cpt(EpicsSignal, "Mass:MID7-SP") + partial_pressure7 = Cpt(EpicsSignalRO, "P:MID7-I") + mass8 = Cpt(EpicsSignal, "Mass:MID8-SP") + partial_pressure8 = Cpt(EpicsSignalRO, "P:MID8-I") + mass9 = Cpt(EpicsSignal, "Mass:MID9-SP") + partial_pressure9 = Cpt(EpicsSignalRO, "P:MID9-I") + -rga = RGA('XF:28ID1-ES{RGA:1}', name='rga') +rga = RGA("XF:28ID1-ES{RGA:1}", name="rga") diff --git a/startup/15-optics.py b/startup/15-optics.py index c3998e9..4f68d74 100644 --- a/startup/15-optics.py +++ b/startup/15-optics.py @@ -6,22 +6,24 @@ from ophyd.sim import NullStatus + class Slits(Device): - top = Cpt(EpicsMotor, 'T}Mtr') - bottom = Cpt(EpicsMotor, 'B}Mtr') - inboard = Cpt(EpicsMotor, 'I}Mtr') - outboard = Cpt(EpicsMotor, 'O}Mtr') - ''' TODO : Add later + top = Cpt(EpicsMotor, "T}Mtr") + bottom = Cpt(EpicsMotor, "B}Mtr") + inboard = Cpt(EpicsMotor, "I}Mtr") + outboard = Cpt(EpicsMotor, "O}Mtr") + """ TODO : Add later xc = Cpt(EpicsMotor, 'XCtr}Mtr') xg = Cpt(EpicsMotor, 'XGap}Mtr') yc = Cpt(EpicsMotor, 'YCtr}Mtr') yg = Cpt(EpicsMotor, 'YGap}Mtr') - ''' + """ + -ocm_slits = Slits('XF:28ID1B-OP{Slt:2-Ax:', name='ocm_slits') # OCM Slits -bdm_slits = Slits('XF:28ID1A-OP{Slt:1-Ax:', name='bdm_slits') # BD Slits -#Added by MA 09/03/2019 -wb_slits = Slits('XF:28ID1A-OP{Slt:0-Ax:', name='wb_slits') # WB Slits +ocm_slits = Slits("XF:28ID1B-OP{Slt:2-Ax:", name="ocm_slits") # OCM Slits +bdm_slits = Slits("XF:28ID1A-OP{Slt:1-Ax:", name="bdm_slits") # BD Slits +# Added by MA 09/03/2019 +wb_slits = Slits("XF:28ID1A-OP{Slt:0-Ax:", name="wb_slits") # WB Slits class SideBounceMono(Device): @@ -34,115 +36,125 @@ class SideBounceMono(Device): twist = Cpt(EpicsMotor, "Twist}Mtr") sbm = SideBounceMono("XF:28ID1A-OP{Mono:SBM-Ax:", name='sbm') -# Shutters: -#fs = EpicsSignal('XF:28ID1B-OP{PSh:1-Det:2}Cmd', name='fs') # fast shutter #temporary fast shutter -# class tempFSShutter: +#class tempFSShutter: # -# def set(self, value): -# if value == 0: -# return fb_two_button_shutters.flt4.set('Close') -# elif value == 1: -# return fb_two_button_shutters.flt4.set('Open') +# def set(self, value): +# if value == 0: +# return fb_two_button_shutters.flt1.set('Close') +# elif value == 1: +# return fb_two_button_shutters.flt1.set('Open') # -# def read(self): -# return fb_two_button_shutters.read() +# def read(self): +# return fb_two_button_shutters.read() # -# def describe(self): -# return fb_two_button_shutters.describe() +# def describe(self): +# return fb_two_button_shutters.describe() # -# def stop(self, success=False): -# return self.set('close') - -# fs = tempFSShutter() +# def stop(self, success=False): +# return self.set('close') +# +#fs = tempFSShutter() # Close the shutter on stop # fs.stop = lambda *args, **kwargs: fs.set(0) + class PDFFastShutter(Device): - cmd = Cpt(EpicsSignal, 'Cmd', kind='omitted') - status = Cpt(EpicsSignal, 'Sts', kind='omitted') - settle_time = Cpt(Signal, kind='config', value=.1) + cmd = Cpt(EpicsSignal, "Cmd", kind="omitted") + status = Cpt(EpicsSignal, "Sts", kind="omitted") + settle_time = Cpt(Signal, kind="config", value=0.1) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.st = None # TODO: ask CJ to change it downstream to only accept the 'Open' or 'Close' strings (no numbers please!). - self.setmap = {'Open': 0, 'Close': 1, - 1: 0, 0: 1} # MR: this is an inversed logic on the xpdacq side - self.readmap = {0: 'Open', 1: 'Close'} + self.setmap = { + "Open": 0, + "Close": 1, + 1: 0, + 0: 1, + } # MR: this is an inversed logic on the xpdacq side + self.readmap = {0: "Open", 1: "Close"} def set(self, val): # NOTE: temporary workaround until the fast shutter works. # - # def check_if_done(value, old_value, **kwargs): - # if ((val in ['Open', 1] and value == 0) or - # (val in ['Close', 0] and value == 1)): - # if self.st is not None: - # self.st._finished() - # self.st = None - # return True - # return False + def check_if_done(value, old_value, **kwargs): + if ((val in ['Open', 1] and value == 0) or + (val in ['Close', 0] and value == 1)): + if self.st is not None: + self.st._finished() + self.st = None + return True + return False self.cmd.set(self.setmap[val]) - # status = SubscriptionStatus(self.status, check_if_done,settle_time=self.settle_time.get()) - # return status + status = SubscriptionStatus(self.status, check_if_done,settle_time=self.settle_time.get()) + return status - ttime.sleep(1.0) # wait to set the value since the status PV does not capture the actual status - return NullStatus() + #ttime.sleep(1.0) # wait to set the value since the status PV does not capture the actual status + #return NullStatus() def get(self): return self.readmap[self.cmd.get()] def read(self): d = super().read() - d[self.name] = {'value': self.get(), 'timestamp': time.time()} + d[self.name] = {"value": self.get(), "timestamp": time.time()} return d # def stop(self, success=False): # return self.set('Close') - +#temporary disable fast shutter while broken - DO 5/18/2022 fs = PDFFastShutter('XF:28ID1B-OP{PSh:1-Det:2}', name='fs') - +#if enable this, need to disable fs in 12-motors: line 80 class Mirror(Device): - y_upstream = Cpt(EpicsMotor, 'YU}Mtr') - y_downstream_inboard = Cpt(EpicsMotor, 'YDI}Mtr') - y_downstream_outboard = Cpt(EpicsMotor, 'YDO}Mtr') - bend_upstream = Cpt(EpicsMotor, 'BndU}Mtr') - bend_encoder = Cpt(EpicsSignalRO, 'BndU}Pos:Enc-I') - bend_downstream = Cpt(EpicsMotor, 'BndD}Mtr') - twist_encoder = Cpt(EpicsSignalRO, 'BndD}Pos:Enc-I') + y_upstream = Cpt(EpicsMotor, "YU}Mtr") + y_downstream_inboard = Cpt(EpicsMotor, "YDI}Mtr") + y_downstream_outboard = Cpt(EpicsMotor, "YDO}Mtr") + bend_upstream = Cpt(EpicsMotor, "BndU}Mtr") + bend_encoder = Cpt(EpicsSignalRO, "BndU}Pos:Enc-I") + bend_downstream = Cpt(EpicsMotor, "BndD}Mtr") + twist_encoder = Cpt(EpicsSignalRO, "BndD}Pos:Enc-I") # TODO: add coordinated motions later: # y_upstream, y_downstream_inboard, y_downstream_outboard -Mirror_VFM = Mirror('XF:28ID1A-OP{Mir:VFM-Ax:', name='Mirror_VFM') + +Mirror_VFM = Mirror("XF:28ID1A-OP{Mir:VFM-Ax:", name="Mirror_VFM") + class OpticsTableADC(Device): - upstream_jack_inboard = Cpt(EpicsMotor, 'YUI}Mtr') - upstream_jack_outboard = Cpt(EpicsMotor, 'YUO}Mtr') - downstream_jack_outboard = Cpt(EpicsMotor, 'YD}Mtr') - X_upstream = Cpt(EpicsMotor, 'XU}Mtr') - X_downstream = Cpt(EpicsMotor, 'XD}Mtr') - Z = Cpt(EpicsMotor, 'Z}Mtr') + upstream_jack_inboard = Cpt(EpicsMotor, "YUI}Mtr") + upstream_jack_outboard = Cpt(EpicsMotor, "YUO}Mtr") + downstream_jack_outboard = Cpt(EpicsMotor, "YD}Mtr") + X_upstream = Cpt(EpicsMotor, "XU}Mtr") + X_downstream = Cpt(EpicsMotor, "XD}Mtr") + Z = Cpt(EpicsMotor, "Z}Mtr") + + +optics_table_adc = OpticsTableADC( + prefix="XF:28ID1B-ES{Tbl:1-Ax:", name="optics_table_adc" +) -optics_table_adc = OpticsTableADC(prefix="XF:28ID1B-ES{Tbl:1-Ax:", - name="optics_table_adc") class SpinnerGoniohead(Device): - X = Cpt(EpicsMotor, 'X}Mtr') - Y = Cpt(EpicsMotor, 'Y}Mtr') - Z = Cpt(EpicsMotor, 'Z}Mtr') - Ry = Cpt(EpicsMotor, 'Ry}Mtr') + X = Cpt(EpicsMotor, "X}Mtr") + Y = Cpt(EpicsMotor, "Y}Mtr") + Z = Cpt(EpicsMotor, "Z}Mtr") + Ry = Cpt(EpicsMotor, "Ry}Mtr") -spinner_goniohead = SpinnerGoniohead(prefix="XF:28ID1B-ES{Stg:Smpl-Ax:", - name="spinner_goniohead") + +spinner_goniohead = SpinnerGoniohead( + prefix="XF:28ID1B-ES{Stg:Smpl-Ax:", name="spinner_goniohead" +) # Added by MA - Sept 5, 2019 class OCMTable(Device): - upstream_jack = Cpt(EpicsMotor, 'YU}Mtr') - downstream_jack = Cpt(EpicsMotor, 'YD}Mtr') - X = Cpt(EpicsMotor, 'X}Mtr') - -OCM_table = OCMTable(prefix="XF:28ID1B-ES{OCM-Ax:", - name="optics_table") + upstream_jack = Cpt(EpicsMotor, "YU}Mtr") + downstream_jack = Cpt(EpicsMotor, "YD}Mtr") + X = Cpt(EpicsMotor, "X}Mtr") + + +OCM_table = OCMTable(prefix="XF:28ID1B-ES{OCM-Ax:", name="optics_table") diff --git a/startup/20-prosilica.py b/startup/20-prosilica.py index a8d9bbc..6711d6e 100644 --- a/startup/20-prosilica.py +++ b/startup/20-prosilica.py @@ -1,69 +1,95 @@ import time as ttime # tea time from types import SimpleNamespace from datetime import datetime -from ophyd import (ProsilicaDetector, SingleTrigger, TIFFPlugin, - ImagePlugin, StatsPlugin, DetectorBase, HDF5Plugin, - AreaDetector, EpicsSignal, EpicsSignalRO, ROIPlugin, - TransformPlugin, ProcessPlugin, Device) +from ophyd import ( + ProsilicaDetector, + SingleTrigger, + TIFFPlugin, + ImagePlugin, + StatsPlugin, + DetectorBase, + HDF5Plugin, + AreaDetector, + EpicsSignal, + EpicsSignalRO, + ROIPlugin, + TransformPlugin, + ProcessPlugin, + Device, +) from ophyd.areadetector.cam import AreaDetectorCam from ophyd.areadetector.base import ADComponent, EpicsSignalWithRBV -from ophyd.areadetector.filestore_mixins import (FileStoreTIFFIterativeWrite, - FileStoreHDF5IterativeWrite, - FileStoreBase, new_short_uid, - FileStoreIterativeWrite) +from ophyd.areadetector.filestore_mixins import ( + FileStoreTIFFIterativeWrite, + FileStoreHDF5IterativeWrite, + FileStoreBase, + new_short_uid, + FileStoreIterativeWrite, +) from ophyd import Component as Cpt, Signal from ophyd.utils import set_and_wait from pathlib import PurePath -from bluesky.plan_stubs import stage, unstage, open_run, close_run, trigger_and_read, pause +from bluesky.plan_stubs import ( + stage, + unstage, + open_run, + close_run, + trigger_and_read, + pause, +) from collections import OrderedDict class TIFFPluginWithFileStore(TIFFPlugin, FileStoreTIFFIterativeWrite): """Add this as a component to detectors that write TIFFs.""" + pass class TIFFPluginEnsuredOff(TIFFPlugin): """Add this as a component to detectors that do not write TIFFs.""" + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.stage_sigs.update([('auto_save', 'No')]) + self.stage_sigs.update([("auto_save", "No")]) class StandardProsilica(SingleTrigger, ProsilicaDetector): - image = Cpt(ImagePlugin, 'image1:') - stats1 = Cpt(StatsPlugin, 'Stats1:') - stats2 = Cpt(StatsPlugin, 'Stats2:') - stats3 = Cpt(StatsPlugin, 'Stats3:') - stats4 = Cpt(StatsPlugin, 'Stats4:') - stats5 = Cpt(StatsPlugin, 'Stats5:') - trans1 = Cpt(TransformPlugin, 'Trans1:') - roi1 = Cpt(ROIPlugin, 'ROI1:') - roi2 = Cpt(ROIPlugin, 'ROI2:') - roi3 = Cpt(ROIPlugin, 'ROI3:') - roi4 = Cpt(ROIPlugin, 'ROI4:') - proc1 = Cpt(ProcessPlugin, 'Proc1:') + image = Cpt(ImagePlugin, "image1:") + stats1 = Cpt(StatsPlugin, "Stats1:") + stats2 = Cpt(StatsPlugin, "Stats2:") + stats3 = Cpt(StatsPlugin, "Stats3:") + stats4 = Cpt(StatsPlugin, "Stats4:") + stats5 = Cpt(StatsPlugin, "Stats5:") + trans1 = Cpt(TransformPlugin, "Trans1:") + roi1 = Cpt(ROIPlugin, "ROI1:") + roi2 = Cpt(ROIPlugin, "ROI2:") + roi3 = Cpt(ROIPlugin, "ROI3:") + roi4 = Cpt(ROIPlugin, "ROI4:") + proc1 = Cpt(ProcessPlugin, "Proc1:") # This class does not save TIFFs. We make it aware of the TIFF plugin # only so that it can ensure that the plugin is not auto-saving. - tiff = Cpt(TIFFPluginEnsuredOff, suffix='TIFF1:') + tiff = Cpt(TIFFPluginEnsuredOff, suffix="TIFF1:") def __init__(self, *args, **kwargs): - kwargs.setdefault('labels', ['cameras']) + kwargs.setdefault("labels", ["cameras"]) super().__init__(*args, **kwargs) - self.stats1.total.kind = 'hinted' + self.stats1.total.kind = "hinted" class StandardProsilicaWithTIFF(StandardProsilica): - tiff = Cpt(TIFFPluginWithFileStore, - suffix='TIFF1:', - write_path_template='/nsls2/data/pdf/legacy/raw/psccd/%Y/%m/%d/', - root='/nsls2/data/pdf/legacy/raw/psccd') + tiff = Cpt( + TIFFPluginWithFileStore, + suffix="TIFF1:", + write_path_template="/nsls2/data/pdf/legacy/raw/psccd/%Y/%m/%d/", + root="/nsls2/data/pdf/legacy/raw/psccd", + ) ## This renaming should be reversed: no correspondance between CSS screens, PV names and ophyd.... # As of May 25, 2018 the cameras are not working -''' +""" Test_Cam1 = StandardProsilicaWithTIFF('XF:28ID1-BI{Test-Cam:1}', name='Test_Cam1') Cam2 = StandardProsilicaWithTIFF('XF:28ID1-BI{Cam:2}', name='Cam2') @@ -84,4 +110,4 @@ class StandardProsilicaWithTIFF(StandardProsilica): for camera in [Test_Cam1, Cam2]: camera.read_attrs.append('tiff') camera.tiff.read_attrs = [] -''' +""" diff --git a/startup/25-sample-env.py b/startup/25-sample-env.py index 8a369c0..23d8562 100644 --- a/startup/25-sample-env.py +++ b/startup/25-sample-env.py @@ -1,23 +1,24 @@ - - class SampleEnvironment(Device): - esc_sample_theta = Cpt(EpicsMotor, 'ECS-Ax:Th1}Mtr') - esc_sample_2_theta = Cpt(EpicsMotor, 'ECS-Ax:2Th1}Mtr') - analyzer_theta = Cpt(EpicsMotor, 'ECS-Ax:Th2}Mtr') - analyzer_2_theta = Cpt(EpicsMotor, 'ECS-Ax:2Th2}Mtr') - y = Cpt(EpicsMotor, 'Spn:Caplr-Ax:Y}Mtr') - z = Cpt(EpicsMotor, 'Spn:Caplr-Ax:Z}Mtr') - ry_yaw = Cpt(EpicsMotor, 'Spn:Caplr-Ax:Ry}Mtr') - rz_roll = Cpt(EpicsMotor, 'Spn:Caplr-Ax:Rz}Mtr') + esc_sample_theta = Cpt(EpicsMotor, "ECS-Ax:Th1}Mtr") + esc_sample_2_theta = Cpt(EpicsMotor, "ECS-Ax:2Th1}Mtr") + analyzer_theta = Cpt(EpicsMotor, "ECS-Ax:Th2}Mtr") + analyzer_2_theta = Cpt(EpicsMotor, "ECS-Ax:2Th2}Mtr") + y = Cpt(EpicsMotor, "Spn:Caplr-Ax:Y}Mtr") + z = Cpt(EpicsMotor, "Spn:Caplr-Ax:Z}Mtr") + ry_yaw = Cpt(EpicsMotor, "Spn:Caplr-Ax:Ry}Mtr") + rz_roll = Cpt(EpicsMotor, "Spn:Caplr-Ax:Rz}Mtr") + -ECS_sample_environment = SampleEnvironment('XF:28ID1B-ES{', name='ECS_sample_environment') +ECS_sample_environment = SampleEnvironment( + "XF:28ID1B-ES{", name="ECS_sample_environment" +) class Analyzer(Device): - y = Cpt(EpicsMotor, 'Y}Mtr') - z = Cpt(EpicsMotor, 'Z}Mtr') - ry_yaw = Cpt(EpicsMotor, 'Ry}Mtr') - rz_roll = Cpt(EpicsMotor, 'Rz}Mtr') + y = Cpt(EpicsMotor, "Y}Mtr") + z = Cpt(EpicsMotor, "Z}Mtr") + ry_yaw = Cpt(EpicsMotor, "Ry}Mtr") + rz_roll = Cpt(EpicsMotor, "Rz}Mtr") -analyzer_goniohead = Analyzer('XF:28ID1B-ES{Spn:Anlzr-Ax:', name='analyzer_goniohead') +analyzer_goniohead = Analyzer("XF:28ID1B-ES{Spn:Anlzr-Ax:", name="analyzer_goniohead") diff --git a/startup/80-areadetector.py b/startup/80-areadetector.py index effd113..26e4fee 100644 --- a/startup/80-areadetector.py +++ b/startup/80-areadetector.py @@ -1,23 +1,42 @@ import time as ttime -from ophyd.areadetector import (PerkinElmerDetector, ImagePlugin, - TIFFPlugin, HDF5Plugin, - ProcessPlugin, ROIPlugin) -from ophyd.device import BlueskyInterface +from ophyd.areadetector import ( + DetectorBase as _PerkinElmerDetector) +from ophyd.areadetector.plugins import ( + ImagePlugin_V34 as ImagePlugin, + TIFFPlugin_V34 as TIFFPlugin, + HDF5Plugin_V34 as HDF5Plugin, + ProcessPlugin_V34 as ProcessPlugin, + ROIPlugin_V34 as ROIPlugin, + StatsPlugin_V34 as StatsPlugin +) +from ophyd.areadetector.cam import CamBase as _PerkinElmerDetectorCam +from ophyd.device import BlueskyInterface, Component as Cpt from ophyd.areadetector.trigger_mixins import SingleTrigger, MultiTrigger -from ophyd.areadetector.filestore_mixins import (FileStoreIterativeWrite, - FileStoreHDF5IterativeWrite, - FileStoreTIFFSquashing, - FileStoreTIFF) -from ophyd import Signal, EpicsSignal, EpicsSignalRO # Tim test +from ophyd.areadetector.filestore_mixins import ( + FileStoreIterativeWrite, + FileStoreHDF5IterativeWrite, + FileStoreTIFFSquashing, + FileStoreTIFF, +) +from ophyd import Signal, EpicsSignal, EpicsSignalRO # Tim test from ophyd import Component as C, Device, DeviceStatus from ophyd import StatusBase -from nslsii.ad33 import StatsPluginV33 + + +class PerkinElmerDetectorCam(_PerkinElmerDetectorCam): + pool_max_buffers = None + pe_dwell_time = None + pe_sync_time = None + pe_system_id = None + +class PerkinElmerDetector(_PerkinElmerDetector): + cam = Cpt(PerkinElmerDetectorCam, 'cam1:') # from shutter import sh1 -#shctl1 = EpicsSignal('XF:28IDC-ES:1{Det:PE1}cam1:ShutterMode', name='shctl1') -#shctl1 = EpicsMotor('XF:28IDC-ES:1{Sh2:Exp-Ax:5}Mtr', name='shctl1') +# shctl1 = EpicsSignal('XF:28IDC-ES:1{Det:PE1}cam1:ShutterMode', name='shctl1') +# shctl1 = EpicsMotor('XF:28IDC-ES:1{Sh2:Exp-Ax:5}Mtr', name='shctl1') # monkey patch for trailing slash problem def _ensure_trailing_slash(path, path_semantics=None): @@ -27,34 +46,32 @@ def _ensure_trailing_slash(path, path_semantics=None): setpoint filepath to match the readback filepath, we need to add the trailing slash ourselves. """ - newpath = os.path.join(path, '') - if newpath[0] != '/' and newpath[-1] == '/': + newpath = os.path.join(path, "") + if newpath[0] != "/" and newpath[-1] == "/": # make it a windows slash newpath = newpath[:-1] return newpath + ophyd.areadetector.filestore_mixins._ensure_trailing_slash = _ensure_trailing_slash class PDFShutter(Device): - cmd = C(EpicsSignal, 'Cmd-Cmd') - close_sts = C(EpicsSignalRO, 'Sw:Cls1-Sts') - open_sts = C(EpicsSignalRO, 'Sw:Opn1-Sts') + cmd = C(EpicsSignal, "Cmd-Cmd") + close_sts = C(EpicsSignalRO, "Sw:Cls1-Sts") + open_sts = C(EpicsSignalRO, "Sw:Opn1-Sts") def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._st = None self._target = None - self.close_sts.subscribe(self._watcher_close, - self.close_sts.SUB_VALUE) + self.close_sts.subscribe(self._watcher_close, self.close_sts.SUB_VALUE) - self.open_sts.subscribe(self._watcher_open, - self.open_sts.SUB_VALUE) + self.open_sts.subscribe(self._watcher_open, self.open_sts.SUB_VALUE) def set(self, value, *, wait=False, **kwargs): - if value not in ('Open', 'Close'): - raise ValueError( - "must be 'Open' or 'Close', not {!r}".format(value)) + if value not in ("Open", "Close"): + raise ValueError("must be 'Open' or 'Close', not {!r}".format(value)) if wait: raise RuntimeError() if self._st is not None: @@ -67,7 +84,7 @@ def set(self, value, *, wait=False, **kwargs): def _watcher_open(self, *, old_value=None, value=None, **kwargs): print("in open watcher", old_value, value) - if self._target != 'Open': + if self._target != "Open": return if self._st is None: return @@ -80,7 +97,7 @@ def _watcher_open(self, *, old_value=None, value=None, **kwargs): def _watcher_close(self, *, old_value=None, value=None, **kwargs): print("in close watcher", old_value, value) - if self._target != 'Close': + if self._target != "Close": return if self._st is None: @@ -112,7 +129,7 @@ def take_dark(cam, light_field, dark_field_name): cam.stage() st = cam.trigger() while not st.done: - ttime.sleep(.1) + ttime.sleep(0.1) ret = cam.read() desc = cam.describe() cam.unstage() @@ -132,6 +149,7 @@ def describe(self): shape[0] = self.get_frames_per_point() shape = tuple(shape) description[f"{self.parent.name}_image"]["shape"] = shape + description[f"{self.parent.name}_image"].setdefault('dtype_str', ' computed exposure time" "= {}".format(exposure, computed_exposure) ) - print('l67') + print("l67") return num_frame, acq_time, computed_exposure - def looptlist(base_temp, T_interval, T_steps): @@ -82,17 +85,17 @@ def conditional_step( detectors, motor, step, - expo_high=60, # all in seconds + expo_high=60, # all in seconds expo_low=600, wait_high=5, wait_low=3, base_temp=25, ): - """ customized step to: - 1. open shutter - 2. take data - 3. close shutter - 4. wait for equilibrium + """customized step to: + 1. open shutter + 2. take data + 3. close shutter + 4. wait for equilibrium """ # base case expo = expo_low @@ -112,29 +115,29 @@ def conditional_step( def motor_dark_step(detectors, motor, step): """ - Take darks while moving motors, wait for all to be finished before + Take darks while moving motors, wait for all to be finished before taking light """ yield from bps.checkpoint() - print('l120') + print("l120") # close the shutter - #yield from _close_shutter_stub() COMMENTED OUT (dark per light) - print('l123') - # move motors don't wait yet. + # yield from _close_shutter_stub() COMMENTED OUT (dark per light) + print("l123") + # move motors don't wait yet. # Note for Soham: use `group=None` to ramp temp after dark collected # (Broken and replaced below) yield from bps.abs_set(motor, step, group="dark_motor") yield from bps.abs_set(motor, step, group="dark_motor") - print('l127') - # take dark (this has an internal wait on the readback) - #yield from bps.trigger_and_read(list(detectors), name="dark") COMMENTED OUT (dark per light) - print('l130') + print("l127") + # take dark (this has an internal wait on the readback) + # yield from bps.trigger_and_read(list(detectors), name="dark") COMMENTED OUT (dark per light) + print("l130") # (Broken) now wait for the motors to be done too yield from bps.wait(group="dark_motor") - print('l133') + print("l133") # open shutter yield from open_shutter_stub() - print('l136') + print("l136") # take data yield from bps.trigger_and_read(list(detectors) + [motor]) - print('l139') + print("l139") diff --git a/startup/94-load.py b/startup/94-load.py index 7004c2d..e26ea6b 100644 --- a/startup/94-load.py +++ b/startup/94-load.py @@ -14,28 +14,37 @@ # ############################################################################## import os -from xpdacq.xpdacq_conf import (glbl_dict, configure_device, - _reload_glbl, _set_glbl, - _load_beamline_config) +import yaml + +from xpdacq.xpdacq_conf import ( + _load_beamline_config, + _reload_glbl, + _set_glbl, + configure_device, + glbl_dict, +) + # configure experiment device being used in current version -if glbl_dict['is_simulation']: - from xpdacq.simulation import (xpd_pe1c, db, cs700, shctl1, - ring_current, fb) - pe1c = xpd_pe1c # alias +if glbl_dict["is_simulation"]: + from xpdacq.simulation import xpd_pe1c, db, cs700, shctl1, ring_current, fb -configure_device(area_det=pe1c, shutter=fs, - temp_controller=eurotherm, #changed from None to eurotherm on 3/22/19 - DPO - db=db, - filter_bank=fb, - ring_current=ring_current) + pe1c = xpd_pe1c # alias + +configure_device( + area_det=pe1c, + shutter=fs, + temp_controller=eurotherm, # changed from None to eurotherm on 3/22/19 - DPO + db=db, + filter_bank=fb, + ring_current=ring_current, +) # cache previous glbl state reload_glbl_dict = _reload_glbl() from xpdacq.glbl import glbl # reload beamtime -from xpdacq.beamtimeSetup import (start_xpdacq, _start_beamtime, - _end_beamtime) +from xpdacq.beamtimeSetup import start_xpdacq, _start_beamtime, _end_beamtime bt = start_xpdacq() if bt is not None: @@ -50,37 +59,59 @@ # instantiate xrun without beamtime, like bluesky setup xrun = CustomizedRunEngine(None) -xrun.md['beamline_id'] = glbl['beamline_id'] -xrun.md['group'] = glbl['group'] -xrun.md['facility'] = glbl['facility'] -beamline_config = _load_beamline_config(glbl['blconfig_path']) -xrun.md['beamline_config'] = beamline_config +xrun.md["beamline_id"] = glbl["beamline_id"] +xrun.md["group"] = glbl["group"] +xrun.md["facility"] = glbl["facility"] +with open(glbl["blconfig_path"], "r") as f: + beamline_config = yaml.unsafe_load(f) +xrun.md["beamline_config"] = beamline_config # insert header to db, either simulated or real -xrun.subscribe(db.insert, 'all') +xrun.subscribe(db.insert, "all") + +# We need to repeat it here for `xrun` as RE is not used here... +nslsii.configure_kafka_publisher(xrun, "pdf") if bt: xrun.beamtime = bt -HOME_DIR = glbl['home'] -BASE_DIR = glbl['base'] +HOME_DIR = glbl["home"] +BASE_DIR = glbl["base"] -print('INFO: Initializing the XPD data acquisition environment\n') +print("INFO: Initializing the XPD data acquisition environment\n") if os.path.isdir(HOME_DIR): os.chdir(HOME_DIR) else: os.chdir(BASE_DIR) -from xpdacq.calib import * - -# We are adding this here because the previous -# line overwrites our logger config. This undoes the logger changes. +# See https://github.com/silx-kit/pyFAI/issues/1399#issuecomment-694185304 import logging -logging.getLogger().handlers.clear() +logging.getLogger().addHandler(logging.NullHandler()) + +from xpdacq.calib import * # analysis functions, only at beamline -#from xpdan.data_reduction import * +# from xpdan.data_reduction import * + +print("OK, ready to go. To continue, follow the steps in the xpdAcq") +print("documentation at http://xpdacq.github.io/xpdacq\n") + + +class MoreCustomizedRunEngine(CustomizedRunEngine): + def __call__(self, plan, *args, **kwargs): + super().__call__({}, plan, *args, **kwargs) + + +from bluesky.utils import ts_msg_hook +RE = MoreCustomizedRunEngine(None) +RE.msg_hook = ts_msg_hook +RE.md = {} +#RE.md.update(xrun.md) +# insert header to db, either simulated or real +RE.subscribe(db.insert, "all") +RE.beamtime = bt +RE.clear_suspenders() -print('OK, ready to go. To continue, follow the steps in the xpdAcq') -print('documentation at http://xpdacq.github.io/xpdacq\n') +del Tramp +del Tlist diff --git a/startup/95-zmq.py b/startup/95-zmq.py index 6c080b6..2359bed 100644 --- a/startup/95-zmq.py +++ b/startup/95-zmq.py @@ -1,4 +1,5 @@ from bluesky.callbacks.zmq import Publisher -pub = Publisher(glbl['inbound_proxy_address'], prefix=b'raw') +pub = Publisher(glbl["inbound_proxy_address"], prefix=b"raw") xrun.subscribe(pub) +RE.subscribe(pub) diff --git a/startup/96-dan_functions.py b/startup/96-dan_functions.py index 99ecfd9..5499029 100644 --- a/startup/96-dan_functions.py +++ b/startup/96-dan_functions.py @@ -1,6 +1,8 @@ +import time import sys -#from slack import WebClient -#from slack.errors import SlackApiError + +# from slack import WebClient +# from slack.errors import SlackApiError import os import bluesky.plan_stubs as bps import bluesky.plans as bp @@ -14,14 +16,18 @@ ############## -#slack_token = os.environ["SLACK_API_TOKEN"] -#client = WebClient(token=slack_token) +try: + slack_token = os.environ["SLACK_API_TOKEN"] +except KeyError: + client = None +else: + client = WebClient(token=slack_token) ### -#def slack_message(my_message): +# def slack_message(my_message): # try: # response = client.chat_postMessage( # channel="pdf_dev", @@ -34,9 +40,9 @@ # print("slack message failed") -#def check_heartbeat( +# def check_heartbeat( # fname="hbeat.txt", tlapse=300, send_warning=False, notify_user=False -#): +# ): # fin = open(fname, "r") # tread = float(fin.read()) # tpassed = time.time() - tread @@ -51,7 +57,7 @@ # return True -#def update_heartbeat(fname="hbeat.txt"): +# def update_heartbeat(fname="hbeat.txt"): # fout = open(fname, "w") # fout.write(str(time.time())) # fout.close() @@ -92,10 +98,14 @@ def show_me_db( if "sc_dk_field_uid" in db[my_id].start.keys(): my_dark_id = db[my_id].start["sc_dk_field_uid"] if new_db: - dark_im = (db[my_dark_id].table(fill=True)[my_det_probably][1][0]).astype(float) + dark_im = ( + db[my_dark_id].table(fill=True)[my_det_probably][1][0] + ).astype(float) else: - dark_im = (db[my_dark_id].table(fill=True)[my_det_probably][1]).astype(float) - + dark_im = (db[my_dark_id].table(fill=True)[my_det_probably][1]).astype( + float + ) + my_im = my_im - dark_im else: print("this run has no associated dark") @@ -297,7 +307,7 @@ def read_twocol_data( # setup pandas dataframe -def make_me_a_dataframe(found_pos,cut_start = None, cut_end = None): +def make_me_a_dataframe(found_pos, cut_start=None, cut_end=None): import glob as glob import pandas as pd @@ -310,11 +320,11 @@ def make_me_a_dataframe(found_pos,cut_start = None, cut_end = None): read_xcel = pd.read_excel(my_excel_file, skiprows=1, usecols=([0, 1])) if cut_start != None: - print ('cutting down') - read_xcel = read_xcel.loc[cut_start:cut_end,:] + print("cutting down") + read_xcel = read_xcel.loc[cut_start:cut_end, :] read_xcel.index = range(len(read_xcel.index)) - print ('expecting length '+str(len(np.array(read_xcel.index)))) + print("expecting length " + str(len(np.array(read_xcel.index)))) df_sample_pos_info = pd.DataFrame(index=np.array(read_xcel.index)) df_sample_pos_info["name"] = read_xcel.iloc[:, 0] @@ -325,7 +335,6 @@ def make_me_a_dataframe(found_pos,cut_start = None, cut_end = None): len(read_xcel.index), dtype=int ) - return df_sample_pos_info @@ -352,9 +361,9 @@ def scan_shifter_pos( min_dist=5, peak_rad=1.5, use_det=True, - abs_data = False, - oset_data = 0.0, - return_to_start = True + abs_data=False, + oset_data=0.0, + return_to_start=True, ): def yn_question(q): return input(q).lower().strip()[0] == "y" @@ -396,10 +405,9 @@ def yn_question(q): return None if return_to_start: - print ('returning to start position....') + print("returning to start position....") motor.move(init_pos) - if oset_data != 0.0: I_list = I_list - oset_data @@ -576,20 +584,22 @@ def this_func(x, c, w, a, b): def get_total_counts(): from epics import caget + return float(caget("XF:28ID1-ES{Det:PE1}Stats2:Total_RBV")) #return float(caget("XF:28ID1-ES{Det:PE2}Stats1:Total_RBV")) #for pe2c def _motor_move_scan_shifter_pos(motor, xmin, xmax, numx): from epics import caget - #ensure shutter is closed - RE(mv(fs,"Close")) + + # ensure shutter is closed + RE(mv(fs, "Close")) I_list = np.zeros(numx) dx = (xmax - xmin) / numx pos_list = np.linspace(xmin, xmax, numx) - print ('moving to starting postion') - RE(mv(motor,pos_list[0])) - print ('opening shutter') + print("moving to starting postion") + RE(mv(motor, pos_list[0])) + print("opening shutter") RE(mv(fs, "Open")) time.sleep(1) fig1, ax1 = plt.subplots() @@ -700,28 +710,27 @@ def simple_ct(dets, exposure, *, md=None): return (yield from plan) -def save_history(histfile,LIMIT=5000): +def save_history(histfile, LIMIT=5000): ip = get_ipython() """save the IPython history to a plaintext file""" - #histfile = os.path.join(ip.profile_dir.location, "history.txt") + # histfile = os.path.join(ip.profile_dir.location, "history.txt") print("Saving plaintext history to %s" % histfile) lines = [] # get previous lines # this is only necessary because we truncate the history, # otherwise we chould just open with mode='a' if os.path.exists(histfile): - with open(histfile, 'r') as f: + with open(histfile, "r") as f: lines = f.readlines() # add any new lines from this session - lines.extend(record[2] + '\n' for record in ip.history_manager.get_range()) + lines.extend(record[2] + "\n" for record in ip.history_manager.get_range()) - with open(histfile, 'w') as f: + with open(histfile, "w") as f: # limit to LIMIT entries f.writelines(lines[-LIMIT:]) - def phase_parser(phase_str): """parser for field with : Parameters @@ -809,3 +818,60 @@ def phase_parser(phase_str): del pe1c.tiff.stage_sigs[pe1c.proc.reset_filter] + +#for looking at data from Pilatus detector + +def set_Pilatus_parameters(num_images=1, exposure_time=0.1): + print ('setting number of images per collection to '+str(num_images)) + pilatus1.set_num_images(num_images) + print ('setting exposure time for a single image to '+str(exposure_time)) + pilatus1.set_exposure_time(exposure_time) + + +def show_me2(my_im, count_low=0, count_high=1, use_colorbar=False, use_cmap='viridis'): + #my_low = np.percentile(my_im, per_low) + #my_high = np.percentile(my_im, per_high) + plt.imshow(my_im, vmin=count_low, vmax=count_high, cmap= use_cmap) + if use_colorbar: + plt.colorbar() + +def show_me_db2( + my_id, + count_low=1, + count_high=99, + use_colorbar=False, + dark_subtract=False, + return_im=False, + return_dark=False, + new_db = True, + use_cmap='viridis', + suffix="_image", +): + my_det_probably = db[my_id].start["detectors"][0] + suffix + if new_db: + my_im = (db[my_id].table(fill=True)[my_det_probably][1][0]).astype(float) + else: + my_im = (db[my_id].table(fill=True)[my_det_probably][1]).astype(float) + + if len(my_im) == 0: + print("issue... passing") + pass + if dark_subtract: + if "sc_dk_field_uid" in db[my_id].start.keys(): + my_dark_id = db[my_id].start["sc_dk_field_uid"] + if new_db: + dark_im = (db[my_dark_id].table(fill=True)[my_det_probably][1][0]).astype(float) + else: + dark_im = (db[my_dark_id].table(fill=True)[my_det_probably][1]).astype(float) + + my_im = my_im - dark_im + else: + print("this run has no associated dark") + if return_im: + return my_im + if return_dark: + return dark_im + + #if all else fails, plot! + show_me2(my_im, count_low=count_low, count_high=count_high, use_colorbar=use_colorbar, use_cmap=use_cmap) + diff --git a/startup/97-MA_functions.py b/startup/97-MA_functions.py index 21f30ba..a5d0f82 100644 --- a/startup/97-MA_functions.py +++ b/startup/97-MA_functions.py @@ -1,220 +1,237 @@ "Define Beamline Modes" -def beam22slit(): - #print("Resetting white beam slits") 2021-3 values - #wb_slits.inboard.move(-11.55) - #wb_slits.outboard.move(-5.879) - - #print("Resetting Monochromator") # 2021-3 values - #sbm.yaw.move(0.00012) - #sbm.roll.move(0.0008) - #sbm.pitch.move(-0.02827) - #sbm.bend.move(2000.0084) - #sbm.twist.move(0) - - print("Resetting Mirror") - #Mirror_VFM.y_upstream.move(-1.2493) # 2021-3 values - #Mirror_VFM.y_downstream_inboard.move(-0.3179) - #Mirror_VFM.y_downstream_outboard.move(-0.0806) - Mirror_VFM.bend_upstream.move(100) - Mirror_VFM.bend_downstream.move(100) - - #print("Resetting BDM Slits") - #bdm_slits.top.move(999.957) - #bdm_slits.bottom.move(-94363.970) - #bdm_slits.inboard.move(-7600.960) - #bdm_slits.outboard.move(-4100.075) - - print("Resetting OCM Slits") - ocm_slits.top.move(-765.286) - ocm_slits.bottom.move(545.00) - ocm_slits.outboard.move(2005.959) - ocm_slits.inboard.move(-1939.037) - - print("Resetting Anti-scatter Slits") - caput('XF:28ID1B-OP{Slt:AS-Ax:T}Mtr.VAL', -24.95948) #Top - caput('XF:28ID1B-OP{Slt:AS-Ax:B}Mtr.VAL', -31.49997) #Bottom - caput('XF:28ID1B-OP{Slt:AS-Ax:O}Mtr.VAL', -27.89998) #Outboard - caput('XF:28ID1B-OP{Slt:AS-Ax:I}Mtr.VAL', 6.09888) #inboard - print("Ready to go !") - -def beam22(): - #print("Resetting white beam slits") 2021-3 values - #wb_slits.inboard.move(-11.55) - #wb_slits.outboard.move(-5.879) - - #print("Resetting Monochromator") # 2021-3 values - #sbm.yaw.move(0.00012) - #sbm.roll.move(0.0008) - #sbm.pitch.move(-0.02827) - #sbm.bend.move(2000.0084) - #sbm.twist.move(0) - - print("Resetting Mirror") - #Mirror_VFM.y_upstream.move(-1.2493) # 2021-3 values - #Mirror_VFM.y_downstream_inboard.move(-0.3179) - #Mirror_VFM.y_downstream_outboard.move(-0.0806) - Mirror_VFM.bend_upstream.move(150) - Mirror_VFM.bend_downstream.move(150) - - #print("Resetting BDM Slits") - #bdm_slits.top.move(999.957) - #bdm_slits.bottom.move(-94363.970) - #bdm_slits.inboard.move(-7600.960) - #bdm_slits.outboard.move(-4100.075) - - print("Resetting OCM Slits") - ocm_slits.top.move(-765.286) - ocm_slits.bottom.move(545.00) - ocm_slits.outboard.move(2005.959) - ocm_slits.inboard.move(-1939.037) - - print("Resetting Anti-scatter Slits") - caput('XF:28ID1B-OP{Slt:AS-Ax:T}Mtr.VAL', -24.95948) #Top - caput('XF:28ID1B-OP{Slt:AS-Ax:B}Mtr.VAL', -31.49997) #Bottom - caput('XF:28ID1B-OP{Slt:AS-Ax:O}Mtr.VAL', -27.89998) #Outboard - caput('XF:28ID1B-OP{Slt:AS-Ax:I}Mtr.VAL', 6.09888) #inboard - print("Ready to go !") - -def beam33(): - #print("Resetting white beam slits") 2021-3 values - #wb_slits.inboard.move(-11.55) - #wb_slits.outboard.move(-5.879) - - #print("Resetting Monochromator") # 2021-3 values - #sbm.yaw.move(0.00012) - #sbm.roll.move(0.0008) - #sbm.pitch.move(-0.02827) - #sbm.bend.move(2000.0084) - #sbm.twist.move(0) - - print("Resetting Mirror") - #Mirror_VFM.y_upstream.move(-1.2493) # 2021-3 values - #Mirror_VFM.y_downstream_inboard.move(-0.3179) - #Mirror_VFM.y_downstream_outboard.move(-0.0806) - Mirror_VFM.bend_upstream.move(120) - Mirror_VFM.bend_downstream.move(120) - - #print("Resetting BDM Slits") - #bdm_slits.top.move(999.957) - #bdm_slits.bottom.move(-94363.970) - #bdm_slits.inboard.move(-7600.960) - #bdm_slits.outboard.move(-4100.075) - - print("Resetting OCM Slits") - ocm_slits.top.move(-765.286) - ocm_slits.bottom.move(545.00) - ocm_slits.outboard.move(2005.959) - ocm_slits.inboard.move(-1939.037) - - print("Resetting Anti-scatter Slits") - caput('XF:28ID1B-OP{Slt:AS-Ax:T}Mtr.VAL', -24.90948) #Top - caput('XF:28ID1B-OP{Slt:AS-Ax:B}Mtr.VAL', -31.44997) #Bottom - caput('XF:28ID1B-OP{Slt:AS-Ax:O}Mtr.VAL', -27.84998) #Outboard - caput('XF:28ID1B-OP{Slt:AS-Ax:I}Mtr.VAL', 6.19888) #inboard - print("Ready to go !") - -def beam55(): - #print("Resetting white beam slits") 2021-3 values - #wb_slits.inboard.move(-11.55) - #wb_slits.outboard.move(-5.879) - - #print("Resetting Monochromator") # 2021-3 values - #sbm.yaw.move(0.00012) - #sbm.roll.move(0.0008) - #sbm.pitch.move(-0.02827) - #sbm.bend.move(2000.0084) - #sbm.twist.move(0) - - print("Resetting Mirror") - #Mirror_VFM.y_upstream.move(-1.2493) # 2021-3 values - #Mirror_VFM.y_downstream_inboard.move(-0.3179) - #Mirror_VFM.y_downstream_outboard.move(-0.0806) - Mirror_VFM.bend_upstream.move(100) - Mirror_VFM.bend_downstream.move(100) - - #print("Resetting BDM Slits") - #bdm_slits.top.move(999.957) - #bdm_slits.bottom.move(-94363.970) - #bdm_slits.inboard.move(-7600.960) - #bdm_slits.outboard.move(-4100.075) - - print("Resetting OCM Slits") - ocm_slits.top.move(-665.286) - ocm_slits.bottom.move(645.00) - ocm_slits.outboard.move(2105.959) - ocm_slits.inboard.move(-1839.037) - - print("Resetting Anti-scatter Slits") - caput('XF:28ID1B-OP{Slt:AS-Ax:T}Mtr.VAL', -24.80948) #Top - caput('XF:28ID1B-OP{Slt:AS-Ax:B}Mtr.VAL', -31.34997) #Bottom - caput('XF:28ID1B-OP{Slt:AS-Ax:O}Mtr.VAL', -27.69998) #Outboard - caput('XF:28ID1B-OP{Slt:AS-Ax:I}Mtr.VAL', 6.29888) #inboard - print("Ready to go !") +def beam22slit(): + # print("Resetting white beam slits") 2021-3 values + # wb_slits.inboard.move(-11.55) + # wb_slits.outboard.move(-5.879) + + # print("Resetting Monochromator") # 2021-3 values + # sbm.yaw.move(0.00012) + # sbm.roll.move(0.0008) + # sbm.pitch.move(-0.02827) + # sbm.bend.move(2000.0084) + # sbm.twist.move(0) + + print("Resetting Mirror") + # Mirror_VFM.y_upstream.move(-1.2493) # 2021-3 values + # Mirror_VFM.y_downstream_inboard.move(-0.3179) + # Mirror_VFM.y_downstream_outboard.move(-0.0806) + Mirror_VFM.bend_upstream.move(100) + Mirror_VFM.bend_downstream.move(100) + + # print("Resetting BDM Slits") + # bdm_slits.top.move(999.957) + # bdm_slits.bottom.move(-94363.970) + # bdm_slits.inboard.move(-7600.960) + # bdm_slits.outboard.move(-4100.075) + + print("Resetting OCM Slits") + ocm_slits.top.move(-765.286) + ocm_slits.bottom.move(545.00) + ocm_slits.outboard.move(2005.959) + ocm_slits.inboard.move(-1939.037) + + print("Resetting Anti-scatter Slits") + caput("XF:28ID1B-OP{Slt:AS-Ax:T}Mtr.VAL", -24.95948) # Top + caput("XF:28ID1B-OP{Slt:AS-Ax:B}Mtr.VAL", -31.49997) # Bottom + caput("XF:28ID1B-OP{Slt:AS-Ax:O}Mtr.VAL", -27.89998) # Outboard + caput("XF:28ID1B-OP{Slt:AS-Ax:I}Mtr.VAL", 6.09888) # inboard + print("Ready to go !") + + +def beam22(): + # print("Resetting white beam slits") 2021-3 values + # wb_slits.inboard.move(-11.55) + # wb_slits.outboard.move(-5.879) + + # print("Resetting Monochromator") # 2021-3 values + # sbm.yaw.move(0.00012) + # sbm.roll.move(0.0008) + # sbm.pitch.move(-0.02827) + # sbm.bend.move(2000.0084) + # sbm.twist.move(0) + + print("Resetting Mirror") + # Mirror_VFM.y_upstream.move(-1.2493) # 2021-3 values + # Mirror_VFM.y_downstream_inboard.move(-0.3179) + # Mirror_VFM.y_downstream_outboard.move(-0.0806) + Mirror_VFM.bend_upstream.move(150) + Mirror_VFM.bend_downstream.move(150) + + # print("Resetting BDM Slits") + # bdm_slits.top.move(999.957) + # bdm_slits.bottom.move(-94363.970) + # bdm_slits.inboard.move(-7600.960) + # bdm_slits.outboard.move(-4100.075) + + print("Resetting OCM Slits") + ocm_slits.top.move(-765.286) + ocm_slits.bottom.move(545.00) + ocm_slits.outboard.move(2005.959) + ocm_slits.inboard.move(-1939.037) + + print("Resetting Anti-scatter Slits") + caput("XF:28ID1B-OP{Slt:AS-Ax:T}Mtr.VAL", -24.95948) # Top + caput("XF:28ID1B-OP{Slt:AS-Ax:B}Mtr.VAL", -31.49997) # Bottom + caput("XF:28ID1B-OP{Slt:AS-Ax:O}Mtr.VAL", -27.89998) # Outboard + caput("XF:28ID1B-OP{Slt:AS-Ax:I}Mtr.VAL", 6.09888) # inboard + print("Ready to go !") + + +def beam33(): + # print("Resetting white beam slits") 2021-3 values + # wb_slits.inboard.move(-11.55) + # wb_slits.outboard.move(-5.879) + + # print("Resetting Monochromator") # 2021-3 values + # sbm.yaw.move(0.00012) + # sbm.roll.move(0.0008) + # sbm.pitch.move(-0.02827) + # sbm.bend.move(2000.0084) + # sbm.twist.move(0) + + print("Resetting Mirror") + # Mirror_VFM.y_upstream.move(-1.2493) # 2021-3 values + # Mirror_VFM.y_downstream_inboard.move(-0.3179) + # Mirror_VFM.y_downstream_outboard.move(-0.0806) + Mirror_VFM.bend_upstream.move(120) + Mirror_VFM.bend_downstream.move(120) + + # print("Resetting BDM Slits") + # bdm_slits.top.move(999.957) + # bdm_slits.bottom.move(-94363.970) + # bdm_slits.inboard.move(-7600.960) + # bdm_slits.outboard.move(-4100.075) + + print("Resetting OCM Slits") + ocm_slits.top.move(-765.286) + ocm_slits.bottom.move(545.00) + ocm_slits.outboard.move(2005.959) + ocm_slits.inboard.move(-1939.037) + + print("Resetting Anti-scatter Slits") + caput("XF:28ID1B-OP{Slt:AS-Ax:T}Mtr.VAL", -24.90948) # Top + caput("XF:28ID1B-OP{Slt:AS-Ax:B}Mtr.VAL", -31.44997) # Bottom + caput("XF:28ID1B-OP{Slt:AS-Ax:O}Mtr.VAL", -27.84998) # Outboard + caput("XF:28ID1B-OP{Slt:AS-Ax:I}Mtr.VAL", 6.19888) # inboard + print("Ready to go !") + + +def beam55(): + # print("Resetting white beam slits") 2021-3 values + # wb_slits.inboard.move(-11.55) + # wb_slits.outboard.move(-5.879) + + # print("Resetting Monochromator") # 2021-3 values + # sbm.yaw.move(0.00012) + # sbm.roll.move(0.0008) + # sbm.pitch.move(-0.02827) + # sbm.bend.move(2000.0084) + # sbm.twist.move(0) + + print("Resetting Mirror") + # Mirror_VFM.y_upstream.move(-1.2493) # 2021-3 values + # Mirror_VFM.y_downstream_inboard.move(-0.3179) + # Mirror_VFM.y_downstream_outboard.move(-0.0806) + Mirror_VFM.bend_upstream.move(100) + Mirror_VFM.bend_downstream.move(100) + + # print("Resetting BDM Slits") + # bdm_slits.top.move(999.957) + # bdm_slits.bottom.move(-94363.970) + # bdm_slits.inboard.move(-7600.960) + # bdm_slits.outboard.move(-4100.075) + + print("Resetting OCM Slits") + ocm_slits.top.move(-665.286) + ocm_slits.bottom.move(645.00) + ocm_slits.outboard.move(2105.959) + ocm_slits.inboard.move(-1839.037) + + print("Resetting Anti-scatter Slits") + caput("XF:28ID1B-OP{Slt:AS-Ax:T}Mtr.VAL", -24.80948) # Top + caput("XF:28ID1B-OP{Slt:AS-Ax:B}Mtr.VAL", -31.34997) # Bottom + caput("XF:28ID1B-OP{Slt:AS-Ax:O}Mtr.VAL", -27.69998) # Outboard + caput("XF:28ID1B-OP{Slt:AS-Ax:I}Mtr.VAL", 6.29888) # inboard + print("Ready to go !") + def saxs(): - print("Resetting white beam slits") - wb_slits.inboard.move(-13.6) - wb_slits.outboard.move(-7.54218) - - print("Resetting Monochromator") - sbm.yaw.move(0.0) - sbm.roll.move(0.0) - sbm.pitch.move(-0.05149) - sbm.bend.move(1550) - sbm.twist.move(-30) - - print("Resetting Mirror") - Mirror_VFM.y_upstream.move(-0.7) - Mirror_VFM.y_downstream_inboard.move(-0.02) - Mirror_VFM.y_downstream_outboard.move(0.32) - Mirror_VFM.bend_upstream.move(10) - Mirror_VFM.bend_downstream.move(10) - - print("Resetting BDM Slits") - #bdm_slits.top.move(999.957) - #bdm_slits.bottom.move(-94363.970) - #bdm_slits.inboard.move(-7600.960) - #bdm_slits.outboard.move(-4100.075) - - print("Resetting OCM Slits") - ocm_slits.top.move(-1065.0) - ocm_slits.bottom.move(1955.0) - ocm_slits.outboard.move(635.959) - ocm_slits.inboard.move(-94.037) - OCM_table.upstream_jack.move(4.14225) - OCM_table.downstream_jack.move(-4.1700) - OCM_table.X.move(-8.44701) - print("Ready to go !") + print("Resetting white beam slits") + wb_slits.inboard.move(-13.6) + wb_slits.outboard.move(-7.54218) + + print("Resetting Monochromator") + sbm.yaw.move(0.0) + sbm.roll.move(0.0) + sbm.pitch.move(-0.05149) + sbm.bend.move(1550) + sbm.twist.move(-30) + + print("Resetting Mirror") + Mirror_VFM.y_upstream.move(-0.7) + Mirror_VFM.y_downstream_inboard.move(-0.02) + Mirror_VFM.y_downstream_outboard.move(0.32) + Mirror_VFM.bend_upstream.move(10) + Mirror_VFM.bend_downstream.move(10) + + print("Resetting BDM Slits") + # bdm_slits.top.move(999.957) + # bdm_slits.bottom.move(-94363.970) + # bdm_slits.inboard.move(-7600.960) + # bdm_slits.outboard.move(-4100.075) + + print("Resetting OCM Slits") + ocm_slits.top.move(-1065.0) + ocm_slits.bottom.move(1955.0) + ocm_slits.outboard.move(635.959) + ocm_slits.inboard.move(-94.037) + OCM_table.upstream_jack.move(4.14225) + OCM_table.downstream_jack.move(-4.1700) + OCM_table.X.move(-8.44701) + print("Ready to go !") def BDM_plot(): - from mpl_toolkits.mplot3d import Axes3D - from matplotlib import pylab as pl - from PIL import Image - import numpy as np - import pylab - - img = Image.open('/nsls2/xf28id1/BDM_camera/BDM_ROI_000.tiff').convert('L') - z = np.asarray(img) - mydata = z[375:450:1, 550:850:1]#y and x - #mydata = z[164:300:1, 200:1000:1] - fig = pl.figure(facecolor='w') - ax1 = fig.add_subplot(1,2,1) - im = ax1.imshow(mydata,interpolation='nearest',cmap=pl.cm.jet) - ax1.set_title('2D') - - ax2 = fig.add_subplot(1,2,2,projection='3d') - x,y = np.mgrid[:mydata.shape[0],:mydata.shape[1]] - ax2.plot_surface(x,y,mydata,cmap=pl.cm.jet,rstride=1,cstride=1,linewidth=0.,antialiased=False) - ax2.set_title('3D') - #ax2.set_zlim3d(0,100) - pl.show() + from mpl_toolkits.mplot3d import Axes3D + from matplotlib import pylab as pl + from PIL import Image + import numpy as np + import pylab + + img = Image.open("/nsls2/xf28id1/BDM_camera/BDM_ROI_000.tiff").convert("L") + z = np.asarray(img) + mydata = z[375:450:1, 550:850:1] # y and x + # mydata = z[164:300:1, 200:1000:1] + fig = pl.figure(facecolor="w") + ax1 = fig.add_subplot(1, 2, 1) + im = ax1.imshow(mydata, interpolation="nearest", cmap=pl.cm.jet) + ax1.set_title("2D") + + ax2 = fig.add_subplot(1, 2, 2, projection="3d") + x, y = np.mgrid[: mydata.shape[0], : mydata.shape[1]] + ax2.plot_surface( + x, + y, + mydata, + cmap=pl.cm.jet, + rstride=1, + cstride=1, + linewidth=0.0, + antialiased=False, + ) + ax2.set_title("3D") + # ax2.set_zlim3d(0,100) + pl.show() + # ----------turbo() is a Temporary fix until auto turbo mode is implemented in the css layer--------- from epics import caget, caput -turbo_T = 110 # Turbo turning on temperature + +turbo_T = 110 # Turbo turning on temperature + + def turbo(): current_T = cryostream.T.get() tb = caget("XF:28ID1-ES:1{Env:01}Cmd:Turbo-Cmd") @@ -225,77 +242,94 @@ def turbo(): if current_T >= turbo_T and tb == 1: caput("XF:28ID1-ES:1{Env:01}Cmd:Turbo-Cmd", 0) time.sleep(2) - caput("XF:28ID1-ES:1{Env:01}Cmd-Cmd", 20) + caput("XF:28ID1-ES:1{Env:01}Cmd-Cmd", 20) + # get direct beamcurrent -#def I0(): +# def I0(): # I0 = caget("SR:OPS-BI{DCCT:1}I:Real-I") -#---------------------------function to display the dark subtracted last image ---------------------------------- +# ---------------------------function to display the dark subtracted last image ---------------------------------- from tifffile import imread, imshow, imsave + + def lastimage(n): - hdr=db[-n] + hdr = db[-n] for doc in hdr.documents(fill=True): - data1=doc[1].get('data') - if data1 != None: - light_img=data1['pe1c_image'] - + data1 = doc[1].get("data") + if data1 != None: + light_img = data1["pe1c_image"] - dark_uid=hdr.start. get('sc_dk_field_uid') - dk_hdrs=db(uid=dark_uid) + dark_uid = hdr.start.get("sc_dk_field_uid") + dk_hdrs = db(uid=dark_uid) for dk_hdr in dk_hdrs: - for doc in dk_hdr.documents(fill=True): - dk_data1=doc[1].get('data') - if dk_data1 != None: - dk_img=dk_data1['pe1c_image'] + for doc in dk_hdr.documents(fill=True): + dk_data1 = doc[1].get("data") + if dk_data1 != None: + dk_img = dk_data1["pe1c_image"] I = light_img - dk_img - imshow(I, vmax = (I.sum()/(2048*2048)), cmap = 'jet' ) - imsave("/nsls2/xf28id1/xpdacq_data/user_data/tiff_base/" + "dark_sub_image" + ".tiff", light_img - dk_img) - imsave("/nsls2/xf28id1/xpdacq_data/user_data/tiff_base/" + "dark_image" + ".tiff", dk_img) - imsave("/nsls2/xf28id1/xpdacq_data/user_data/tiff_base/" + "light_image" + ".tiff", light_img) - - -#---------------------------------HAB T setpoint threshold-------------------------------------------- + imshow(I, vmax=(I.sum() / (2048 * 2048)), cmap="jet") + imsave( + "/nsls2/xf28id1/xpdacq_data/user_data/tiff_base/" + "dark_sub_image" + ".tiff", + light_img - dk_img, + ) + imsave( + "/nsls2/xf28id1/xpdacq_data/user_data/tiff_base/" + "dark_image" + ".tiff", + dk_img, + ) + imsave( + "/nsls2/xf28id1/xpdacq_data/user_data/tiff_base/" + "light_image" + ".tiff", + light_img, + ) + + +# ---------------------------------HAB T setpoint threshold-------------------------------------------- def HAB_Tset(t, threshold, settle_time): - caput("XF:28ID1-ES:1{Env:05}LOOP1:SP", t) - T_now = hotairblower.get() + caput("XF:28ID1-ES:1{Env:05}LOOP1:SP", t) + T_now = hotairblower.get() - while T_now not in range(t-threshold, t+2*threshold): - T_now = hotairblower.get() - time.sleep(0.5) - time.sleep(settle_time) + while T_now not in range(t - threshold, t + 2 * threshold): + T_now = hotairblower.get() + time.sleep(0.5) + time.sleep(settle_time) -#---------------------------------Magnet I setpoint threshold-------------------------------------------- -def Magnet_Iset(i, settle_time): # rounds up the setpoint to a integer thres - RE(mv(magnet.setpoint,i)) - I_now = magnet.readback.get() - while np.around(I_now)!=i : - I_now = magnet.readback.get() - time.sleep(0.5) - time.sleep(settle_time) +# ---------------------------------Magnet I setpoint threshold-------------------------------------------- +def Magnet_Iset(i, settle_time): # rounds up the setpoint to a integer thres + RE(mv(magnet.setpoint, i)) + I_now = magnet.readback.get() -def Magnet_Iset2(i, thershold_1_D_point,settle_time): - RE(mv(magnet.setpoint,i)) - I_now = magnet.readback.get() + while np.around(I_now) != i: + I_now = magnet.readback.get() + time.sleep(0.5) + time.sleep(settle_time) - while (I_now*10) not in range(np.around((i-thershold_1_D_point)*10,1), np.around((i+thershold_1_D_point)*10,1)): - I_now = magnet.readback.get() - time.sleep(0.5) - time.sleep(settle_time) -def Cryostat_CF(t, settle_time): # rounds up the setpoint to a integer thres - RE(mv(cryostat1,t)) - t_now = caget('XF:28ID1-ES1:LS335:{CryoStat}:IN2') +def Magnet_Iset2(i, thershold_1_D_point, settle_time): + RE(mv(magnet.setpoint, i)) + I_now = magnet.readback.get() - while np.around(t_now)!=i : - t_now = caget('XF:28ID1-ES1:LS335:{CryoStat}:IN2') - time.sleep(0.5) - time.sleep(settle_time) + while (I_now * 10) not in range( + np.around((i - thershold_1_D_point) * 10, 1), + np.around((i + thershold_1_D_point) * 10, 1), + ): + I_now = magnet.readback.get() + time.sleep(0.5) + time.sleep(settle_time) + + +def Cryostat_CF(t, settle_time): # rounds up the setpoint to a integer thres + RE(mv(cryostat1, t)) + t_now = caget("XF:28ID1-ES1:LS335:{CryoStat}:IN2") - -#---------------------------------HAB T setpoint threshold-------------------------------------------- + while np.around(t_now) != i: + t_now = caget("XF:28ID1-ES1:LS335:{CryoStat}:IN2") + time.sleep(0.5) + time.sleep(settle_time) + + +# ---------------------------------HAB T setpoint threshold-------------------------------------------- def Humidity_set(a, b, threshold, settle_time): RE(flow(a,b)) H = readRH @@ -316,4 +350,4 @@ def HAB_Tset(t, threshold, settle_time): T_now = caget("Readback PV") time.sleep(0.5) time.sleep(settle_time) -''' \ No newline at end of file +''' diff --git a/startup/98-jog_scans.py b/startup/98-jog_scans.py index c6f8ff9..6df5469 100644 --- a/startup/98-jog_scans.py +++ b/startup/98-jog_scans.py @@ -1,5 +1,6 @@ from bluesky.utils import short_uid + def future_count(detectors, num=1, delay=None, *, per_shot=None, md=None): """ Take one or more readings from detectors. @@ -145,18 +146,17 @@ def rocking_ct(dets, exposure, motor, start, stop, *, num=1, md=None): @bpp.reset_positions_decorator([motor.velocity]) def per_shot(dets): nonlocal start, stop - yield from bps.mv(motor, start) # got to initial position - yield from bps.mv(motor.velocity, abs(stop - start) / exposure) # set velocity + yield from bps.mv(motor.velocity, abs(stop - start) / exposure) # set velocity gp = short_uid("rocker") - yield from bps.abs_set(motor, stop, group=gp) # set motor to move towards end - yield from bps.trigger_and_read(dets) # collect off detector + yield from bps.abs_set(motor, stop, group=gp) # set motor to move towards end + yield from bps.trigger_and_read(dets) # collect off detector yield from bps.wait(group=gp) start, stop = stop, start + yield from bps.mv(motor, start) # got to initial position return (yield from future_count(dets, md=_md, per_shot=per_shot, num=num)) + def jog(exposure_s, motor, start, stop): - """ pass total exposure time (in seconds), motor name (i.e. Grid_Y), start and stop positions for the motor.""" + """pass total exposure time (in seconds), motor name (i.e. Grid_Y), start and stop positions for the motor.""" yield from rocking_ct([pe1c], exposure_s, motor, start, stop) - - diff --git a/startup/98-map_scans.py b/startup/98-map_scans.py index 6b4c2df..dd34fe2 100644 --- a/startup/98-map_scans.py +++ b/startup/98-map_scans.py @@ -156,9 +156,9 @@ def dp(det : Detector, shell : SnapshotShell): "dimensions", [((f"start_{fly_motor.name}",), "primary"), ((step_motor.name,), "primary")], ) - #_md["hints"].setdefault( + # _md["hints"].setdefault( # "extents", [(fly_start, fly_stop), (step_stop, step_start)], - #) + # ) # soft signal to use for tracking pixel edges # TODO put better metadata on these @@ -252,7 +252,8 @@ def dark_plan(detector, shell, *, stream_name="dark"): # emit the event to the dark stream yield from bps.stage(shell) yield from bps.trigger_and_read( - [shell], name=stream_name, + [shell], + name=stream_name, ) yield from bps.unstage(shell) diff --git a/startup/99-demo_plans.py b/startup/99-demo_plans.py new file mode 100644 index 0000000..1395a41 --- /dev/null +++ b/startup/99-demo_plans.py @@ -0,0 +1,197 @@ +from dataclasses import dataclass +import bluesky.plan_stubs as bps +from xpdacq.xpdacq import translate_to_sample as get_metadata_for_sample_number +import itertools + + +@dataclass(frozen=True) +class SamplePos: + x: float + y: float + + +@dataclass(frozen=True) +class DetectorConfiguration: + beamstop_x: float + beamstop_y: float + detector: float + + +SAMPLE_POSITONS = { + # 'a': SamplePos(0, 0), +} + +DETECTOR_POSITIONS = { + "near": DetectorConfiguration( + beamstop_x=-16.44653, beamstop_y=3.7878875, detector=3700.0 + ), + "far": DetectorConfiguration( + beamstop_x=-16.44653, beamstop_y=3.7878875, detector=4700.0 + ), +} + + +def move_det(x: float = None, y: float = None, z: float = None): + """ + Move the detector to the given (x, y, z) + + """ + args = tuple( + itertools.chain( + (m, t) + for m, t in zip([Det_1_X, Det_1_Y, Det_1_Z], [x, y, z]) + if t is not None + ) + ) + yield from bps.mv(*args) + + +def move_sample(x: float = None, y: float = None, z: float = None): + """ + Move the detector to the given (x, y, z) + + """ + args = tuple( + itertools.chain( + (m, t) for m, t in zip([Grid_X, Grid_Y, Grid_Z], [x, y, z]) if t is not None + ) + ) + yield from bps.mv(*args) + + +def move_to_sample(name: str): + sample_x = Grid_X + sample_y = Grid_Y + target_pos = SAMPLE_POSITONS[name] + yield from bps.mv(sample_x, target_pos.x, sample_y, target_pos.y) + + +def move_to_det_config(name: str): + + detector_motor = Det_1_Z + beam_stop = BStop1 + + target_pos = DETECTOR_POSITIONS[name] + yield from bps.mv( + beam_stop.x, + target_pos.beamstop_x, + beam_stop.y, + target_pos.beamstop_y, + detector_motor, + target_pos.detector, + ) + + +def sample_aware_count(sample_num: int, exposure: float, *, md=None): + """ + A wrapper around count that tries to mimic xpdacq. + + """ + _md = get_metadata_for_sample_number(bt, sample_num) + _md.update(md or {}) + yield from simple_ct([pe1c], exposure, md=_md) + + +fake_db = { + 0: { + "xpdacq_number": 0, + "detector_position": "far", + "jog_start": 936.0 - 0.0, + "jog_stop": 936.0 + 0.0, + "x": 45.26912, + } +} + + +def _df_to_fake_db(df): + key_map = { + "xpdacq_number": "xpdacq_name_num", + "x": "xpos", + "jog_start": "ymin", + "job_stop": "ymax", + "detector_position": "det_pos", + } + + return { + ix: {dest: r[src] for dest, src in key_map.items()} for ix, r in df.iterrows() + } + + +def _refresh_sample_database() -> dict: + # target = '/nsls2/data/pdf/legacy/processed/xpdacq_data/user_data_Purdy_Fall2021_Brackets_307061_4b04ec0b_2021-10-11-0917/my_df2.xlsx' + # return _df_to_fake_db(pd.read_excel(target)) + return fake_db + + +def _pdf_count( + sample_number: str, + exposure_time: float, + *, + sample_db: dict, + z_for_move: float, + z_for_data: float, + md: dict, + # detectors + dets: list, + # motors + beam_stop: Device, + detector_motor: EpicsMotor, + sample_x: EpicsMotor, + sample_y: EpicsMotor, + sample_z: EpicsMotor, + bt, +): + # sample_db = _refresh_sample_database() + sample_info = sample_db[sample_number] + _md = get_metadata_for_sample_number(bt, sample_info["xpdacq_number"]) + _md["sample_info"] = sample_info + _md.update(md or {}) + + target_pos = DETECTOR_POSITIONS[sample_info["detector_position"]] + yield from bps.mv(sample_z, z_for_move) + yield from bps.mv( + # beamstop and detector + # TODO make beamstop optional + beam_stop.x, + target_pos.beamstop_x, + beam_stop.y, + target_pos.beamstop_y, + detector_motor, + target_pos.detector, + # sample position + sample_x, + sample_info["x"], + sample_y, + sample_info["jog_start"], + ) + yield from bps.mv(sample_z, z_for_data) + yield from rocking_ct( + dets, + exposure_time, + sample_y, + sample_info["jog_start"], + sample_info["jog_stop"], + md=_md, + ) + + +def pdf_count(sample_number: int, exposure_time: float, *, md: dict = {}): + yield from _pdf_count( + sample_number=sample_number, + exposure_time=exposure_time, + sample_db=_refresh_sample_database(), + z_for_data=909.83, + z_for_move=909.83 + 15.0, + md=md, + # + beam_stop=BStop1, + detector_motor=Det_1_Z, + sample_y=Grid_Y, + sample_x=broadside45_shifter, + sample_z=Grid_Z, + bt=bt, + dets=[pe1c], + ) + +def take_a_nap(delay: float): + yield from bps.sleep(delay) \ No newline at end of file diff --git a/startup/99-humidity.py b/startup/99-humidity.py index 4ae1767..d90b2db 100644 --- a/startup/99-humidity.py +++ b/startup/99-humidity.py @@ -1,42 +1,50 @@ -#Voltage output 1 -#PV: XF:28ID1-ES{IO-E1241:1}AO:2-SP -#MOXA (E1241) channel: AO1 -#Voltage output 2 -#PV: XF:28ID1-ES{IO-E1241:1}AO:4-SP -#MOXA (E1241) channel: AO 3 -#Voltage input -#PV: XF:28ID1-ES{IO-E1240:1}AI:2-I -#MOXA (E1240) channel: AI +# Voltage output 1 +# PV: XF:28ID1-ES{IO-E1241:1}AO:2-SP +# MOXA (E1241) channel: AO1 +# Voltage output 2 +# PV: XF:28ID1-ES{IO-E1241:1}AO:4-SP +# MOXA (E1241) channel: AO 3 +# Voltage input +# PV: XF:28ID1-ES{IO-E1240:1}AI:2-I +# MOXA (E1240) channel: AI -flow_dry_v = EpicsSignal("XF:28ID1-ES{IO-E1241:1}AO:4-SP",name="flow_dry_v") -flow_wet_v = EpicsSignal("XF:28ID1-ES{IO-E1241:1}AO:2-SP",name="flow_wet_v") -humidity_v = EpicsSignal("XF:28ID1-ES{IO-E1240:1}AI:8-I",name="humidity_v") +flow_dry_v = EpicsSignal("XF:28ID1-ES{IO-E1241:1}AO:4-SP", name="flow_dry_v") +flow_wet_v = EpicsSignal("XF:28ID1-ES{IO-E1241:1}AO:2-SP", name="flow_wet_v") +humidity_v = EpicsSignal("XF:28ID1-ES{IO-E1240:1}AI:8-I", name="humidity_v") -def readRH( temperature=25.0, voltage_supply=5.0, coeff_slope=0.030, coeff_offset=0.787, verbosity=3): - voltage_out = humidity_v.get() - corr_voltage_out = voltage_out * (5.0 / voltage_supply) - #For sensor #220 used for SVA chamber - #coeff_offset = 0.788 #from the certificate - #coeff_offset = 0.746 #from the environment of RH=0 - #coeff_slope = 0.029 - #For sensor used for Linkam tensile stage - #coeff_offset = 0.787 - #coeff_slope = 0.030 - #For sensor 114 used for environmental bar - #coeff_offset = 0.787 - #coeff_slope = 0.030 - #For sensor 43 used in humidity stage - coeff_offset = 0.816887 - coeff_slope = 0.028813 - sensor_RH = (corr_voltage_out - coeff_offset) / coeff_slope - true_RH = sensor_RH / (1.0546 - 0.00216 * temperature) # T in [degC] - if verbosity >= 3: - print('Raw sensor RH = {:.3f} pct.'.format(sensor_RH)) - print('T-corrected RH = {:.3f} pct at {:.3f} degC.'.format(true_RH, temperature)) - return true_RH -def flow(dry,wet): - yield from mov(flow_dry_v,dry) - yield from mov(flow_wet_v,wet) - - +def readRH( + temperature=25.0, + voltage_supply=5.0, + coeff_slope=0.030, + coeff_offset=0.787, + verbosity=3, +): + voltage_out = humidity_v.get() + corr_voltage_out = voltage_out * (5.0 / voltage_supply) + # For sensor #220 used for SVA chamber + # coeff_offset = 0.788 #from the certificate + # coeff_offset = 0.746 #from the environment of RH=0 + # coeff_slope = 0.029 + # For sensor used for Linkam tensile stage + # coeff_offset = 0.787 + # coeff_slope = 0.030 + # For sensor 114 used for environmental bar + # coeff_offset = 0.787 + # coeff_slope = 0.030 + # For sensor 43 used in humidity stage + coeff_offset = 0.816887 + coeff_slope = 0.028813 + sensor_RH = (corr_voltage_out - coeff_offset) / coeff_slope + true_RH = sensor_RH / (1.0546 - 0.00216 * temperature) # T in [degC] + if verbosity >= 3: + print("Raw sensor RH = {:.3f} pct.".format(sensor_RH)) + print( + "T-corrected RH = {:.3f} pct at {:.3f} degC.".format(true_RH, temperature) + ) + return true_RH + + +def flow(dry, wet): + yield from mov(flow_dry_v, dry) + yield from mov(flow_wet_v, wet) diff --git a/startup/99-linkam.py b/startup/99-linkam.py index c950fc5..da9cf92 100644 --- a/startup/99-linkam.py +++ b/startup/99-linkam.py @@ -1,8 +1,11 @@ from ophyd.signal import DerivedSignal -#import inflection, textwrap, ansiwrap + +# import inflection, textwrap, ansiwrap + class AtSetpoint(DerivedSignal): - '''A signal that does bit-wise arithmetic on the Linkam's status code''' + """A signal that does bit-wise arithmetic on the Linkam's status code""" + def __init__(self, parent_attr, *, parent=None, **kwargs): code_signal = getattr(parent, parent_attr) super().__init__(derived_from=code_signal, parent=parent, **kwargs) @@ -21,60 +24,58 @@ def forward(self, value): # desc[self.name]['units'] = 'eV' # return desc - + class Linkam(PVPositioner): - '''An ophyd wrapper around the Linkam T96 controller - ''' + """An ophyd wrapper around the Linkam T96 controller""" ## following https://blueskyproject.io/ophyd/positioners.html#pvpositioner - readback = Cpt(EpicsSignalRO, 'TEMP') - setpoint = Cpt(EpicsSignal, 'SETPOINT:SET') - status_code = Cpt(EpicsSignal, 'STATUS') - done = Cpt(AtSetpoint, parent_attr = 'status_code') + readback = Cpt(EpicsSignalRO, "TEMP") + setpoint = Cpt(EpicsSignal, "SETPOINT:SET") + status_code = Cpt(EpicsSignal, "STATUS") + done = Cpt(AtSetpoint, parent_attr="status_code") ## all the rest of the Linkam signals - init = Cpt(EpicsSignal, 'INIT') - model_array = Cpt(EpicsSignal, 'MODEL') - serial_array = Cpt(EpicsSignal, 'SERIAL') - stage_model_array = Cpt(EpicsSignal, 'STAGE:MODEL') - stage_serial_array = Cpt(EpicsSignal, 'STAGE:SERIAL') - firm_ver = Cpt(EpicsSignal, 'FIRM:VER') - hard_ver = Cpt(EpicsSignal, 'HARD:VER') - ctrllr_err = Cpt(EpicsSignal, 'CTRLLR:ERR') - config = Cpt(EpicsSignal, 'CONFIG') - stage_config = Cpt(EpicsSignal, 'STAGE:CONFIG') - disable = Cpt(EpicsSignal, 'DISABLE') - dsc = Cpt(EpicsSignal, 'DSC') - RR_set = Cpt(EpicsSignal, 'RAMPRATE:SET') - RR = Cpt(EpicsSignal, 'RAMPRATE') - ramptime = Cpt(EpicsSignal, 'RAMPTIME') - startheat = Cpt(EpicsSignal, 'STARTHEAT') - holdtime_set = Cpt(EpicsSignal, 'HOLDTIME:SET') - holdtime = Cpt(EpicsSignal, 'HOLDTIME') - power = Cpt(EpicsSignalRO, 'POWER') - lnp_speed = Cpt(EpicsSignal, 'LNP_SPEED') - lnp_mode_set = Cpt(EpicsSignal, 'LNP_MODE:SET') - lnp_speed_set = Cpt(EpicsSignal, 'LNP_SPEED:SET') - - + init = Cpt(EpicsSignal, "INIT") + model_array = Cpt(EpicsSignal, "MODEL") + serial_array = Cpt(EpicsSignal, "SERIAL") + stage_model_array = Cpt(EpicsSignal, "STAGE:MODEL") + stage_serial_array = Cpt(EpicsSignal, "STAGE:SERIAL") + firm_ver = Cpt(EpicsSignal, "FIRM:VER") + hard_ver = Cpt(EpicsSignal, "HARD:VER") + ctrllr_err = Cpt(EpicsSignal, "CTRLLR:ERR") + config = Cpt(EpicsSignal, "CONFIG") + stage_config = Cpt(EpicsSignal, "STAGE:CONFIG") + disable = Cpt(EpicsSignal, "DISABLE") + dsc = Cpt(EpicsSignal, "DSC") + RR_set = Cpt(EpicsSignal, "RAMPRATE:SET") + RR = Cpt(EpicsSignal, "RAMPRATE") + ramptime = Cpt(EpicsSignal, "RAMPTIME") + startheat = Cpt(EpicsSignal, "STARTHEAT") + holdtime_set = Cpt(EpicsSignal, "HOLDTIME:SET") + holdtime = Cpt(EpicsSignal, "HOLDTIME") + power = Cpt(EpicsSignalRO, "POWER") + lnp_speed = Cpt(EpicsSignal, "LNP_SPEED") + lnp_mode_set = Cpt(EpicsSignal, "LNP_MODE:SET") + lnp_speed_set = Cpt(EpicsSignal, "LNP_SPEED:SET") + def on(self): self.startheat.put(1) def off(self): self.startheat.put(0) - + def on_plan(self): - return(yield from mv(self.startheat, 1)) + return (yield from mv(self.startheat, 1)) def off_plan(self): - return(yield from mv(self.startheat, 0)) + return (yield from mv(self.startheat, 0)) def arr2word(self, lst): - word = '' + word = "" for l in lst[:-1]: word += chr(l) return word - + @property def serial(self): return self.arr2word(self.serial_array.get()) @@ -82,11 +83,11 @@ def serial(self): @property def model(self): return self.arr2word(self.model_array.get()) - + @property def stage_model(self): return self.arr2word(self.stage_model_array.get()) - + @property def stage_serial(self): return self.arr2word(self.stage_serial_array.get()) @@ -100,78 +101,81 @@ def hardware_version(self): return self.arr2word(self.hard_ver.get()) def status(self): - text = f'\nCurrent temperature = {self.readback.get():.1f}, setpoint = {self.setpoint.get():.1f}\n\n' + text = f"\nCurrent temperature = {self.readback.get():.1f}, setpoint = {self.setpoint.get():.1f}\n\n" code = int(self.status_code.get()) if code & 1: - text += error_msg('Error : yes') + '\n' + text += error_msg("Error : yes") + "\n" else: - text += 'Error : no\n' + text += "Error : no\n" if code & 2: - text += go_msg('At setpoint : yes') + '\n' + text += go_msg("At setpoint : yes") + "\n" else: - text += 'At setpoint : no\n' + text += "At setpoint : no\n" if code & 4: - text += go_msg('Heater : on') + '\n' + text += go_msg("Heater : on") + "\n" else: - text += 'Heater : off\n' + text += "Heater : off\n" if code & 8: - text += go_msg('Pump : on') + '\n' + text += go_msg("Pump : on") + "\n" else: - text += 'Pump : off\n' + text += "Pump : off\n" if code & 16: - text += go_msg('Pump Auto : yes') + '\n' + text += go_msg("Pump Auto : yes") + "\n" else: - text += 'Pump Auto : no\n' - - boxedtext(f'Linkam {self.model}, stage {self.stage_model}', text, 'brown', width = 45) + text += "Pump Auto : no\n" + + boxedtext( + f"Linkam {self.model}, stage {self.stage_model}", text, "brown", width=45 + ) def boxedtext(title, text, tint, width=75): - ''' + """ Put text in a lovely unicode block element box. The top of the box will contain a title. The box elements will be colored. - ''' + """ remainder = width - 2 - len(title) - ul = u'\u2554' # u'\u250C' - ur = u'\u2557' # u'\u2510' - ll = u'\u255A' # u'\u2514' - lr = u'\u255D' # u'\u2518' - bar = u'\u2550' # u'\u2500' - strut = u'\u2551' # u'\u2502' - template = '%-' + str(width) + 's' - - print('') - print(colored(''.join([ul, bar*3, ' ', title, ' ', bar*remainder, ur]), tint)) - for line in text.split('\n'): + ul = "\u2554" # u'\u250C' + ur = "\u2557" # u'\u2510' + ll = "\u255A" # u'\u2514' + lr = "\u255D" # u'\u2518' + bar = "\u2550" # u'\u2500' + strut = "\u2551" # u'\u2502' + template = "%-" + str(width) + "s" + + print("") + print(colored("".join([ul, bar * 3, " ", title, " ", bar * remainder, ur]), tint)) + for line in text.split("\n"): lne = line.rstrip() - #add = ' '*(width-ansiwrap.ansilen(lne)) - add = ' '*(width-5) - print(' '.join([colored(strut, tint), lne, add, colored(strut, tint)])) - print(colored(''.join([ll, bar*(width+3), lr]), tint)) + # add = ' '*(width-ansiwrap.ansilen(lne)) + add = " " * (width - 5) + print(" ".join([colored(strut, tint), lne, add, colored(strut, tint)])) + print(colored("".join([ll, bar * (width + 3), lr]), tint)) -def colored(text, tint='white', attrs=[],do_thing=False): - ''' +def colored(text, tint="white", attrs=[], do_thing=False): + """ A simple wrapper around IPython's interface to TermColors - ''' + """ if not do_thing: from IPython.utils.coloransi import TermColors as color + tint = tint.lower() - if 'dark' in tint: - tint = 'Dark' + tint[4:].capitalize() - elif 'light' in tint: - tint = 'Light' + tint[5:].capitalize() - elif 'blink' in tint: - tint = 'Blink' + tint[5:].capitalize() - elif 'no' in tint: - tint = 'Normal' + if "dark" in tint: + tint = "Dark" + tint[4:].capitalize() + elif "light" in tint: + tint = "Light" + tint[5:].capitalize() + elif "blink" in tint: + tint = "Blink" + tint[5:].capitalize() + elif "no" in tint: + tint = "Normal" else: tint = tint.capitalize() - return '{0}{1}{2}'.format(getattr(color, tint), text, color.Normal) + return "{0}{1}{2}".format(getattr(color, tint), text, color.Normal) else: - return(text) + return text -linkam = Linkam('XF:28ID1-ES{LINKAM:T96}:', name='linkam', settle_time=0) +linkam = Linkam("XF:28ID1-ES{LINKAM:T96}:", name="linkam", settle_time=0) diff --git a/startup/99-qs_agent_plans.py b/startup/99-qs_agent_plans.py new file mode 100644 index 0000000..3b1afde --- /dev/null +++ b/startup/99-qs_agent_plans.py @@ -0,0 +1,280 @@ +from confluent_kafka import Producer +from nslsii.kafka_utils import _read_bluesky_kafka_config_file +import msgpack +import json + +import redis + +def agent_directive(tla, name, doc): + """ + Issue any directive to a listening agent by name/uid. + Parameters + ---------- + tla : str + Beamline three letter acronym + name : str + Unique agent name. These are generated using xkcdpass for names like: + "agent-exotic-farm" + "xca-clever-table" + doc : dict + This is the message to pass to the agent. It must take the form: + {"action": method_name, + "args": (arguments,), + "kwargs: {keyword:argument} + } + Returns + ------- + """ + kafka_config = _read_bluesky_kafka_config_file("/etc/bluesky/kafka.yml") + producer_config = dict() + producer_config.update(kafka_config["runengine_producer_config"]) + producer_config["bootstrap.servers"] = ",".join(kafka_config["bootstrap_servers"]) + agent_producer = Producer(producer_config) + + # All 3 steps should happen for each message publication + agent_producer.produce(topic=f"{tla}.mmm.bluesky.agents", key="", value=msgpack.dumps((name, doc))) + agent_producer.poll(0) + agent_producer.flush() + yield from bps.null() + +# def agent_sample_count(motor, position: float, exposure: float, *, sample_number: int, md=None): +# yield from bps.mv(motor, position) +# _md = dict( +# Grid_X=Grid_X.read(), +# Grid_Y=Grid_Y.read(), +# Grid_Z=Grid_Z.read(), +# Det_1_X=Det_1_X.read(), +# Det_1_Y=Det_1_Y.read(), +# Det_1_Z=Det_1_Z.read(), +# ring_current=ring_current.read(), +# BStop1=BStop1.read(), +# ) +# _md.update(get_metadata_for_sample_number(bt, sample_number)) +# _md.update(md or {}) +# yield from simple_ct([pe1c], exposure, md=_md) + + + +def agent_redisAware_XRDcount(position: float, *, md=None): + rkvs = redis.Redis(host="info.pdf.nsls2.bnl.gov", port=6379, db=0) # redis key value store + #fixing motor for now + motor = Grid_X + + #getting XRD distance + target_dist = float(rkvs.get('PDF:bl_config:Det_1_Z:far').decode('utf-8')) + print ('moving to XRD position') + yield from bps.mv(Det_1_Z, target_dist) + #put xrd-speicifc config in place + #my_config = {'auto_mask': False, + #'user_mask': '/nsls2/data2/pdf/legacy/processed/xpdacq_data/user_data/my_mask_xrd.npy', + #'method': 'splitpixel'} + #p_my_config = json.dumps(my_config) + #rkvs.set('PDF:xpdacq:user_config',p_my_config) + + #getting the user_config from redis + p_my_config = rkvs.get("PDF:xpdacq:user_config:far") + user_config = json.loads(p_my_config) #here is the user_config + + if bool(rkvs.exists('PDF:xpdacq:xrd_sample_number')): + sample_number = int(rkvs.get('PDF:xpdacq:xrd_sample_number').decode('utf-8')) #here is the sample num + else: + print ('missing sample number in redis') + + #gettting sample metadata from redis + if bool(rkvs.exists('PDF:xpdacq:sample_dict')): + p_info = rkvs.get('PDF:xpdacq:sample_dict') + else: + print ('missing bt sample info, need to stow_bt_sample_info') + all_sample_info = json.loads(p_info) + sample_name = list(all_sample_info)[sample_number] + this_sample_md = all_sample_info[sample_name] #here is the sample metadata from bt + + #get the XRD calibration info from redis + xrd_calib_md = json.loads(rkvs.get('PDF:xpdacq:xrd_calibration_md')) + + #getting exposure time from redis + exposure = float(rkvs.get('PDF:desired_exposure_time').decode('utf-8')) + #print ('exposure is '+str(exposure)) + + yield from bps.mv(motor, position) + _md = dict( + Grid_X=Grid_X.read(), + Grid_Y=Grid_Y.read(), + Grid_Z=Grid_Z.read(), + Det_1_X=Det_1_X.read(), + Det_1_Y=Det_1_Y.read(), + Det_1_Z=Det_1_Z.read(), + ring_current=ring_current.read(), + BStop1=BStop1.read(), + user_config=user_config, + calibration_md = xrd_calib_md, + ) + #_md.update(get_metadata_for_sample_number(bt, sample_number)) + _md.update(this_sample_md) + _md.update(md or {}) + yield from simple_ct([pe1c], exposure, md=_md) + + +def agent_redisAware_PDFcount(position: float, *, md=None): + rkvs = redis.Redis(host="info.pdf.nsls2.bnl.gov", port=6379, db=0) # redis key value store + #fixing motor for now + motor = Grid_X + + #getting PDF distance + target_dist = float(rkvs.get('PDF:bl_config:Det_1_Z:near').decode('utf-8')) + print ('moving to PDF position') + yield from bps.mv(Det_1_Z, target_dist) + #put pdf-specific config in place + #my_config = {'auto_mask': False, + #'user_mask': '/nsls2/data2/pdf/legacy/processed/xpdacq_data/user_data/my_mask_pdf.npy', + #'method': 'splitpixel'} + #p_my_config = json.dumps(my_config) + #rkvs.set('PDF:xpdacq:user_config',p_my_config) + + #getting the user_config from redis + p_my_config = rkvs.get("PDF:xpdacq:user_config:near") + user_config = json.loads(p_my_config) #here is the user_config + + #getting the current sample number from redis + #check if this exists, then read + if bool(rkvs.exists('PDF:xpdacq:pdf_sample_number')): + sample_number = int(rkvs.get('PDF:xpdacq:pdf_sample_number').decode('utf-8')) #here is the sample num + else: + print ('missing sample number in redis') + + #gettting sample metadata from redis + p_info = rkvs.get('PDF:xpdacq:sample_dict') + all_sample_info = json.loads(p_info) + sample_name = list(all_sample_info)[sample_number] + this_sample_md = all_sample_info[sample_name] #here is the sample metadata from bt + + #get the PDF calibration info from redis + #print ('loading calibration from redis.\n\n\n') + pdf_calib_md = json.loads(rkvs.get('PDF:xpdacq:pdf_calibration_md')) + #print ('got the following md '+str(pdf_calib_md)) + + #getting exposure time from redis + exposure = float(rkvs.get('PDF:desired_exposure_time').decode('utf-8')) + print ('exposure is '+str(exposure)) + + yield from bps.mv(motor, position) + _md = dict( + Grid_X=Grid_X.read(), + Grid_Y=Grid_Y.read(), + Grid_Z=Grid_Z.read(), + Det_1_X=Det_1_X.read(), + Det_1_Y=Det_1_Y.read(), + Det_1_Z=Det_1_Z.read(), + ring_current=ring_current.read(), + BStop1=BStop1.read(), + user_config=user_config, + #this_sample_md = this_sample_md, + calibration_md=pdf_calib_md, + #calibration_md=None, + #calibration_md2=pdf_calib_md, + ) + #print ('\n\nmd is '+str(md)) + #print ('_md is '+str(_md)) + #_md.update(get_metadata_for_sample_number(bt, sample_number)) + _md.update(this_sample_md) + _md.update(md or {}) + #print ('\n\nbut now md is '+str(md)) + #print ('and _md is '+str(_md)) + yield from simple_ct([pe1c], exposure, md=_md) + + + + +def agent_redisAware_count(position: float, *, md=None): + #fixing motor for now + motor = Grid_X + + + #getting the user_config from redis + rkvs = redis.Redis(host="info.pdf.nsls2.bnl.gov", port=6379, db=0) # redis key value store + p_my_config = rkvs.get("PDF:xpdacq:user_config") + user_config = json.loads(p_my_config) #here is the user_config + + #getting the current sample number from redis + sample_number = int(rkvs.get('PDF:xpdacq:sample_number').decode('utf-8')) #here is the sample num + + #gettting sample metadata from redis + p_info = rkvs.get('PDF:xpdacq:sample_dict') + all_sample_info = json.loads(p_info) + sample_name = list(all_sample_info)[sample_number] + this_sample_md = all_sample_info[sample_name] #here is the sample metadata from bt + + #getting exposure time from redis + exposure = float(rkvs.get('PDF:desired_exposure_time').decode('utf-8')) + print ('exposure is '+str(exposure)) + + yield from bps.mv(motor, position) + _md = dict( + Grid_X=Grid_X.read(), + Grid_Y=Grid_Y.read(), + Grid_Z=Grid_Z.read(), + Det_1_X=Det_1_X.read(), + Det_1_Y=Det_1_Y.read(), + Det_1_Z=Det_1_Z.read(), + ring_current=ring_current.read(), + BStop1=BStop1.read(), + user_config=user_config, + ) + #_md.update(get_metadata_for_sample_number(bt, sample_number)) + _md.update(this_sample_md) + _md.update(md or {}) + yield from simple_ct([pe1c], exposure, md=_md) + + + +def agent_sample_count(motor, position: float, exposure: float, *, sample_number: int, md=None): + rkvs = redis.Redis(host="info.pdf.nsls2.bnl.gov", port=6379, db=0) # redis key value store + p_my_config = rkvs.get("PDF:xpdacq:user_config") + user_config = json.loads(p_my_config) + yield from bps.mv(motor, position) + _md = dict( + Grid_X=Grid_X.read(), + Grid_Y=Grid_Y.read(), + Grid_Z=Grid_Z.read(), + Det_1_X=Det_1_X.read(), + Det_1_Y=Det_1_Y.read(), + Det_1_Z=Det_1_Z.read(), + ring_current=ring_current.read(), + BStop1=BStop1.read(), + user_config=user_config, + ) + _md.update(get_metadata_for_sample_number(bt, sample_number)) + _md.update(md or {}) + yield from simple_ct([pe1c], exposure, md=_md) + +@bpp.run_decorator(md={}) +def agent_driven_nap(delay: float, *, delay_kwarg: float = 0): + """Ensuring we can auto add 'agent_' plans and use args/kwargs""" + if delay_kwarg: + yield from bps.sleep(delay_kwarg) + else: + yield from bps.sleep(delay) + + +def agent_print_glbl_val(key: str): + """ + Get common global values from a namespace dictionary. + Keys + --- + frame_acq_time : Frame rate acquisition time + dk_window : dark window time + """ + print(glbl[key]) + yield from bps.null() + + +def agent_set_glbl_val(key: str, val: float): + """ + Set common global values from a namespace dictionary. + Keys + --- + frame_acq_time : Frame rate acquisition time + dk_window : dark window time + """ + glbl[key] = val + yield from bps.null() diff --git a/startup/99-webcam_device.py b/startup/99-webcam_device.py index 0d85444..3ac6555 100644 --- a/startup/99-webcam_device.py +++ b/startup/99-webcam_device.py @@ -9,26 +9,46 @@ # https://github.com/bluesky/ophyd/blob/b1d258a36c974013b6e3ac8ee7112ed876b7653a/ophyd/areadetector/filestore_mixins.py#L70-L112 import requests -from PIL import Image, ImageFont, ImageDraw +from PIL import Image, ImageFont, ImageDraw from io import BytesIO def annotate_image(imagefile, text): - bluesky_path_as_list = bluesky.__path__[0].split('/') # crude, but finds current collection folder - font_path = os.path.join('/', *bluesky_path_as_list[:4], 'lib', 'python3.7', 'site-packages', 'matplotlib', 'mpl-data', 'fonts', 'ttf') + bluesky_path_as_list = bluesky.__path__[0].split( + "/" + ) # crude, but finds current collection folder + font_path = os.path.join( + "/", + *bluesky_path_as_list[:4], + "lib", + "python3.7", + "site-packages", + "matplotlib", + "mpl-data", + "fonts", + "ttf", + ) img = Image.open(imagefile) width, height = img.size - draw = ImageDraw.Draw(img, 'RGBA') - draw.rectangle(((0, int(9.5*height/10)), (width, height)), fill=(255,255,255,125)) - font = ImageFont.truetype(font_path + '/DejaVuSans.ttf', 24) - draw.text((int(0.2*width/10), int(9.6*height/10)), text, (0,0,0), font=font) + draw = ImageDraw.Draw(img, "RGBA") + draw.rectangle( + ((0, int(9.5 * height / 10)), (width, height)), fill=(255, 255, 255, 125) + ) + font = ImageFont.truetype(font_path + "/DejaVuSans.ttf", 24) + draw.text( + (int(0.2 * width / 10), int(9.6 * height / 10)), text, (0, 0, 0), font=font + ) img.save(imagefile) + def now(fmt="%Y-%m-%dT%H-%M-%S"): return datetime.datetime.now().strftime(fmt) + + def today(fmt="%Y-%m-%d"): return datetime.datetime.today().strftime(fmt) + class WEBCAM_JPEG_HANDLER: def __init__(self, resource_path): # resource_path is really a template string with a %d in it @@ -38,28 +58,32 @@ def __call__(self, index): filepath = self._template % index return numpy.asarray(Image.open(filepath)) + db.reg.register_handler("BEAMLINE_WEBCAM", WEBCAM_JPEG_HANDLER) + class ExternalFileReference(Signal): """ A pure software signal where a Device can stash a datum_id """ + def __init__(self, *args, shape, **kwargs): super().__init__(*args, **kwargs) self.shape = shape def describe(self): res = super().describe() - res[self.name].update(dict(external="FILESTORE:", dtype="array", shape=self.shape)) + res[self.name].update( + dict(external="FILESTORE:", dtype="array", shape=self.shape) + ) return res class CameraSnapshot(Device): image = Component(ExternalFileReference, value="", kind="normal", shape=[]) - beamline_id = '' - annotation_string = '' - - + beamline_id = "" + annotation_string = "" + def __init__(self, *args, root, bl, url, **kwargs): super().__init__(*args, **kwargs) self._root = root @@ -71,20 +95,31 @@ def __init__(self, *args, root, bl, url, **kwargs): self._url = url def current_folder(self): - #folder = os.path.join('/nsls2', 'data', self._beamline, 'assets', *today.split('-')) - folder = os.path.join('/nsls2', 'data', 'pdf', 'legacy','processed','xpdacq_data','user_data','webcam', *today().split('-')) + # folder = os.path.join('/nsls2', 'data', self._beamline, 'assets', *today.split('-')) + folder = os.path.join( + "/nsls2", + "data", + "pdf", + "legacy", + "processed", + "xpdacq_data", + "user_data", + "webcam", + *today().split("-"), + ) if not os.path.isdir(folder): os.makedirs(folder) return folder - + def stage(self): - #self._rel_path_template = f"path/to/files/{uuid.uuid4()}_%d.ext" + # self._rel_path_template = f"path/to/files/{uuid.uuid4()}_%d.ext" self._rel_path_template = f"{uuid.uuid4()}_%d.jpg" self._root = self.current_folder() resource, self._datum_factory = resource_factory( - self._SPEC, self._root, self._rel_path_template, {}, "posix") - self._asset_docs_cache.append(('resource', resource)) + self._SPEC, self._root, self._rel_path_template, {}, "posix" + ) + self._asset_docs_cache.append(("resource", resource)) self._counter = itertools.count() # Set the filepath return super().stage() @@ -108,18 +143,23 @@ def _capture(self, status, i): # that a file is saved at `filename`. if self._SPEC == "BEAMLINE_WEBCAM": - CAM_PROXIES = {"http": None, "https": None,} - r=requests.get(self._url, proxies=CAM_PROXIES) + CAM_PROXIES = { + "http": None, + "https": None, + } + r = requests.get(self._url, proxies=CAM_PROXIES) im = Image.open(BytesIO(r.content)) - im.save(filename, 'JPEG') - #print(f'w: {im.width} h: {im.height}') + im.save(filename, "JPEG") + # print(f'w: {im.width} h: {im.height}') self.image.shape = (im.height, im.width, 3) - annotation = f'{self.beamline_id} {self.annotation_string} {now()}' + annotation = ( + f"{self.beamline_id} {self.annotation_string} {now()}" + ) annotate_image(filename, annotation) datum = self._datum_factory({"index": i}) - self._asset_docs_cache.append(('datum', datum)) + self._asset_docs_cache.append(("datum", datum)) self.image.set(datum["datum_id"]).wait() except Exception as exc: status.set_exception(exc) @@ -136,11 +176,29 @@ def trigger(self): return status -root = os.path.join('/nsls2', 'data', 'pdf', 'legacy','processed','xpdacq_data','user_data','webcam', *today().split('-')) -cam_outboard = CameraSnapshot(root=root, bl='pdf', url='http://10.66.217.45/axis-cgi/jpg/image.cgi', name='outboard webcam') -cam_outboard.beamline_id = 'PDF (NSLS-II 28ID)' - -cam_downstream = CameraSnapshot(root=root, bl='pdf', url='http://10.66.217.46/axis-cgi/jpg/image.cgi', name='downstream webcam') -cam_downstream.beamline_id = 'PDF (NSLS-II 28ID)' - - +root = os.path.join( + "/nsls2", + "data", + "pdf", + "legacy", + "processed", + "xpdacq_data", + "user_data", + "webcam", + *today().split("-"), +) +cam_outboard = CameraSnapshot( + root=root, + bl="pdf", + url="http://10.66.217.45/axis-cgi/jpg/image.cgi", + name="outboard webcam", +) +cam_outboard.beamline_id = "PDF (NSLS-II 28ID)" + +cam_downstream = CameraSnapshot( + root=root, + bl="pdf", + url="http://10.66.217.46/axis-cgi/jpg/image.cgi", + name="downstream webcam", +) +cam_downstream.beamline_id = "PDF (NSLS-II 28ID)" diff --git a/startup/existing_plans_and_devices.yaml b/startup/existing_plans_and_devices.yaml new file mode 100644 index 0000000..7616510 --- /dev/null +++ b/startup/existing_plans_and_devices.yaml @@ -0,0 +1,4369 @@ +# This file is automatically generated. Edit at your own risk. +existing_devices: + Analyzer: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + AreaDetector: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + AreaDetectorCam: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + AtSetpoint: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + AttributeSignal: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + BStop1: + classname: BeamStop + is_flyable: false + is_movable: false + is_readable: true + module: + BStop2: + classname: BeamStop + is_flyable: false + is_movable: false + is_readable: true + module: + BeamStop: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + CS700TemperatureController: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + CryoStat1: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + CryoStat2: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + CryoStream: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + DerivedSignal: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + Det_1_X: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + Det_1_Y: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + Det_1_Z: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + Det_2_X: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + Det_2_Y: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + Det_2_Z: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + DetectorBase: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + Device: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + ECS: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + ECS_An_th: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + ECS_An_tth: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + ECS_Sam_tth: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + ECS_det1: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + ECS_laser_foil_filter: + classname: ECS + is_flyable: false + is_movable: false + is_readable: true + module: + ECS_sample_environment: + classname: SampleEnvironment + is_flyable: false + is_movable: false + is_readable: true + module: + ECS_tel_guide: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + EpicsMotor: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + EpicsSignal: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + EpicsSignalBase: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + EpicsSignalPositioner: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + EpicsSignalRO: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + EpicsSignalWithRBV: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + Eurotherm: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + FilterBank: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + FilterBankTwoButtonShutter: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + Grid_X: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + Grid_Y: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + Grid_Z: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + HDF5Plugin: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + ImagePlugin: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + Lakeshore336: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + Lakeshore336Channel: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + Lakeshore336Setpoint: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + Linkam: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + LinkamFurnace: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + Magnet: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + Mirror: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + Mirror_VFM: + classname: Mirror + is_flyable: false + is_movable: false + is_readable: true + module: + OCMTable: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + OCM_table: + classname: OCMTable + is_flyable: false + is_movable: false + is_readable: true + module: + OmniaDetector: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + OpticsTableADC: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + PDFFastShutter: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + PDFShutter: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + PVPositioner: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + PVPositionerPC: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + ParnoidEpicsSignal: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + PerkinElmerContinuous1: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + PerkinElmerContinuous2: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + PerkinElmerDetector: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + PerkinElmerMulti1: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + PerkinElmerMulti2: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + PerkinElmerStandard1: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + PerkinElmerStandard2: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + PilatusDetector: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + PilatusDetectorCam: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + PilatusDetectorCamV33: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + PilatusV33: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + ProcessPlugin: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + ProsilicaDetector: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + RGA: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + ROIPlugin: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + RampControl: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + SampleEnvironment: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + SavedImageSignal: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + SideBounceMono: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + Signal: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + Slits: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + SpinnerGoniohead: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + Spinnergo_Ry: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + Spinnergo_X: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + Spinnergo_Y: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + Spinnergo_Z: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + StandardProsilica: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + StandardProsilicaWithTIFF: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + StatsPlugin: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + StatsPluginV33: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + SynSignal: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + TIFFPlugin: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + TIFFPluginEnsuredOff: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + TIFFPluginWithFileStore: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + Tomo_spinner: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + TransformPlugin: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + TwoButtonShutter: + classname: type + is_flyable: false + is_movable: true + is_readable: true + module: builtins + XPDHDF5Plugin: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + XPDPerkinElmer: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + XPDPerkinElmer1: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + XPDPerkinElmer2: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + XPDTIFFPlugin: + classname: type + is_flyable: false + is_movable: false + is_readable: true + module: builtins + XPD_shutter: + classname: PDFFastShutter + is_flyable: false + is_movable: true + is_readable: true + module: + analyzer_goniohead: + classname: Analyzer + is_flyable: false + is_movable: false + is_readable: true + module: + bdm_slits: + classname: Slits + is_flyable: false + is_movable: false + is_readable: true + module: + broadside45_shifter: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + cryostat1: + classname: CryoStat1 + is_flyable: false + is_movable: true + is_readable: true + module: + cryostat2: + classname: CryoStat2 + is_flyable: false + is_movable: true + is_readable: true + module: + cryostream: + classname: CryoStream + is_flyable: false + is_movable: true + is_readable: true + module: + eurotherm: + classname: Eurotherm + is_flyable: false + is_movable: true + is_readable: true + module: + eurovolt: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + fb: + classname: FilterBank + is_flyable: false + is_movable: false + is_readable: true + module: + fb_two_button_shutters: + classname: FilterBankTwoButtonShutter + is_flyable: false + is_movable: false + is_readable: true + module: + fs: + classname: PDFFastShutter + is_flyable: false + is_movable: true + is_readable: true + module: + hotairblower: + classname: Eurotherm + is_flyable: false + is_movable: true + is_readable: true + module: + lakeshore336: + classname: Lakeshore336 + is_flyable: false + is_movable: false + is_readable: true + module: + linkam: + classname: Linkam + is_flyable: false + is_movable: true + is_readable: true + module: + linkam_furnace: + classname: LinkamFurnace + is_flyable: false + is_movable: true + is_readable: true + module: + magnet: + classname: Magnet + is_flyable: false + is_movable: true + is_readable: true + module: + noxbox_x: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + noxbox_y: + classname: EpicsMotor + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + ocm_slits: + classname: Slits + is_flyable: false + is_movable: false + is_readable: true + module: + optics_table_adc: + classname: OpticsTableADC + is_flyable: false + is_movable: false + is_readable: true + module: + pe1: + classname: PerkinElmerStandard1 + is_flyable: false + is_movable: false + is_readable: true + module: + pe1c: + classname: PerkinElmerContinuous1 + is_flyable: false + is_movable: false + is_readable: true + module: + pilatus300: + classname: PilatusV33 + is_flyable: false + is_movable: false + is_readable: true + module: + ramp_control: + classname: RampControl + is_flyable: false + is_movable: false + is_readable: true + module: + rga: + classname: RGA + is_flyable: false + is_movable: false + is_readable: true + module: + ring_current: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + sbm: + classname: SideBounceMono + is_flyable: false + is_movable: false + is_readable: true + module: + sorensen850_manual: + classname: ParnoidEpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: + spinner_goniohead: + classname: SpinnerGoniohead + is_flyable: false + is_movable: false + is_readable: true + module: + wb_slits: + classname: Slits + is_flyable: false + is_movable: false + is_readable: true + module: +existing_plans: + _pdf_count: + name: _pdf_count + parameters: + - annotation: + type: str + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: sample_number + - annotation: + type: float + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exposure_time + - annotation: + type: dict + kind: + name: KEYWORD_ONLY + value: 3 + name: sample_db + - annotation: + type: float + kind: + name: KEYWORD_ONLY + value: 3 + name: z_for_move + - annotation: + type: float + kind: + name: KEYWORD_ONLY + value: 3 + name: z_for_data + - annotation: + type: dict + kind: + name: KEYWORD_ONLY + value: 3 + name: md + - annotation: + type: list + kind: + name: KEYWORD_ONLY + value: 3 + name: dets + - kind: + name: KEYWORD_ONLY + value: 3 + name: beam_stop + - kind: + name: KEYWORD_ONLY + value: 3 + name: detector_motor + - kind: + name: KEYWORD_ONLY + value: 3 + name: sample_x + - kind: + name: KEYWORD_ONLY + value: 3 + name: sample_y + - kind: + name: KEYWORD_ONLY + value: 3 + name: sample_z + - kind: + name: KEYWORD_ONLY + value: 3 + name: bt + properties: + is_generator: true + _xpd_pre_plan: + description: Handle detector exposure time + xpdan required metadata + name: _xpd_pre_plan + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: dets + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exposure + properties: + is_generator: true + abs_set: + description: Set a value. Optionally, wait for it to complete before continuing. + module: bluesky.plan_stubs + name: abs_set + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: obj + - description: passed to obj.set() + kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + description: identifier used by 'wait' + kind: + name: KEYWORD_ONLY + value: 3 + name: group + - default: 'False' + description: 'If True, wait for completion before processing any more messages. + + False by default.' + kind: + name: KEYWORD_ONLY + value: 3 + name: wait + - description: passed to obj.set() + kind: + name: VAR_KEYWORD + value: 4 + name: kwargs + properties: + is_generator: true + acquisition_plan: + description: "This is testing a simple acquisition plan.\nHere we open shutter,\ + \ take an image, close shutter, take a dark then\n stop.\ndets : dets to\ + \ read from\nmotors: motors to take readings from\n (for later use)\nfs :\ + \ the fast shutter\nsample_name : the sample name" + name: acquisition_plan + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: dets + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: motors + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: fs + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: sample_name + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: images_per_set + properties: + is_generator: true + adaptive_scan: + description: Scan over one variable with adaptively tuned step size. + module: bluesky.plans + name: adaptive_scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: data field whose output is the focus of the adaptive tuning + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: target_field + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: motor + - description: starting position of motor + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: start + - description: ending position of motor + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: stop + - description: smallest step for fast-changing regions + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: min_step + - description: largest step for slow-chaning regions + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: max_step + - description: desired fractional change in detector signal between steps + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: target_delta + - description: whether backward steps are allowed -- this is concern with some + motors + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: backstep + - default: '0.8' + description: threshold for going backward and rescanning a region, default is + 0.8 + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: threshold + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + bring_to_temperature: + name: bring_to_temperature + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: power_supply + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: thermo + - kind: + name: KEYWORD_ONLY + value: 3 + name: out_path + properties: + is_generator: true + broadcast_msg: + description: Generate many copies of a message, applying it to a list of devices. + module: bluesky.plan_stubs + name: broadcast_msg + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: command + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: objs + - kind: + name: VAR_POSITIONAL + value: 2 + name: args + - kind: + name: VAR_KEYWORD + value: 4 + name: kwargs + properties: + is_generator: true + caching_repeater: + description: Generate n chained copies of the messages in a plan. + module: bluesky.plan_stubs + name: caching_repeater + parameters: + - description: total number of repetitions; if None, infinite + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: n + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: plan + properties: + is_generator: true + checkpoint: + description: If interrupted, rewind to this point. + module: bluesky.plan_stubs + name: checkpoint + parameters: [] + properties: + is_generator: true + clear_checkpoint: + description: Designate that it is not safe to resume. If interrupted or paused, + abort. + module: bluesky.plan_stubs + name: clear_checkpoint + parameters: [] + properties: + is_generator: true + close_run: + description: Mark the end of the current 'run'. Emit a RunStop document. + module: bluesky.plan_stubs + name: close_run + parameters: + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exit_status + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: reason + properties: + is_generator: true + close_shutter_stub: + description: 'simple function to return a generator that yields messages to + + close the shutter' + module: xpdacq.beamtime + name: close_shutter_stub + parameters: [] + properties: + is_generator: true + collect: + description: Collect data cached by a fly-scanning device and emit documents. + module: bluesky.plan_stubs + name: collect + parameters: + - description: Device with 'kickoff', 'complete', and 'collect' methods + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: obj + - default: 'False' + description: 'If False (default), emit Event documents in one bulk dump. If + True, + + emit events one at time.' + kind: + name: KEYWORD_ONLY + value: 3 + name: stream + - default: 'True' + description: 'If True (default), return the collected Events. If False, return + None. + + Using ``stream=True`` and ``return_payload=False`` together avoids + + accumulating the documents in memory: they are emitted as they are + + collected, and they are not accumulated.' + kind: + name: KEYWORD_ONLY + value: 3 + name: return_payload + properties: + is_generator: true + complete: + description: Tell a flyer, 'stop collecting, whenever you are ready'. + module: bluesky.plan_stubs + name: complete + parameters: + - description: Device with 'kickoff', 'complete', and 'collect' methods + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: obj + - default: None + description: identifier used by 'wait' + kind: + name: KEYWORD_ONLY + value: 3 + name: group + - default: 'False' + description: 'If True, wait for completion before processing any more messages. + + False by default.' + kind: + name: KEYWORD_ONLY + value: 3 + name: wait + - description: passed through to ``obj.complete()`` + kind: + name: VAR_KEYWORD + value: 4 + name: kwargs + properties: + is_generator: true + configure: + description: Change Device configuration and emit an updated Event Descriptor + document. + module: bluesky.plan_stubs + name: configure + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: obj + - description: passed through to ``obj.configure()`` + kind: + name: VAR_POSITIONAL + value: 2 + name: args + - description: passed through to ``obj.configure()`` + kind: + name: VAR_KEYWORD + value: 4 + name: kwargs + properties: + is_generator: true + configure_area_det: + description: Configure an area detector in "continuous mode" + name: configure_area_det + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: det + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exposure + properties: + is_generator: true + count: + description: Take one or more readings from detectors. + module: bluesky.plans + name: count + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - default: '1' + description: 'number of readings to take; default is 1 + + + If None, capture data until canceled' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: num + - default: None + description: Time delay in seconds between successive readings; default is 0. + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: delay + - default: None + description: "hook for customizing action of inner loop (messages per step)\n\ + Expected signature ::\n\n def f(detectors: Iterable[OphydObj]) -> Generator[Msg]:\n\ + \ ..." + kind: + name: KEYWORD_ONLY + value: 3 + name: per_shot + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + count_with_calib: + description: Take one or more readings from detectors with shutter control and + calibration metadata injection. + module: xpdacq.beamtime + name: count_with_calib + parameters: + - annotation: + type: list + description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - annotation: + type: int + default: '1' + description: 'number of readings to take; default is 1 + + + If None, capture data until canceled' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: num + - annotation: + type: float + default: None + description: Time delay in seconds between successive readings; default is 0. + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: delay + - annotation: + type: dict + default: None + description: The calibration data in a dictionary. If not applied, the function + is a normal `bluesky.plans.count`. + kind: + name: KEYWORD_ONLY + value: 3 + name: calibration_md + - annotation: + type: dict + default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + create: + description: Bundle future readings into a new Event document. + module: bluesky.plan_stubs + name: create + parameters: + - default: '''primary''' + description: 'name given to event stream, used to convenient identification + + default is ''primary''' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: name + properties: + is_generator: true + ct: + description: Take one reading from area detector with given exposure time + module: xpdacq.beamtime + name: ct + parameters: + - description: 'list of ''readable'' objects. default to area detector + + linked to xpdAcq.' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: dets + - description: total time of exposrue in seconds + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exposure + properties: + is_generator: true + deferred_pause: + description: Pause at the next checkpoint. + module: bluesky.plan_stubs + name: deferred_pause + parameters: [] + properties: + is_generator: true + drop: + description: Drop a bundle of readings without emitting a completed Event document. + module: bluesky.plan_stubs + name: drop + parameters: [] + properties: + is_generator: true + fly: + description: Perform a fly scan with one or more 'flyers'. + module: bluesky.plans + name: fly + parameters: + - description: objects that support the flyer interface + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: flyers + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + future_count: + description: "Take one or more readings from detectors.\nParameters\n----------\n\ + detectors : list\n list of 'readable' objects\nnum : integer, optional\n\ + \ number of readings to take; default is 1\n If None, capture data until\ + \ canceled\ndelay : iterable or scalar, optional\n Time delay in seconds\ + \ between successive readings; default is 0.\nper_shot : callable, optional\n\ + \ hook for customizing action of inner loop (messages per step)\n Expected\ + \ signature ::\n def f(detectors: Iterable[OphydObj]) -> Generator[Msg]:\n\ + \ ...\nmd : dict, optional\n metadata\nNotes\n-----\nIf ``delay``\ + \ is an iterable, it must have at least ``num - 1`` entries or\nthe plan will\ + \ raise a ``ValueError`` during iteration." + name: future_count + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - default: '1' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: num + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: delay + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: per_shot + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + grid_scan: + description: Scan over a mesh; each motor is on an independent trajectory. + module: bluesky.plans + name: grid_scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + description: 'which axes should be snaked, either ``False`` (do not snake any + axes), + + ``True`` (snake all axes) or a list of axes to snake. "Snaking" an axis + + is defined as following snake-like, winding trajectory instead of a + + simple left-to-right trajectory. The elements of the list are motors + + that are listed in `args`. The list must not contain the slowest + + (first) motor, since it can''t be snaked.' + kind: + name: KEYWORD_ONLY + value: 3 + name: snake_axes + - default: None + description: 'hook for customizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) + + for details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + group_by_sample: + description: Group the sample and plan by sample. Return sample, a list of plans. + module: xpdacq.xpdacq + name: group_by_sample + parameters: + - annotation: + type: list + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: sample + - annotation: + type: list + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: plan + properties: + is_generator: true + inner_product_scan: + module: bluesky.plans + name: inner_product_scan + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: num + - kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + input_plan: + description: Prompt the user for text input. + module: bluesky.plan_stubs + name: input_plan + parameters: + - default: '''''' + description: prompt string, e.g., 'enter user name' or 'enter next position' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: prompt + properties: + is_generator: true + install_suspender: + description: Install a suspender during a plan. + module: bluesky.plan_stubs + name: install_suspender + parameters: + - description: The suspender to install + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: suspender + properties: + is_generator: true + jog: + description: pass total exposure time (in seconds), motor name (i.e. Grid_Y), + start and stop positions for the motor. + name: jog + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exposure_s + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: motor + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: start + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: stop + properties: + is_generator: true + kickoff: + description: Kickoff a fly-scanning device. + module: bluesky.plan_stubs + name: kickoff + parameters: + - description: Device with 'kickoff', 'complete', and 'collect' methods + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: obj + - default: None + description: identifier used by 'wait' + kind: + name: KEYWORD_ONLY + value: 3 + name: group + - default: 'False' + description: 'If True, wait for completion before processing any more messages. + + False by default.' + kind: + name: KEYWORD_ONLY + value: 3 + name: wait + - description: passed through to ``obj.kickoff()`` + kind: + name: VAR_KEYWORD + value: 4 + name: kwargs + properties: + is_generator: true + list_grid_scan: + description: Scan over a mesh; each motor is on an independent trajectory. + module: bluesky.plans + name: list_grid_scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: "patterned like (``motor1, position_list1,``\n ``motor2,\ + \ position_list2,``\n ``motor3, position_list3,``\n \ + \ ``...,``\n ``motorN, position_listN``)\n\nThe first\ + \ motor is the \"slowest\", the outer loop. ``position_list``'s\nare lists\ + \ of positions, all lists must have the same length. Motors\ncan be any 'settable'\ + \ object (motor, temp controller, etc.)." + kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: 'False' + description: 'which axes should be snaked, either ``False`` (do not snake any + axes), + + ``True`` (snake all axes) or a list of axes to snake. "Snaking" an axis + + is defined as following snake-like, winding trajectory instead of a + + simple left-to-right trajectory.The elements of the list are motors + + that are listed in `args`. The list must not contain the slowest + + (first) motor, since it can''t be snaked.' + kind: + name: KEYWORD_ONLY + value: 3 + name: snake_axes + - default: None + description: 'hook for customizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) + + for details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + list_scan: + description: Scan over one or more variables in steps simultaneously (inner product). + module: bluesky.plans + name: list_scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: "For one dimension, ``motor, [point1, point2, ....]``.\nIn general:\n\ + \n.. code-block:: python\n\n motor1, [point1, point2, ...],\n motor2,\ + \ [point1, point2, ...],\n ...,\n motorN, [point1, point2, ...]\n\n\ + Motors can be any 'settable' object (motor, temp controller, etc.)" + kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + description: 'hook for customizing action of inner loop (messages per step) + + Expected signature: + + ``f(detectors, motor, step) -> plan (a generator)``' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + load_sample: + description: For robot. + module: xpdacq.xpdacq + name: load_sample + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: position + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: geometry + properties: + is_generator: true + log_scan: + description: Scan over one variable in log-spaced steps. + module: bluesky.plans + name: log_scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: motor + - description: starting position of motor + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: start + - description: ending position of motor + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: stop + - description: number of steps + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: num + - default: None + description: 'hook for customizing action of inner loop (messages per step) + + Expected signature: ``f(detectors, motor, step)``' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + monitor: + description: Asynchronously monitor for new values and emit Event documents. + module: bluesky.plan_stubs + name: monitor + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: obj + - default: None + description: name of event stream; default is None + kind: + name: KEYWORD_ONLY + value: 3 + name: name + - description: passed through to ``obj.subscribe()`` + kind: + name: VAR_KEYWORD + value: 4 + name: kwargs + properties: + is_generator: true + mov: + description: Move one or more devices to a setpoint. Wait for all to complete. + module: bluesky.plan_stubs + name: mv + parameters: + - description: device1, value1, device2, value2, ... + kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + description: Used to mark these as a unit to be waited on. + kind: + name: KEYWORD_ONLY + value: 3 + name: group + - description: passed to obj.set() + kind: + name: VAR_KEYWORD + value: 4 + name: kwargs + properties: + is_generator: true + move_det: + description: Move the detector to the given (x, y, z) + name: move_det + parameters: + - annotation: + type: float + default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x + - annotation: + type: float + default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y + - annotation: + type: float + default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: z + properties: + is_generator: true + move_per_step: + description: Inner loop of an N-dimensional step scan without any readings + module: bluesky.plan_stubs + name: move_per_step + parameters: + - description: mapping motors to positions in this step + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: step + - description: mapping motors to their last-set positions + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: pos_cache + properties: + is_generator: true + move_sample: + description: Move the detector to the given (x, y, z) + name: move_sample + parameters: + - annotation: + type: float + default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x + - annotation: + type: float + default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y + - annotation: + type: float + default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: z + properties: + is_generator: true + move_to_det_config: + name: move_to_det_config + parameters: + - annotation: + type: str + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: name + properties: + is_generator: true + move_to_sample: + name: move_to_sample + parameters: + - annotation: + type: str + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: name + properties: + is_generator: true + movr: + description: Move one or more devices to a relative setpoint. Wait for all to + complete. + module: bluesky.plan_stubs + name: mvr + parameters: + - description: device1, value1, device2, value2, ... + kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + description: Used to mark these as a unit to be waited on. + kind: + name: KEYWORD_ONLY + value: 3 + name: group + - description: passed to obj.set() + kind: + name: VAR_KEYWORD + value: 4 + name: kwargs + properties: + is_generator: true + mv: + description: Move one or more devices to a setpoint. Wait for all to complete. + module: bluesky.plan_stubs + name: mv + parameters: + - description: device1, value1, device2, value2, ... + kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + description: Used to mark these as a unit to be waited on. + kind: + name: KEYWORD_ONLY + value: 3 + name: group + - description: passed to obj.set() + kind: + name: VAR_KEYWORD + value: 4 + name: kwargs + properties: + is_generator: true + mvr: + description: Move one or more devices to a relative setpoint. Wait for all to + complete. + module: bluesky.plan_stubs + name: mvr + parameters: + - description: device1, value1, device2, value2, ... + kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + description: Used to mark these as a unit to be waited on. + kind: + name: KEYWORD_ONLY + value: 3 + name: group + - description: passed to obj.set() + kind: + name: VAR_KEYWORD + value: 4 + name: kwargs + properties: + is_generator: true + 'null': + description: Yield a no-op Message. (Primarily for debugging and testing.) + module: bluesky.plan_stubs + name: 'null' + parameters: [] + properties: + is_generator: true + open_run: + description: Mark the beginning of a new 'run'. Emit a RunStart document. + module: bluesky.plan_stubs + name: open_run + parameters: + - default: None + description: metadata + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: md + properties: + is_generator: true + open_shutter_stub: + description: 'simple function to return a generator that yields messages to + + open the shutter' + module: xpdacq.beamtime + name: open_shutter_stub + parameters: [] + properties: + is_generator: true + outer_product_scan: + description: Scan over a mesh; each motor is on an independent trajectory. + module: bluesky.plans + name: grid_scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + description: 'which axes should be snaked, either ``False`` (do not snake any + axes), + + ``True`` (snake all axes) or a list of axes to snake. "Snaking" an axis + + is defined as following snake-like, winding trajectory instead of a + + simple left-to-right trajectory. The elements of the list are motors + + that are listed in `args`. The list must not contain the slowest + + (first) motor, since it can''t be snaked.' + kind: + name: KEYWORD_ONLY + value: 3 + name: snake_axes + - default: None + description: 'hook for customizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) + + for details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + pause: + description: Pause and wait for the user to resume. + module: bluesky.plan_stubs + name: pause + parameters: [] + properties: + is_generator: true + pchain: + description: Like `itertools.chain` but using `yield from` + module: bluesky.preprocessors + name: pchain + parameters: + - description: generators (plans) + kind: + name: VAR_POSITIONAL + value: 2 + name: args + properties: + is_generator: true + pdf_count: + name: pdf_count + parameters: + - annotation: + type: int + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: sample_number + - annotation: + type: float + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exposure_time + - annotation: + type: dict + default: '{}' + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + periodic_dark: + description: a plan wrapper that takes a plan and inserts `take_dark` + module: xpdacq.xpdacq + name: periodic_dark + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: plan + properties: + is_generator: true + power_calibration_ramp: + name: power_calibration_ramp + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: power_levels + - kind: + name: KEYWORD_ONLY + value: 3 + name: hold_time + - default: '10' + kind: + name: KEYWORD_ONLY + value: 3 + name: n_per_hold + - kind: + name: KEYWORD_ONLY + value: 3 + name: path + properties: + is_generator: true + power_ramp: + name: power_ramp + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: start + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: stop + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: steps + - kind: + name: KEYWORD_ONLY + value: 3 + name: exposure + - default: '0' + kind: + name: KEYWORD_ONLY + value: 3 + name: settle_time + - default: '1' + kind: + name: KEYWORD_ONLY + value: 3 + name: n_per_hold + - kind: + name: VAR_KEYWORD + value: 4 + name: kwargs + properties: + is_generator: true + power_ramp_T_threshold: + description: Plan to take externally controlled temperature ramps. + name: power_ramp_T_threshold + parameters: + - kind: + name: KEYWORD_ONLY + value: 3 + name: start_power_pct + - kind: + name: KEYWORD_ONLY + value: 3 + name: max_temperature + - kind: + name: KEYWORD_ONLY + value: 3 + name: delta_power + - kind: + name: KEYWORD_ONLY + value: 3 + name: max_power_pct + - annotation: + type: float + description: Exposure time in seconds for each shot + kind: + name: KEYWORD_ONLY + value: 3 + name: exposure + - default: '1' + description: The number of exposures to take at each power step + kind: + name: KEYWORD_ONLY + value: 3 + name: n_per_step + - description: Used to get the sample meta-data + kind: + name: KEYWORD_ONLY + value: 3 + name: beamtime + - annotation: + type: str + description: Looked up in beamtime to get sample meta-data + kind: + name: KEYWORD_ONLY + value: 3 + name: xrd_sample_name + - annotation: + type: str + kind: + name: KEYWORD_ONLY + value: 3 + name: pdf_sample_name + - description: 'The location of the beamstop and detector for "near" (PDF) and + "far" (XRD) + + measurements' + kind: + name: KEYWORD_ONLY + value: 3 + name: near_positions + - description: 'The location of the beamstop and detector for "near" (PDF) and + "far" (XRD) + + measurements' + kind: + name: KEYWORD_ONLY + value: 3 + name: far_positions + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: diagostic_T_file + properties: + is_generator: true + power_ramp_controlled: + description: Plan to take externally controlled temperature ramps. + name: power_ramp_controlled + parameters: + - annotation: + type: float + default: '0' + description: The minimum power (as a perentage) to give the heater + kind: + name: KEYWORD_ONLY + value: 3 + name: min_power_pct + - annotation: + type: float + default: '1' + description: The maxmimum power (as a percentage) to give the heater + kind: + name: KEYWORD_ONLY + value: 3 + name: max_power_pct + - annotation: + type: float + description: Exposure time in seconds for each shot + kind: + name: KEYWORD_ONLY + value: 3 + name: exposure + - default: '1' + description: The number of exposures to take at each power step + kind: + name: KEYWORD_ONLY + value: 3 + name: n_per_step + - description: Used to get the sample meta-data + kind: + name: KEYWORD_ONLY + value: 3 + name: beamtime + - annotation: + type: str + description: Looked up in beamtime to get sample meta-data + kind: + name: KEYWORD_ONLY + value: 3 + name: xrd_sample_name + - annotation: + type: str + kind: + name: KEYWORD_ONLY + value: 3 + name: pdf_sample_name + - description: 'The location of the beamstop and detector for "near" (PDF) and + "far" (XRD) + + measurements' + kind: + name: KEYWORD_ONLY + value: 3 + name: near_positions + - description: 'The location of the beamstop and detector for "near" (PDF) and + "far" (XRD) + + measurements' + kind: + name: KEYWORD_ONLY + value: 3 + name: far_positions + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: diagostic_T_file + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: ramp_uid + properties: + is_generator: true + power_ramp_sequence: + description: Plan to take externally controlled temperature ramps. + name: power_ramp_sequence + parameters: + - kind: + name: KEYWORD_ONLY + value: 3 + name: power_pct_seq + - annotation: + type: float + description: Exposure time in seconds for each shot + kind: + name: KEYWORD_ONLY + value: 3 + name: exposure + - default: '1' + description: The number of exposures to take at each power step + kind: + name: KEYWORD_ONLY + value: 3 + name: n_per_step + - description: Used to get the sample meta-data + kind: + name: KEYWORD_ONLY + value: 3 + name: beamtime + - annotation: + type: str + description: Looked up in beamtime to get sample meta-data + kind: + name: KEYWORD_ONLY + value: 3 + name: xrd_sample_name + - annotation: + type: str + kind: + name: KEYWORD_ONLY + value: 3 + name: pdf_sample_name + - description: 'The location of the beamstop and detector for "near" (PDF) and + "far" (XRD) + + measurements' + kind: + name: KEYWORD_ONLY + value: 3 + name: near_positions + - description: 'The location of the beamstop and detector for "near" (PDF) and + "far" (XRD) + + measurements' + kind: + name: KEYWORD_ONLY + value: 3 + name: far_positions + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: diagostic_T_file + properties: + is_generator: true + print_summary_wrapper: + description: Print summary of plan as it goes by + module: bluesky.preprocessors + name: print_summary_wrapper + parameters: + - description: Must yield `Msg` objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: plan + properties: + is_generator: true + ramp_plan: + description: Take data while ramping one or more positioners. + module: bluesky.plans + name: ramp_plan + parameters: + - description: 'plan to start the ramp. This will be run inside of a open/close + + run. + + + This plan must return a `ophyd.StatusBase` object.' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: go_plan + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: monitor_sig + - description: 'generator which takes no input + + + This will be called for every data point. This should create + + one or more events.' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: inner_plan_func + - default: 'True' + description: If True, add a pre data at beginning + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: take_pre_data + - default: None + description: 'If not None, the maximum time the ramp can run. + + + In seconds' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: timeout + - default: None + description: '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.' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: period + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: md + properties: + is_generator: true + rd: + description: Reads a single-value non-triggered object + module: bluesky.plan_stubs + name: rd + parameters: + - description: The device to be read + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: obj + - default: '0' + description: "The value to return when not running in a \"live\" RunEngine.\n\ + This come ups when ::\n\n ret = yield Msg('read', obj)\n assert ret is\ + \ None\n\nthe plan is passed to `list` or some other iterator that\nrepeatedly\ + \ sends `None` into the plan to advance the\ngenerator." + kind: + name: KEYWORD_ONLY + value: 3 + name: default_value + properties: + is_generator: true + read: + description: Take a reading and add it to the current bundle of readings. + module: bluesky.plan_stubs + name: read + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: obj + properties: + is_generator: true + rel_adaptive_scan: + description: Relative scan over one variable with adaptively tuned step size. + module: bluesky.plans + name: rel_adaptive_scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: data field whose output is the focus of the adaptive tuning + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: target_field + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: motor + - description: starting position of motor + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: start + - description: ending position of motor + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: stop + - description: smallest step for fast-changing regions + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: min_step + - description: largest step for slow-chaning regions + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: max_step + - description: desired fractional change in detector signal between steps + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: target_delta + - description: whether backward steps are allowed -- this is concern with some + motors + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: backstep + - default: '0.8' + description: threshold for going backward and rescanning a region, default is + 0.8 + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: threshold + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + rel_grid_scan: + description: Scan over a mesh relative to current position. + module: bluesky.plans + name: rel_grid_scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + description: 'which axes should be snaked, either ``False`` (do not snake any + axes), + + ``True`` (snake all axes) or a list of axes to snake. "Snaking" an axis + + is defined as following snake-like, winding trajectory instead of a + + simple left-to-right trajectory. The elements of the list are motors + + that are listed in `args`. The list must not contain the slowest + + (first) motor, since it can''t be snaked.' + kind: + name: KEYWORD_ONLY + value: 3 + name: snake_axes + - default: None + description: 'hook for customizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) + + for details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + rel_list_grid_scan: + description: 'Scan over a mesh; each motor is on an independent trajectory. Each + point is + + relative to the current position.' + module: bluesky.plans + name: rel_list_grid_scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: "patterned like (``motor1, position_list1,``\n ``motor2,\ + \ position_list2,``\n ``motor3, position_list3,``\n \ + \ ``...,``\n ``motorN, position_listN``)\n\nThe first\ + \ motor is the \"slowest\", the outer loop. ``position_list``'s\nare lists\ + \ of positions, all lists must have the same length. Motors\ncan be any 'settable'\ + \ object (motor, temp controller, etc.)." + kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: 'False' + description: 'which axes should be snaked, either ``False`` (do not snake any + axes), + + ``True`` (snake all axes) or a list of axes to snake. "Snaking" an axis + + is defined as following snake-like, winding trajectory instead of a + + simple left-to-right trajectory.The elements of the list are motors + + that are listed in `args`. The list must not contain the slowest + + (first) motor, since it can''t be snaked.' + kind: + name: KEYWORD_ONLY + value: 3 + name: snake_axes + - default: None + description: 'hook for customizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) + + for details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + rel_list_scan: + description: Scan over one variable in steps relative to current position. + module: bluesky.plans + name: rel_list_scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: "For one dimension, ``motor, [point1, point2, ....]``.\nIn general:\n\ + \n.. code-block:: python\n\n motor1, [point1, point2, ...],\n motor2,\ + \ [point1, point2, ...],\n ...,\n motorN, [point1, point2, ...]\n\n\ + Motors can be any 'settable' object (motor, temp controller, etc.)\npoint1,\ + \ point2 etc are relative to the current location." + kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + description: 'hook for customizing action of inner loop (messages per step) + + Expected signature: ``f(detectors, motor, step)``' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + rel_log_scan: + description: Scan over one variable in log-spaced steps relative to current position. + module: bluesky.plans + name: rel_log_scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: motor + - description: starting position of motor + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: start + - description: ending position of motor + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: stop + - description: number of steps + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: num + - default: None + description: 'hook for customizing action of inner loop (messages per step) + + Expected signature: ``f(detectors, motor, step)``' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + rel_scan: + description: Scan over one multi-motor trajectory relative to current position. + module: bluesky.plans + name: rel_scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: "For one dimension, ``motor, start, stop``.\nIn general:\n\n..\ + \ code-block:: python\n\n motor1, start1, stop1,\n motor2, start2, start2,\n\ + \ ...,\n motorN, startN, stopN,\n\nMotors can be any 'settable' object\ + \ (motor, temp controller, etc.)" + kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + description: number of points + kind: + name: KEYWORD_ONLY + value: 3 + name: num + - default: None + description: 'hook for customizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) + + for details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + rel_set: + description: Set a value relative to current value. Optionally, wait before continuing. + module: bluesky.plan_stubs + name: rel_set + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: obj + - description: passed to obj.set() + kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + description: identifier used by 'wait'; None by default + kind: + name: KEYWORD_ONLY + value: 3 + name: group + - default: 'False' + description: 'If True, wait for completion before processing any more messages. + + False by default.' + kind: + name: KEYWORD_ONLY + value: 3 + name: wait + - description: passed to obj.set() + kind: + name: VAR_KEYWORD + value: 4 + name: kwargs + properties: + is_generator: true + rel_spiral: + description: Relative spiral scan + module: bluesky.plans + name: rel_spiral + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_motor + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_motor + - description: x width of spiral + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_range + - description: y width of spiral + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_range + - description: Delta radius along the minor axis of the ellipse. + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: dr + - description: Number of theta steps + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: nth + - default: None + description: 'Delta radius along the major axis of the ellipse. If None, it + + defaults to dr.' + kind: + name: KEYWORD_ONLY + value: 3 + name: dr_y + - default: '0.0' + description: Tilt angle in radians, default 0.0 + kind: + name: KEYWORD_ONLY + value: 3 + name: tilt + - default: None + description: 'hook for customizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) + + for details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + rel_spiral_fermat: + description: Relative fermat spiral scan + module: bluesky.plans + name: rel_spiral_fermat + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_motor + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_motor + - description: x width of spiral + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_range + - description: y width of spiral + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_range + - description: delta radius + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: dr + - description: radius gets divided by this + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: factor + - default: None + description: 'Delta radius along the major axis of the ellipse, if not specifed + + defaults to dr' + kind: + name: KEYWORD_ONLY + value: 3 + name: dr_y + - default: '0.0' + description: Tilt angle in radians, default 0.0 + kind: + name: KEYWORD_ONLY + value: 3 + name: tilt + - default: None + description: 'hook for customizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) + + for details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + rel_spiral_square: + description: Relative square spiral scan, centered around current (x, y) position. + module: bluesky.plans + name: rel_spiral_square + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_motor + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_motor + - description: x width of spiral + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_range + - description: y width of spiral + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_range + - description: number of x axis points + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_num + - description: Number of y axis points. + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_num + - default: None + description: 'hook for cutomizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plans.one_nd_step` (the default) for + + details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + relative_adaptive_scan: + description: Relative scan over one variable with adaptively tuned step size. + module: bluesky.plans + name: rel_adaptive_scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: data field whose output is the focus of the adaptive tuning + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: target_field + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: motor + - description: starting position of motor + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: start + - description: ending position of motor + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: stop + - description: smallest step for fast-changing regions + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: min_step + - description: largest step for slow-chaning regions + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: max_step + - description: desired fractional change in detector signal between steps + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: target_delta + - description: whether backward steps are allowed -- this is concern with some + motors + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: backstep + - default: '0.8' + description: threshold for going backward and rescanning a region, default is + 0.8 + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: threshold + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + relative_inner_product_scan: + module: bluesky.plans + name: relative_inner_product_scan + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: num + - kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + relative_list_scan: + description: Scan over one variable in steps relative to current position. + module: bluesky.plans + name: rel_list_scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: "For one dimension, ``motor, [point1, point2, ....]``.\nIn general:\n\ + \n.. code-block:: python\n\n motor1, [point1, point2, ...],\n motor2,\ + \ [point1, point2, ...],\n ...,\n motorN, [point1, point2, ...]\n\n\ + Motors can be any 'settable' object (motor, temp controller, etc.)\npoint1,\ + \ point2 etc are relative to the current location." + kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + description: 'hook for customizing action of inner loop (messages per step) + + Expected signature: ``f(detectors, motor, step)``' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + relative_log_scan: + description: Scan over one variable in log-spaced steps relative to current position. + module: bluesky.plans + name: rel_log_scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: motor + - description: starting position of motor + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: start + - description: ending position of motor + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: stop + - description: number of steps + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: num + - default: None + description: 'hook for customizing action of inner loop (messages per step) + + Expected signature: ``f(detectors, motor, step)``' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + relative_outer_product_scan: + description: Scan over a mesh relative to current position. + module: bluesky.plans + name: rel_grid_scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + description: 'which axes should be snaked, either ``False`` (do not snake any + axes), + + ``True`` (snake all axes) or a list of axes to snake. "Snaking" an axis + + is defined as following snake-like, winding trajectory instead of a + + simple left-to-right trajectory. The elements of the list are motors + + that are listed in `args`. The list must not contain the slowest + + (first) motor, since it can''t be snaked.' + kind: + name: KEYWORD_ONLY + value: 3 + name: snake_axes + - default: None + description: 'hook for customizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) + + for details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + relative_scan: + description: Scan over one multi-motor trajectory relative to current position. + module: bluesky.plans + name: rel_scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: "For one dimension, ``motor, start, stop``.\nIn general:\n\n..\ + \ code-block:: python\n\n motor1, start1, stop1,\n motor2, start2, start2,\n\ + \ ...,\n motorN, startN, stopN,\n\nMotors can be any 'settable' object\ + \ (motor, temp controller, etc.)" + kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + description: number of points + kind: + name: KEYWORD_ONLY + value: 3 + name: num + - default: None + description: 'hook for customizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) + + for details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + relative_spiral: + description: Relative spiral scan + module: bluesky.plans + name: rel_spiral + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_motor + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_motor + - description: x width of spiral + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_range + - description: y width of spiral + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_range + - description: Delta radius along the minor axis of the ellipse. + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: dr + - description: Number of theta steps + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: nth + - default: None + description: 'Delta radius along the major axis of the ellipse. If None, it + + defaults to dr.' + kind: + name: KEYWORD_ONLY + value: 3 + name: dr_y + - default: '0.0' + description: Tilt angle in radians, default 0.0 + kind: + name: KEYWORD_ONLY + value: 3 + name: tilt + - default: None + description: 'hook for customizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) + + for details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + relative_spiral_fermat: + description: Relative fermat spiral scan + module: bluesky.plans + name: rel_spiral_fermat + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_motor + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_motor + - description: x width of spiral + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_range + - description: y width of spiral + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_range + - description: delta radius + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: dr + - description: radius gets divided by this + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: factor + - default: None + description: 'Delta radius along the major axis of the ellipse, if not specifed + + defaults to dr' + kind: + name: KEYWORD_ONLY + value: 3 + name: dr_y + - default: '0.0' + description: Tilt angle in radians, default 0.0 + kind: + name: KEYWORD_ONLY + value: 3 + name: tilt + - default: None + description: 'hook for customizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) + + for details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + remove_suspender: + description: Remove a suspender during a plan. + module: bluesky.plan_stubs + name: remove_suspender + parameters: + - description: The suspender to remove + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: suspender + properties: + is_generator: true + repeat: + description: Repeat a plan num times with delay and checkpoint between each repeat. + module: bluesky.plan_stubs + name: repeat + parameters: + - description: Callable that returns an iterable of Msg objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: plan + - default: '1' + description: 'number of readings to take; default is 1 + + + If None, capture data until canceled' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: num + - default: None + description: time delay between successive readings; default is 0 + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: delay + properties: + is_generator: true + repeater: + description: Generate n chained copies of the messages from gen_func + module: bluesky.plan_stubs + name: repeater + parameters: + - description: total number of repetitions; if None, infinite + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: n + - description: returns generator instance + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: gen_func + - kind: + name: VAR_POSITIONAL + value: 2 + name: args + - kind: + name: VAR_KEYWORD + value: 4 + name: kwargs + properties: + is_generator: true + robot_wrapper: + description: "Wrap a plan in load/unload messages.\nParameters\n----------\nplan\ + \ : a bluesky plan\nsample : dict\n must contain 'position'; optionally also\ + \ 'geometry'\nExample\n-------\n>>> plan = count([pe1c])\n>>> new_plan = robot_wrapper(plan,\ + \ {'position': 1})" + module: xpdacq.xpdacq + name: robot_wrapper + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: plan + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: sample + properties: + is_generator: true + rocking_ct: + description: Take a count while "rocking" the y-position + name: rocking_ct + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: dets + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exposure + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: motor + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: start + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: stop + - default: '1' + kind: + name: KEYWORD_ONLY + value: 3 + name: num + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + sample_aware_count: + description: A wrapper around count that tries to mimic xpdacq. + name: sample_aware_count + parameters: + - annotation: + type: int + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: sample_num + - annotation: + type: float + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exposure + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + save: + description: Close a bundle of readings and emit a completed Event document. + module: bluesky.plan_stubs + name: save + parameters: [] + properties: + is_generator: true + scan: + description: Scan over one multi-motor trajectory. + module: bluesky.plans + name: scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: "For one dimension, ``motor, start, stop``.\nIn general:\n\n..\ + \ code-block:: python\n\n motor1, start1, stop1,\n motor2, start2, start2,\n\ + \ ...,\n motorN, startN, stopN\n\nMotors can be any 'settable' object\ + \ (motor, temp controller, etc.)" + kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + description: number of points + kind: + name: KEYWORD_ONLY + value: 3 + name: num + - default: None + description: 'hook for customizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) + + for details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + scan_nd: + description: Scan over an arbitrary N-dimensional trajectory. + module: bluesky.plans + name: scan_nd + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: cycler.Cycler object mapping movable interfaces to positions + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: cycler + - default: None + description: 'hook for customizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) + + for details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + shutter_step: + description: 'customized step to ensure shutter is open before + + reading at each motor point and close shutter after reading' + module: xpdacq.beamtime + name: shutter_step + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: motor + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: step + properties: + is_generator: true + simple_ct: + description: A minimal wrapper around count that adjusts exposure time. + name: simple_ct + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: dets + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exposure + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + single_gen: + description: Turn a single message into a plan + module: bluesky.utils + name: single_gen + parameters: + - description: a single message + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: msg + properties: + is_generator: true + sleep: + description: Tell the RunEngine to sleep, while asynchronously doing other processing. + module: bluesky.plan_stubs + name: sleep + parameters: + - description: seconds + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: time + properties: + is_generator: true + spiral: + description: Spiral scan, centered around (x_start, y_start) + module: bluesky.plans + name: spiral + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_motor + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_motor + - description: x center + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_start + - description: y center + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_start + - description: x width of spiral + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_range + - description: y width of spiral + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_range + - description: Delta radius along the minor axis of the ellipse. + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: dr + - description: Number of theta steps + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: nth + - default: None + description: 'Delta radius along the major axis of the ellipse. If None, defaults + to + + dr.' + kind: + name: KEYWORD_ONLY + value: 3 + name: dr_y + - default: '0.0' + description: Tilt angle in radians, default 0.0 + kind: + name: KEYWORD_ONLY + value: 3 + name: tilt + - default: None + description: 'hook for customizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) + + for details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + spiral_fermat: + description: Absolute fermat spiral scan, centered around (x_start, y_start) + module: bluesky.plans + name: spiral_fermat + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_motor + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_motor + - description: x center + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_start + - description: y center + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_start + - description: x width of spiral + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_range + - description: y width of spiral + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_range + - description: delta radius + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: dr + - description: radius gets divided by this + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: factor + - default: None + description: 'Delta radius along the major axis of the ellipse, if not specifed + + defaults to dr.' + kind: + name: KEYWORD_ONLY + value: 3 + name: dr_y + - default: '0.0' + description: Tilt angle in radians, default 0.0 + kind: + name: KEYWORD_ONLY + value: 3 + name: tilt + - default: None + description: 'hook for customizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) + + for details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + spiral_square: + description: Absolute square spiral scan, centered around (x_center, y_center) + module: bluesky.plans + name: spiral_square + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_motor + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_motor + - description: x center + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_center + - description: y center + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_center + - description: x width of spiral + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_range + - description: y width of spiral + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_range + - description: number of x axis points + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: x_num + - description: Number of y axis points. + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: y_num + - default: None + description: 'hook for cutomizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plans.one_nd_step` (the default) for + + details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + stage: + description: '''Stage'' a device (i.e., prepare it for use, ''arm'' it).' + module: bluesky.plan_stubs + name: stage + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: obj + properties: + is_generator: true + stop: + description: Stop a device. + module: bluesky.plan_stubs + name: stop + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: obj + properties: + is_generator: true + subscribe: + description: Subscribe the stream of emitted documents. + module: bluesky.plan_stubs + name: subscribe + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: name + - description: 'Expected signature: ``f(name, doc)`` where ``name`` is one of + the + + strings above (''all, ''start'', ...) and ``doc`` is a dict' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: func + properties: + is_generator: true + take_dark: + description: a plan for taking a single dark frame + module: xpdacq.xpdacq + name: take_dark + parameters: [] + properties: + is_generator: true + temperature_distance_plan: + description: "This is testing a simple acquisition plan.\n Here we open\ + \ shutter, take an image, close shutter, take a dark then\n stop." + name: temperature_distance_plan + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: dets + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: motor + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: fs + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: cryostream + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: sample_name + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: distances + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: temperatures + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: images_per_set + properties: + is_generator: true + trigger: + description: Trigger and acquisition. Optionally, wait for it to complete. + module: bluesky.plan_stubs + name: trigger + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: obj + - default: None + description: identifier used by 'wait'; None by default + kind: + name: KEYWORD_ONLY + value: 3 + name: group + - default: 'False' + description: 'If True, wait for completion before processing any more messages. + + False by default.' + kind: + name: KEYWORD_ONLY + value: 3 + name: wait + properties: + is_generator: true + trigger_and_read: + description: Trigger and read a list of detectors and bundle readings into one + Event. + module: bluesky.plan_stubs + name: trigger_and_read + parameters: + - description: devices to trigger (if they have a trigger method) and then read + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: devices + - default: '''primary''' + description: 'event stream name, a convenient human-friendly identifier; default + + name is ''primary''' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: name + properties: + is_generator: true + tseries: + description: time series scan with area detector. + module: xpdacq.beamtime + name: tseries + parameters: + - description: 'list of ''readable'' objects. default to area detector + + linked to xpdAcq.' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: dets + - description: exposure time at each reading from area detector in seconds + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exposure + - description: delay between two consecutive readings from area detector in seconds + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: delay + - description: total number of readings + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: num + - default: 'True' + description: 'Option on whether delegates shutter control to ``xpdAcq``. If + True, + + following behavior will take place: + + + `` open shutter - collect data - close shutter `` + + + To make shutter stay open during ``tseries`` scan, + + pass ``False`` to this argument. See ``Notes`` below for more + + detailed information.' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: auto_shutter + properties: + is_generator: true + tune_centroid: + description: 'plan: tune a motor to the centroid of signal(motor)' + module: bluesky.plans + name: tune_centroid + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: detector field whose output is to maximize + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: signal + - description: any 'settable' object (motor, temp controller, etc.) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: motor + - description: start of range + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: start + - description: 'end of range, note: start < stop' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: stop + - description: smallest step size to use. + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: min_step + - default: '10' + description: number of points with each traversal, default = 10 + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: num + - default: '3.0' + description: 'used in calculating new range after each pass + + + note: step_factor > 1.0, default = 3' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: step_factor + - default: 'False' + description: if False (default), always scan from start to stop + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: snake + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + tweak: + description: Move and motor and read a detector with an interactive prompt. + module: bluesky.plans + name: tweak + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detector + - description: data field whose output is the focus of the adaptive tuning + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: target_field + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: motor + - description: initial suggestion for step size + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + two_distance_plan: + description: "This is testing a simple acquisition plan.\n Here we open\ + \ shutter, take an image, close shutter, take a dark then\n stop.\n\ + \ dets : dets to read from\n motor: the motor to move\n \ + \ (for later use)\n fs : the fast shutter\n sample_name :\ + \ the sample name\n\tdistances : list\n\t a list of distances desired" + name: two_distance_plan + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: dets + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: motor + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: fs + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: cryostream + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: sample_name + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: distances + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: images_per_set + properties: + is_generator: true + unload_sample: + description: For robot. + module: xpdacq.xpdacq + name: unload_sample + parameters: [] + properties: + is_generator: true + unmonitor: + description: Stop monitoring. + module: bluesky.plan_stubs + name: unmonitor + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: obj + properties: + is_generator: true + unstage: + description: '''Unstage'' a device (i.e., put it in standby, ''disarm'' it).' + module: bluesky.plan_stubs + name: unstage + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: obj + properties: + is_generator: true + unsubscribe: + description: Remove a subscription. + module: bluesky.plan_stubs + name: unsubscribe + parameters: + - description: token returned by processing a 'subscribe' message + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: token + properties: + is_generator: true + wait: + description: Wait for all statuses in a group to report being finished. + module: bluesky.plan_stubs + name: wait + parameters: + - default: None + description: Identifier given to `abs_set`, `rel_set`, `trigger`; None by default + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: group + properties: + is_generator: true + wait_for: + description: 'Low-level: wait for a list of ``asyncio.Future`` objects to set + (complete).' + module: bluesky.plan_stubs + name: wait_for + parameters: + - description: collection of asyncio.Future objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: futures + - description: passed through to ``asyncio.wait()`` + kind: + name: VAR_KEYWORD + value: 4 + name: kwargs + properties: + is_generator: true + x2x_scan: + description: Relatively scan over two motors in a 2:1 ratio + module: bluesky.plans + name: x2x_scan + parameters: + - description: list of 'readable' objects + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: The second motor will move half as much as the first + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: motor1 + - description: The second motor will move half as much as the first + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: motor2 + - description: 'The relative limits of the first motor. The second motor + + will move between ``start / 2`` and ``stop / 2``' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: start + - description: 'The relative limits of the first motor. The second motor + + will move between ``start / 2`` and ``stop / 2``' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: stop + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: num + - default: None + description: 'hook for cutomizing action of inner loop (messages per step). + + See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) + + for details.' + kind: + name: KEYWORD_ONLY + value: 3 + name: per_step + - default: None + description: metadata + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true diff --git a/startup/monitor_heartbeat_py b/startup/monitor_heartbeat_py index 1387455..2977e7e 100644 --- a/startup/monitor_heartbeat_py +++ b/startup/monitor_heartbeat_py @@ -6,62 +6,65 @@ import os import time ##load local source -#sys.path.insert(1, "./python-slackclient") +# sys.path.insert(1, "./python-slackclient") ##enable logging -#logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) -#client = WebClient() -#api_response = client.api_test() +# client = WebClient() +# api_response = client.api_test() ############## slack_token = os.environ["SLACK_API_TOKEN"] client = WebClient(token=slack_token) + def slack_message(my_message): try: response = client.chat_postMessage( - channel = "pdf_dev", - #channel = user_name, - text = my_message, - ) + channel="pdf_dev", + # channel = user_name, + text=my_message, + ) except SlackApiError as e: assert e.response["something went wrong"] -def check_heartbeat(fname='hbeat.txt', tlapse=300,send_warning=False,notify_user=False): - fin = open(fname,'r') +def check_heartbeat( + fname="hbeat.txt", tlapse=300, send_warning=False, notify_user=False +): + fin = open(fname, "r") tread = float(fin.read()) tpassed = time.time() - tread if tpassed > tlapse: - tpassed_str = str(tpassed/60)[:3] + tpassed_str = str(tpassed / 60)[:3] if send_warning: - msg_to_send = "Issue detected, no pulse in "+tpassed_str+" mins" + msg_to_send = "Issue detected, no pulse in " + tpassed_str + " mins" if notify_user: - msg_to_send = "<@"+str(user_ID)+"> "+msg_to_send + msg_to_send = "<@" + str(user_ID) + "> " + msg_to_send slack_message(msg_to_send) return False return True -def update_heartbeat(fname='hbeat.txt'): - fout = open(fname,'w') +def update_heartbeat(fname="hbeat.txt"): + fout = open(fname, "w") fout.write(str(time.time())) fout.close() ##### -wait_time = 10 #time in seconds between each check -user_ID = 'ULP5FCDDH' +wait_time = 10 # time in seconds between each check +user_ID = "ULP5FCDDH" notify_user = False if len(sys.argv) != 2: - print ('default monitoring - updates required within 5 minute window') + print("default monitoring - updates required within 5 minute window") monitor_window_s = 300 monitor_window_mins = 5 else: monitor_window_mins = float(sys.argv[1]) - print ("Monitoring heartbeat every "+str(monitor_window_mins)+" minutes") + print("Monitoring heartbeat every " + str(monitor_window_mins) + " minutes") monitor_window_s = monitor_window_mins * 60.0 @@ -70,13 +73,12 @@ while go_on: go_on1 = check_heartbeat(tlapse=monitor_window_s) time.sleep(wait_time) - if not go_on1: #wait 1 second, then try again + if not go_on1: # wait 1 second, then try again time.sleep(1) - go_on = check_heartbeat(tlapse=monitor_window_s,send_warning = True, notify_user=True) - -#slack_message("I have lost the heartbeat - last updated over "+str(monitor_window_mins)+" mins ago") - -print ("Ending monitoring process, lost heartbeat") - + go_on = check_heartbeat( + tlapse=monitor_window_s, send_warning=True, notify_user=True + ) +# slack_message("I have lost the heartbeat - last updated over "+str(monitor_window_mins)+" mins ago") +print("Ending monitoring process, lost heartbeat") diff --git a/startup/tmp/97-MA_functions.py b/startup/tmp/97-MA_functions.py index 6c5e6d6..8d28ab7 100644 --- a/startup/tmp/97-MA_functions.py +++ b/startup/tmp/97-MA_functions.py @@ -1,101 +1,113 @@ "Define Beamline Modes" + + def high_resolution(): - print("Resetting white beam slits") - wb_slits.inboard.move(-8.7605) - wb_slits.outboard.move(-5.0251) - - print("Resetting Monochromator") - sbm.yaw.move(-0.00013) - sbm.roll.move(0.000) - sbm.pitch.move(0.07414) - sbm.bend.move(0.0084) - sbm.twist.move(0.0084) - - print("Resetting Mirror") - Mirror_VFM.y_upstream.move(-2.3695) - Mirror_VFM.y_downstream_inboard.move(-1.5492) - Mirror_VFM.y_downstream_outboard.move(-1.2505) - Mirror_VFM.bend_upstream.move(100) - Mirror_VFM.bend_downstream.move(100) - - print("Resetting BDM Slits") - bdm_slits.top.move(0.034) - bdm_slits.bottom.move(-25363.970) - bdm_slits.inboard.move(400.040) - bdm_slits.outboard.move(-4100.075) - - print("Resetting OCM Slits") - ocm_slits.top.move(-2569.894) - ocm_slits.bottom.move(2460.259) - ocm_slits.inboard.move(-844.963) - ocm_slits.outboard.move(454.959) - OCM_table.upstream_jack.move(4.70035) - OCM_table.downstream_jack.move(-4.19820) - OCM_table.X.move(-8.44701) - print("Ready to go !") + print("Resetting white beam slits") + wb_slits.inboard.move(-8.7605) + wb_slits.outboard.move(-5.0251) + + print("Resetting Monochromator") + sbm.yaw.move(-0.00013) + sbm.roll.move(0.000) + sbm.pitch.move(0.07414) + sbm.bend.move(0.0084) + sbm.twist.move(0.0084) + + print("Resetting Mirror") + Mirror_VFM.y_upstream.move(-2.3695) + Mirror_VFM.y_downstream_inboard.move(-1.5492) + Mirror_VFM.y_downstream_outboard.move(-1.2505) + Mirror_VFM.bend_upstream.move(100) + Mirror_VFM.bend_downstream.move(100) + + print("Resetting BDM Slits") + bdm_slits.top.move(0.034) + bdm_slits.bottom.move(-25363.970) + bdm_slits.inboard.move(400.040) + bdm_slits.outboard.move(-4100.075) + + print("Resetting OCM Slits") + ocm_slits.top.move(-2569.894) + ocm_slits.bottom.move(2460.259) + ocm_slits.inboard.move(-844.963) + ocm_slits.outboard.move(454.959) + OCM_table.upstream_jack.move(4.70035) + OCM_table.downstream_jack.move(-4.19820) + OCM_table.X.move(-8.44701) + print("Ready to go !") + def high_flux(): - print("Resetting white beam slits") - wb_slits.inboard.move(-6.7605) - wb_slits.outboard.move(-3.0251) - - print("Resetting Monochromator") - sbm.yaw.move(-0.00013) - sbm.roll.move(0.000) - sbm.pitch.move(-0.02093) - sbm.bend.move(5000.0104) - sbm.twist.move(0.0) - - print("Resetting Mirror") - Mirror_VFM.y_upstream.move(-2.3695) - Mirror_VFM.y_downstream_inboard.move(-1.5492) - Mirror_VFM.y_downstream_outboard.move(-1.2505) - Mirror_VFM.bend_upstream.move(50) - Mirror_VFM.bend_downstream.move(50) - - print("Resetting BDM Slits") - bdm_slits.top.move(0.034) - bdm_slits.bottom.move(-25363.970) - bdm_slits.inboard.move(999.39974) - bdm_slits.outboard.move(-3550.022) - - print("Resetting OCM Slits and Table") - ocm_slits.top.move(-2469.894) - ocm_slits.bottom.move(2585.259) - ocm_slits.inboard.move(-564.909) - ocm_slits.outboard.move(554.960) - OCM_table.upstream_jack.move(4.70035) - OCM_table.downstream_jack.move(-4.19820) - OCM_table.X.move(-8.44701) - print("Ready to go!") + print("Resetting white beam slits") + wb_slits.inboard.move(-6.7605) + wb_slits.outboard.move(-3.0251) + + print("Resetting Monochromator") + sbm.yaw.move(-0.00013) + sbm.roll.move(0.000) + sbm.pitch.move(-0.02093) + sbm.bend.move(5000.0104) + sbm.twist.move(0.0) + + print("Resetting Mirror") + Mirror_VFM.y_upstream.move(-2.3695) + Mirror_VFM.y_downstream_inboard.move(-1.5492) + Mirror_VFM.y_downstream_outboard.move(-1.2505) + Mirror_VFM.bend_upstream.move(50) + Mirror_VFM.bend_downstream.move(50) + + print("Resetting BDM Slits") + bdm_slits.top.move(0.034) + bdm_slits.bottom.move(-25363.970) + bdm_slits.inboard.move(999.39974) + bdm_slits.outboard.move(-3550.022) + + print("Resetting OCM Slits and Table") + ocm_slits.top.move(-2469.894) + ocm_slits.bottom.move(2585.259) + ocm_slits.inboard.move(-564.909) + ocm_slits.outboard.move(554.960) + OCM_table.upstream_jack.move(4.70035) + OCM_table.downstream_jack.move(-4.19820) + OCM_table.X.move(-8.44701) + print("Ready to go!") def BDM_plot(): - from mpl_toolkits.mplot3d import Axes3D - from matplotlib import pylab as pl - from PIL import Image - import numpy as np - import pylab - - img = Image.open('/nsls2/xf28id1/BDM_camera/BDM_ROI_000.tiff').convert('L') - z = np.asarray(img) - mydata = z[500:800:1, 500:800:1] - #mydata = z[164:300:1, 200:1000:1] - fig = pl.figure(facecolor='w') - ax1 = fig.add_subplot(1,2,1) - im = ax1.imshow(z,interpolation='nearest',cmap=pl.cm.jet) - ax1.set_title('2D') - - ax2 = fig.add_subplot(1,2,2,projection='3d') - x,y = np.mgrid[:mydata.shape[0],:mydata.shape[1]] - ax2.plot_surface(x,y,mydata,cmap=pl.cm.jet,rstride=1,cstride=1,linewidth=0.,antialiased=False) - ax2.set_title('3D') - #ax2.set_zlim3d(0,100) - pl.show() - -#def temp() -# Det_1_Z.move(1674.44155) -# Grid_X.move(32) -# Grid_Y.move(41.75) -# Grid_Z.move(830.39405) + from mpl_toolkits.mplot3d import Axes3D + from matplotlib import pylab as pl + from PIL import Image + import numpy as np + import pylab + + img = Image.open("/nsls2/xf28id1/BDM_camera/BDM_ROI_000.tiff").convert("L") + z = np.asarray(img) + mydata = z[500:800:1, 500:800:1] + # mydata = z[164:300:1, 200:1000:1] + fig = pl.figure(facecolor="w") + ax1 = fig.add_subplot(1, 2, 1) + im = ax1.imshow(z, interpolation="nearest", cmap=pl.cm.jet) + ax1.set_title("2D") + + ax2 = fig.add_subplot(1, 2, 2, projection="3d") + x, y = np.mgrid[: mydata.shape[0], : mydata.shape[1]] + ax2.plot_surface( + x, + y, + mydata, + cmap=pl.cm.jet, + rstride=1, + cstride=1, + linewidth=0.0, + antialiased=False, + ) + ax2.set_title("3D") + # ax2.set_zlim3d(0,100) + pl.show() + +# def temp() +# Det_1_Z.move(1674.44155) +# Grid_X.move(32) +# Grid_Y.move(41.75) +# Grid_Z.move(830.39405) diff --git a/startup/user_group_permissions.yaml b/startup/user_group_permissions.yaml new file mode 100644 index 0000000..635c04a --- /dev/null +++ b/startup/user_group_permissions.yaml @@ -0,0 +1,26 @@ +user_groups: + root: # The group includes all available plan and devices + allowed_plans: + - "move_to_sample" + - "move_to_det_config" + - "sample_aware_count" + - "move_det" + - "move_sample" + - "pdf_count" + - "take_a_nap" + - ":^agent_" + forbidden_plans: + - ":^_" # All plans with names starting with '_' + allowed_devices: + - null # Allow all + forbidden_devices: + - ":^_" # All devices with names starting with '_' + admin: # The group includes beamline staff, includes all or most of the plans and devices + allowed_plans: + - ":.*" # A different way to allow all + forbidden_plans: + - null # Nothing is forbidden + allowed_devices: + - ":.*" # A different way to allow all + forbidden_devices: + - null # Nothing is forbidden