diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..60b358d --- /dev/null +++ b/.flake8 @@ -0,0 +1,12 @@ +[flake8] +exclude = + .git, + __pycache__, + build, + dist, + versioneer.py, + pyxrf/_version.py, + docs/conf.py +# There are some errors produced by 'black', therefore unavoidable +ignore = E203, W503 +max-line-length = 115 diff --git a/.gitignore b/.gitignore index ac1e408..272ca6f 100755 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,10 @@ history.sqlite pid security static +*.tgz +backups* +*.remove +*.bak # https://github.com/bluesky/databroker/blob/master/.gitignore diff --git a/profile_/Users/gbischof/dama/profile_collection_pta/startup/README b/profile_/Users/gbischof/dama/profile_collection_pta/startup/README new file mode 100644 index 0000000..61d4700 --- /dev/null +++ b/profile_/Users/gbischof/dama/profile_collection_pta/startup/README @@ -0,0 +1,11 @@ +This is the IPython startup directory + +.py and .ipy files in this directory will be run *prior* to any code or files specified +via the exec_lines or exec_files configurables whenever you load this profile. + +Files will be run in lexicographical order, so you can control the execution order of files +with a prefix, e.g.:: + + 00-first.py + 50-middle.py + 99-last.ipy diff --git a/pyproject.toml b/pyproject.toml index 500d1c7..96e972c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,6 +3,7 @@ line-length = 115 target-version = ['py37'] include = '\.pyi?$' exclude = ''' + ( /( \.eggs # exclude a few common directories in the diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a820d12 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,15 @@ +appdirs==1.4.4 +bluesky==1.10.0 +caproto==1.0.0 +ipython==8.9.0 +lmfit==1.1.0 +msgpack_numpy==0.4.8 +msgpack_python==0.5.6 +nslsii==0.9.0 +ophyd==1.7.0 +pandas==1.5.3 +pyOlog==4.5.0 +pyepics +requests==2.28.2 +scipy==1.10.0 +zict==2.2.0 diff --git a/startup/.cms_config b/startup/.cms_config index c6dd7c4..83fb87e 100644 --- a/startup/.cms_config +++ b/startup/.cms_config @@ -831,101 +831,4 @@ 829,44.45,63.5,5.0,4.0,"[-93.0, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.100025,Wed Feb 1 15:00:18 2023 830,44.45,63.5,5.0,4.0,"[-93.0, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.500038,Wed Feb 1 15:04:18 2023 831,44.45,63.5,5.0,4.0,"[-93.0, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.2,Thu Feb 2 10:22:05 2023 -832,44.45,63.5,5.0,4.0,"[-93.0, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.500016,Mon Feb 6 09:53:04 2023 -833,44.45,63.5,5.0,4.0,"[-93.0, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.700202,Mon Feb 6 13:58:01 2023 -834,44.45,63.5,5.0,4.0,"[-93.0, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.200392,Mon Feb 6 15:37:09 2023 -835,44.45,63.5,5.0,4.0,"[-93.0, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-12.700396,Tue Feb 7 09:46:31 2023 -836,44.45,63.5,5.0,4.0,"[-93.0, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.50046,Wed Feb 8 19:41:57 2023 -837,44.45,63.5,5.0,4.0,"[-93.0, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.793502,Fri Feb 10 09:26:20 2023 -838,44.45,63.5,5.0,4.0,"[-93.0, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.393518,Fri Feb 10 10:21:56 2023 -839,44.45,63.5,5.0,4.0,"[-93.0, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.793637999999998,Thu Feb 16 09:36:12 2023 -840,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-10.091886,Sun Feb 19 21:07:37 2023 -841,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.200134,Sat Feb 25 21:15:58 2023 -842,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.400102,Mon Feb 27 10:33:09 2023 -843,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.100085,Tue Feb 28 10:15:50 2023 -844,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.100084,Tue Feb 28 10:42:33 2023 -845,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.100082,Tue Feb 28 10:48:16 2023 -846,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-12.800081,Tue Feb 28 12:43:48 2023 -847,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-15.499966,Tue Feb 28 18:26:41 2023 -848,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-12.600195,Wed Mar 1 10:50:06 2023 -849,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.100248,Sat Mar 4 23:25:43 2023 -850,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.989959,Sun Mar 5 17:05:53 2023 -851,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-15.9,Thu Mar 9 10:24:22 2023 -852,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.400024,Sat Mar 11 12:21:46 2023 -853,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-12.599998,Sat Mar 11 15:38:00 2023 -854,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-12.700043,Sat Mar 11 15:51:11 2023 -855,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.400088,Sat Mar 11 20:04:17 2023 -856,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.200095,Sat Mar 11 20:13:13 2023 -857,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.300127,Sat Mar 11 20:25:05 2023 -858,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.400129,Sat Mar 11 22:56:50 2023 -859,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.400129,Sat Mar 11 23:04:13 2023 -860,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.300136,Sun Mar 12 22:58:37 2023 -861,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.299993,Mon Mar 13 14:35:54 2023 -862,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.3,Sat Mar 18 11:54:18 2023 -863,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.30002,Fri Mar 24 02:00:22 2023 -864,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-17.000450999999998,Thu Mar 30 10:41:59 2023 -865,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-17.000450999999998,Sat Apr 1 12:14:26 2023 -866,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.700478,Sat Apr 1 16:53:50 2023 -867,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-12.899962,Sun Apr 2 14:21:40 2023 -868,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.199969,Sun Apr 2 18:32:13 2023 -869,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-15.899964,Sun Apr 2 18:32:20 2023 -870,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.700117,Mon Apr 3 09:27:29 2023 -871,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.70001,Thu May 4 10:01:58 2023 -872,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.100002,Mon May 8 16:22:52 2023 -873,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.100238,Mon May 8 19:32:22 2023 -874,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.099999,Thu May 11 15:40:07 2023 -875,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.65016,Tue May 16 11:14:37 2023 -876,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.300197999999998,Tue May 16 19:50:30 2023 -877,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.600251,Tue May 16 19:56:17 2023 -878,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.100173,Wed May 17 10:27:21 2023 -879,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.699994,Mon May 29 10:58:34 2023 -880,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.682055,Mon May 29 16:09:16 2023 -881,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.382132,Thu Jun 1 11:10:42 2023 -882,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.700038,Sun Jun 4 16:24:16 2023 -883,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.700148,Tue Jun 6 10:54:16 2023 -884,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-10.700148,Tue Jun 6 17:15:05 2023 -885,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.700365,Tue Jun 6 17:16:31 2023 -886,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-10.300193,Tue Jun 6 19:39:06 2023 -887,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.900418,Thu Jun 8 17:05:46 2023 -888,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-10.300216,Thu Jun 8 21:24:27 2023 -889,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.600092,Fri Jun 16 18:19:07 2023 -890,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.800134,Fri Jun 16 20:22:34 2023 -891,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-10.400193,Sun Jun 18 17:42:23 2023 -892,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.795003,Mon Jun 19 09:01:46 2023 -893,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.700215999999998,Fri Jun 23 18:28:02 2023 -894,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-17.300283,Sat Jun 24 10:18:45 2023 -895,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.80007,Sat Jun 24 14:09:01 2023 -896,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.800071,Sat Jun 24 14:11:20 2023 -897,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-17.300348,Sun Jun 25 12:48:24 2023 -898,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-17.600392,Sun Jun 25 12:51:12 2023 -899,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.871565,Thu Jun 29 21:02:25 2023 -900,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-17.30043,Mon Jul 3 11:28:03 2023 -901,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.90025,Mon Jul 3 17:40:12 2023 -902,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-10.90025,Tue Jul 4 22:05:54 2023 -903,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-10.300213,Tue Jul 4 22:47:19 2023 -904,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.500228,Wed Jul 5 00:11:48 2023 -905,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-9.899939,Thu Jul 6 12:33:52 2023 -906,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-18.395097,Sat Jul 8 11:32:16 2023 -907,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-18.338224,Sat Jul 8 11:38:40 2023 -908,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-14.5,Mon Jul 10 16:46:55 2023 -909,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-15.000001,Mon Jul 10 16:57:21 2023 -910,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-18.379008,Sat Jul 15 17:22:16 2023 -911,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-17.079439,Mon Jul 17 10:04:46 2023 -912,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-14.079439,Wed Jul 19 08:26:56 2023 -913,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-17.379747,Wed Jul 19 09:38:20 2023 -914,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-17.229717,Wed Jul 19 11:04:45 2023 -915,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.429659,Mon Jul 24 09:40:20 2023 -916,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-15.829637,Mon Jul 24 23:00:28 2023 -917,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.389969,Tue Jul 25 23:22:04 2023 -918,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-16.582884,Thu Aug 3 08:50:55 2023 -919,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-13.200256,Thu Aug 3 10:09:59 2023 -920,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-15.600516,Sat Aug 5 09:59:28 2023 -921,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-18.100697,Mon Aug 7 00:17:53 2023 -922,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-18.0,Mon Sep 11 16:11:00 2023 -923,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-17.500574,Thu Sep 21 09:45:25 2023 -924,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-15.59172,Mon Sep 25 11:14:32 2023 -925,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-18.393962,Tue Sep 26 18:04:17 2023 -926,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-18.200273,Wed Sep 27 11:32:16 2023 -927,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-15.30025,Wed Sep 27 20:39:10 2023 -928,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-18.100334,Thu Sep 28 15:33:18 2023 -929,44.45,63.5,5.0,4.0,"[-91.5, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-18.100334,Thu Sep 28 18:19:22 2023 +832,44.45,63.5,5.0,4.0,"[-93.0, -200.0, -124.5, -1.5]","[0.0, -105.500090625, -91.99959375, 88.0]","[0.0, -104.9, 0.0, 90.0]","[-94.99996875, -105.500090625, -91.99959375, 88.0]","[51.5, -1.87]","[-30.0, -2.37]",,,-12.21,Wed Mar 22 10:05:03 2023 diff --git a/startup/00-startup.py b/startup/00-startup.py index ab4a80e..a0c2479 100644 --- a/startup/00-startup.py +++ b/startup/00-startup.py @@ -1,27 +1,29 @@ -# import logging -# import caproto -# handler = logging.FileHandler('pilatus-trigger-log.txt') -# from caproto._log import LogFormatter, color_log_format, log_date_format -# handler.setFormatter( -# LogFormatter(color_log_format, datefmt=log_date_format)) -# caproto_log = logging.getLogger('caproto') -# caproto_log.handlers.clear() -# caproto_log.addHandler(handler) -# logging.getLogger('caproto.ch').setLevel('DEBUG') -import nslsii - -nslsii.configure_base(get_ipython().user_ns, "cms", publish_documents_with_kafka=True) +print(f"Loading {__file__!r} ...") +import nslsii +import os from bluesky.magics import BlueskyMagics from bluesky.preprocessors import pchain +from bluesky.utils import PersistentDict +from pyOlog.ophyd_tools import * # At the end of every run, verify that files were saved and # print a confirmation message. from bluesky.callbacks.broker import verify_files_saved + +# Added this variable temporarily to bypass some code that doesn't run without the beamline. +# This can be set when starting bsui like this: `BS_MODE=test bsui` + +testing = os.environ.get("BS_MODE", False) == "test" + +if testing: + nslsii.configure_base(get_ipython().user_ns, "temp", publish_documents_with_kafka=False) +else: + nslsii.configure_base(get_ipython().user_ns, "cms", publish_documents_with_kafka=True) + # RE.subscribe(post_run(verify_files_saved), 'stop') -from pyOlog.ophyd_tools import * # Uncomment the following lines to turn on verbose messages for # debugging. @@ -36,169 +38,17 @@ # # RE.subscribe(print_scan_ids, 'start') -# - HACK #1 - patch EpicsSignal.get to retry when timeouts happen stolen from HXN -import ophyd - - -def _epicssignal_get(self, *, as_string=None, connection_timeout=1.0, **kwargs): - """Get the readback value through an explicit call to EPICS - Parameters - ---------- - count : int, optional - Explicitly limit count for array data - as_string : bool, optional - Get a string representation of the value, defaults to as_string - from this signal, optional - as_numpy : bool - Use numpy array as the return type for array data. - timeout : float, optional - maximum time to wait for value to be received. - (default = 0.5 + log10(count) seconds) - use_monitor : bool, optional - to use value from latest monitor callback or to make an - explicit CA call for the value. (default: True) - connection_timeout : float, optional - If not already connected, allow up to `connection_timeout` seconds - for the connection to complete. - """ - if as_string is None: - as_string = self._string - - with self._metadata_lock: - if not self._read_pv.connected: - if not self._read_pv.wait_for_connection(connection_timeout): - raise TimeoutError("Failed to connect to %s" % self._read_pv.pvname) - - ret = None - attempts = 0 - max_attempts = 4 - while ret is None and attempts < max_attempts: - attempts += 1 - ret = self._read_pv.get(as_string=as_string, **kwargs) - if ret is None: - print(f"*** PV GET TIMED OUT {self._read_pv.pvname} *** attempt #{attempts}/{max_attempts}") - if ret is None: - print(f"*** PV GET TIMED OUT {self._read_pv.pvname} *** return `None` as value :(") - # TODO we really want to raise TimeoutError here, but that may cause more - # issues in the codebase than we have the time to fix... - # If this causes issues, remove it to keep the old functionality... - raise TimeoutError("Failed to get %s after %d attempts" % (self._read_pv.pvname, attempts)) - if attempts > 1: - print(f"*** PV GET succeeded {self._read_pv.pvname} on attempt #{attempts}") - - if as_string: - return ophyd.signal.waveform_to_string(ret) - - return ret - - -from ophyd import EpicsSignal -from ophyd import EpicsSignalRO - -# from ophyd import EpicsSignalBase - -from ophyd.areadetector import EpicsSignalWithRBV - -# Increase the timeout for EpicsSignal.get() -# This beamline was occasionally getting ReadTimeoutErrors -# EpicsSignal.set_defaults(timeout=10) -# EpicsSignalRO.set_defaults(timeout=10) -ophyd.signal.EpicsSignalBase.set_defaults(timeout=15) - - -# We have commented this because we would like to identify the PVs that are causing problems. -# Then the controls group can investigate why it is not working as expected. -# Increasing the get() timeout argument is the prefered way to work around this problem. -# EpicsSignal.get = _epicssignal_get -# EpicsSignalRO.get = _epicssignal_get -# EpicsSignalWithRBV.get = _epicssignal_get - -from pathlib import Path - -import appdirs - - -try: - from bluesky.utils import PersistentDict -except ImportError: - import msgpack - import msgpack_numpy - import zict - - class PersistentDict(zict.Func): - """ - A MutableMapping which syncs it contents to disk. - The contents are stored as msgpack-serialized files, with one file per item - in the mapping. - Note that when an item is *mutated* it is not immediately synced: - >>> d['sample'] = {"color": "red"} # immediately synced - >>> d['sample']['shape'] = 'bar' # not immediately synced - but that the full contents are synced to disk when the PersistentDict - instance is garbage collected. - """ - - def __init__(self, directory): - self._directory = directory - self._file = zict.File(directory) - self._cache = {} - super().__init__(self._dump, self._load, self._file) - self.reload() - - # Similar to flush() or _do_update(), but without reference to self - # to avoid circular reference preventing collection. - # NOTE: This still doesn't guarantee call on delete or gc.collect()! - # Explicitly call flush() if immediate write to disk required. - def finalize(zfile, cache, dump): - zfile.update((k, dump(v)) for k, v in cache.items()) - - import weakref - - self._finalizer = weakref.finalize(self, finalize, self._file, self._cache, PersistentDict._dump) - - @property - def directory(self): - return self._directory - - def __setitem__(self, key, value): - self._cache[key] = value - super().__setitem__(key, value) - - def __getitem__(self, key): - return self._cache[key] - - def __delitem__(self, key): - del self._cache[key] - super().__delitem__(key) - - def __repr__(self): - return f"<{self.__class__.__name__} {dict(self)!r}>" - - @staticmethod - 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) - - @staticmethod - def _load(file): - return msgpack.unpackb(file, object_hook=msgpack_numpy.decode, raw=False) - - def flush(self): - """Force a write of the current state to disk""" - for k, v in self.items(): - super().__setitem__(k, v) - - def reload(self): - """Force a reload from disk, overwriting current cache""" - self._cache = dict(super().items()) - - # runengine_metadata_dir = appdirs.user_data_dir(appname="bluesky") / Path("runengine-metadata") -runengine_metadata_dir = "/nsls2/data/cms/shared/config/runengine-metadata" +if testing: + runengine_metadata_dir = "/tmp/runingine-metadata" +else: + runengine_metadata_dir = "/nsls2/data/cms/shared/config/runengine-metadata" + # PersistentDict will create the directory if it does not exist RE.md = PersistentDict(runengine_metadata_dir) -print("a new version of bsui") -print("sth is happening") +# The following plan stubs are automatically imported in global namespace by 'nslsii.configure_base', +# but have signatures that are not compatible with the Queue Server. They should not exist in the global +# namespace, but can be accessed as 'bps.one_1d_step' etc. from other plans. +del one_1d_step, one_nd_step, one_shot diff --git a/startup/01-ad33_tmp.py b/startup/01-ad33_tmp.py index bb98713..55e94fb 100644 --- a/startup/01-ad33_tmp.py +++ b/startup/01-ad33_tmp.py @@ -1,8 +1,6 @@ -from ophyd.areadetector.base import ( - ADComponent as C, - ad_group, - EpicsSignalWithRBV as SignalWithRBV, -) +print(f"Loading {__file__!r} ...") + +from ophyd.areadetector.base import ADComponent as C, ad_group, EpicsSignalWithRBV as SignalWithRBV from ophyd.areadetector.plugins import PluginBase from ophyd.device import DynamicDeviceComponent as DDC, Staged from ophyd.signal import EpicsSignalRO, EpicsSignal @@ -74,26 +72,17 @@ class StatsPluginV33(PluginBase): ) net = C(EpicsSignalRO, "Net_RBV") profile_average = DDC( - ad_group( - EpicsSignalRO, - (("x", "ProfileAverageX_RBV"), ("y", "ProfileAverageY_RBV")), - ), + ad_group(EpicsSignalRO, (("x", "ProfileAverageX_RBV"), ("y", "ProfileAverageY_RBV"))), doc="Profile average in XY", default_read_attrs=("x", "y"), ) profile_centroid = DDC( - ad_group( - EpicsSignalRO, - (("x", "ProfileCentroidX_RBV"), ("y", "ProfileCentroidY_RBV")), - ), + ad_group(EpicsSignalRO, (("x", "ProfileCentroidX_RBV"), ("y", "ProfileCentroidY_RBV"))), doc="Profile centroid in XY", default_read_attrs=("x", "y"), ) profile_cursor = DDC( - ad_group( - EpicsSignalRO, - (("x", "ProfileCursorX_RBV"), ("y", "ProfileCursorY_RBV")), - ), + ad_group(EpicsSignalRO, (("x", "ProfileCursorX_RBV"), ("y", "ProfileCursorY_RBV"))), doc="Profile cursor in XY", default_read_attrs=("x", "y"), ) @@ -103,10 +92,7 @@ class StatsPluginV33(PluginBase): default_read_attrs=("x", "y"), ) profile_threshold = DDC( - ad_group( - EpicsSignalRO, - (("x", "ProfileThresholdX_RBV"), ("y", "ProfileThresholdY_RBV")), - ), + ad_group(EpicsSignalRO, (("x", "ProfileThresholdX_RBV"), ("y", "ProfileThresholdY_RBV"))), doc="Profile threshold in XY", default_read_attrs=("x", "y"), ) diff --git a/startup/10-motors.py b/startup/10-motors.py index 5ba3ae3..a7cc61d 100644 --- a/startup/10-motors.py +++ b/startup/10-motors.py @@ -1,4 +1,7 @@ +print(f"Loading {__file__!r} ...") + from ophyd import EpicsMotor, Device, Component as Cpt +from ophyd.sim import SynAxis # slity = EpicsMotor('XF:11BMA-OP{Slt:0-Ax:T}Mtr', name='slity') @@ -7,10 +10,10 @@ # top = Cpt(EpicsMotor, '-Ax:T}Mtr') # bottom = Cpt(EpicsMotor, '-Ax:B}Mtr') -beamline_stage = "default" +# beamline_stage = 'default' # beamline_stage = 'open_MAXS' -# beamline_stage = 'BigHuber' - +beamline_stage = "BigHuber" +# beamline_stage = 'testing' # slits = Slits('XF:11BMA-OP{Slt:0', name='slits') @@ -113,12 +116,8 @@ class Filter(Device): if beamline_stage == "default": smx = EpicsMotor("XF:11BMB-ES{Chm:Smpl-Ax:X}Mtr", name="smx") smy = EpicsMotor("XF:11BMB-ES{Chm:Smpl-Ax:Z}Mtr", name="smy") - # 2023-Sep-12, change sth and schi back to original setting sth = EpicsMotor("XF:11BMB-ES{Chm:Smpl-Ax:theta}Mtr", name="sth") schi = EpicsMotor("XF:11BMB-ES{Chm:Smpl-Ax:chi}Mtr", name="schi") - # 2023-Jul-29 theta not stable, switch to chi for incident angle - # sth = EpicsMotor('XF:11BMB-ES{Chm:Smpl-Ax:chi}Mtr', name='sth') - # schi = EpicsMotor('XF:11BMB-ES{Chm:Smpl-Ax:theta}Mtr', name='schi') elif beamline_stage == "open_MAXS": smx = EpicsMotor("XF:11BMB-ES{Chm:Smpl2-Ax:X}Mtr", name="smx") @@ -136,25 +135,31 @@ class Filter(Device): sth = EpicsMotor("XF:11BMB-ES{Chm:Smpl3-Ax:theta}Mtr", name="sth") schi = EpicsMotor("XF:11BMB-ES{Chm:Smpl3-Ax:chi}Mtr", name="schi") - # # Newports for PTA - # smx = EpicsMotor('XF:11BMB-ES{PTA:Sample-Ax:X}Mtr', name='smx') - # laserx = EpicsMotor('XF:11BMB-ES{PTA:Laser-Ax:X}Mtr', name='laserx') - # lasery = EpicsMotor('XF:11BMB-ES{PTA:Laser-Ax:Y}Mtr', name='lasery') + # Newports + smx = EpicsMotor("XF:11BMB-ES{PTA:Sample-Ax:X}Mtr", name="smx") + laserx = EpicsMotor("XF:11BMB-ES{PTA:Laser-Ax:X}Mtr", name="laserx") + lasery = EpicsMotor("XF:11BMB-ES{PTA:Laser-Ax:Y}Mtr", name="lasery") - # # GDoerk's spray coater - smx = EpicsMotor("XF:11BMB-ES{Chm:Smpl2-Ax:X}Mtr", name="smx") +elif beamline_stage == "testing": + # Huber + smy = SynAxis(name="smy") + sth = SynAxis(name="sth") + schi = SynAxis(name="schi") + + # Newports + smx = SynAxis(name="smx") + laserx = SynAxis(name="laserx") + lasery = SynAxis(name="lasery") # goniometer smy2 = EpicsMotor("XF:11BMB-ES{Chm:Smpl-Ax:Y}Mtr", name="smy2") sphi = EpicsMotor("XF:11BMB-ES{Chm:Smpl-Ax:phi}Mtr", name="sphi") - - -srot = EpicsMotor("XF:11BMB-ES{SM:1-Ax:Srot}Mtr", name="srot") -strans = EpicsMotor("XF:11BMB-ES{SM:1-Ax:Strans}Mtr", name="strans") -strans2 = EpicsMotor("XF:11BMB-ES{SM:1-Ax:Strans2}Mtr", name="strans2") -stilt = EpicsMotor("XF:11BMB-ES{SM:1-Ax:Stilt}Mtr", name="stilt") -stilt2 = EpicsMotor("XF:11BMB-ES{SM:1-Ax:Stilt2}Mtr", name="stilt2") +# srot = EpicsMotor('XF:11BMB-ES{SM:1-Ax:Srot}Mtr', name='srot') +# strans = EpicsMotor('XF:11BMB-ES{SM:1-Ax:Strans}Mtr', name='strans') +# strans2 = EpicsMotor('XF:11BMB-ES{SM:1-Ax:Strans2}Mtr', name='strans2') +# stilt = EpicsMotor('XF:11BMB-ES{SM:1-Ax:Stilt}Mtr', name='stilt') +# stilt2 = EpicsMotor('XF:11BMB-ES{SM:1-Ax:Stilt2}Mtr', name='stilt2') # the srot is fixed after repair but two module controllers are broken, # strans, strans2, stilt, stilt2 and strot are moved to backup controllers @@ -220,11 +225,6 @@ class Filter(Device): gatex = EpicsMotor("XF:11BMB-ES{Chm:Gate-Ax:X}Mtr", name="gatex") -# For MDrive (X, Y, edited by YZ, 20230920) -mdx = EpicsMotor("XF:11BM-ES{Mdrive-Ax:X}Mtr", name="mdx") -mdy = EpicsMotor("XF:11BM-ES{Mdrive-Ax:Y}Mtr", name="mdy") - - ## easy access for stages def wbs(): print("bsx = {}".format(bsx.position)) diff --git a/startup/11-temperature.py b/startup/11-temperature.py new file mode 100644 index 0000000..10176a5 --- /dev/null +++ b/startup/11-temperature.py @@ -0,0 +1,36 @@ +print(f"Loading {__file__!r} ...") + +from ophyd import PVPositionerPC +from ophyd import FormattedComponent +from ophyd import EpicsSignal, EpicsSignalRO +from ophyd import Component as Cpt + + +class Lakeshore(PVPositionerPC): + """ + Ophyd device for Lakeshore that uses put completion. + PVPositionerPC does not require a done signal like PVPositioner, + instead it uses the setpoint put_completion. + + Example + ------- + lakeshore = Lakeshore('Lakeshore', output="1", chan="A", settle_time=5) + lakeshore.set(100).wait() + This will wait for the ramp to be completed and also wait for + the settle_time. + + lakeshore.get() to see all of the pv values. + """ + + feedback = FormattedComponent(EpicsSignalRO, "{self.prefix}-Chan:{self._chan}}}T:C-I") + output = FormattedComponent(EpicsSignalRO, "{self.prefix}-Out:{self._output}}}Out-I") + setpoint = FormattedComponent(EpicsSignal, "{self.prefix}-Out:{self._output}}}T-SP", put_complete=True) + ramp_rate = FormattedComponent(EpicsSignal, "{self.prefix}-Out:{self._output}}}Val:Ramp-SP") + + def __init__(self, *args, chan, output, **kwargs) -> None: + self._chan = chan + self._output = output + super().__init__(*args, **kwargs) + + +lakeshore = Lakeshore("XF:11BM-ES{Env:01", output="1", chan="A", settle_time=5) diff --git a/startup/12-attenuator.py b/startup/12-attenuator.py new file mode 100644 index 0000000..ebff2cd --- /dev/null +++ b/startup/12-attenuator.py @@ -0,0 +1,165 @@ +""" +This code is ready to be tested. + +Here we create an ArrayDevice for the attentuator. + +This allows us to do: + +attenuator.set([1,0,1]) + +and: + +attenuator.get() will return an array with all of the filter states. +""" + +from enum import Enum +from functools import reduce +from ophyd import Device, DeviceStatus, FormattedComponent, EpicsSignal, EpicsSignalRO, FormattedComponent +from ophyd.device import DynamicDeviceComponent + + +class TernaryDevice(Device): + """ + A general purpose ophyd device with set and reset signals, and a state signal + with 3 posible signals. + """ + + set_cmd = FormattedComponent(EpicsSignal, "{self._set_name}") + reset_cmd = FormattedComponent(EpicsSignal, "{self._reset_name}") + state_rbv = FormattedComponent(EpicsSignalRO, "{self._state_name}", kind="hinted") + + def __init__(self, *args, set_name, reset_name, state_name, state_enum, **kwargs) -> None: + self._state_enum = state_enum + self._set_name = set_name + self._reset_name = reset_name + self._state_name = state_name + self._state = None + super().__init__(*args, **kwargs) + + def set(self, value=True): + if value not in {True, False, 0, 1}: + raise ValueError("value must be one of the following: True, False, 0, 1") + + target_value = bool(value) + + st = DeviceStatus(self) + + # If the device already has the requested state, return a finished status. + if self._state == bool(value): + st._finished() + return st + self._set_st = st + + def state_cb(value, timestamp, **kwargs): + """ + Updates self._state and checks if the status should be marked as finished. + """ + try: + self._state = self._state_enum[value].value + except KeyError: + raise ValueError(f"self._state_enum does not contain value: {value}") + if self._state == target_value: + self._set_st = None + self.state_rbv.clear_sub(state_cb) + st._finished() + + # Subscribe the callback to the readback signal. + # The callback will be called each time the PV value changes. + self.state_rbv.subscribe(state_cb) + + # Write to the signal. + if value: + self.set_cmd.set(1) + else: + self.reset_cmd.set(1) + return st + + def reset(self): + self.set(False) + + def get(self): + return self.state_rbv.get() + + +def ArrayDevice(components, *args, **kwargs): + """ + A function, that behaves like a class init, that dynamically creates an + ArrayDevice class. This is needed to set class attributes before the init. + Adding devices in the init can subvert important ophyd code that + manages sub devices. + """ + + class _ArrayDeviceBase(Device): + """ + An ophyd.Device that is an array of devices. + + The set method takes a list of values. + the get method returns a list of values. + Parameters + ---------- + devices: iterable + The array of ophyd devices. + """ + + def set(self, values): + if len(values) != len(self.component_names): + raise ValueError( + f"The number of values ({len(values)}) must match " + f"the number of devices ({len(self.devices)})" + ) + + # If the device already has the requested state, return a finished status. + diff = [getattr(self, self.devices[i]).get() != value for i, value in enumerate(values)] + if not any(diff): + return DeviceStatus(self)._finished() + + # Set the value of each device and return a union of the statuses. + statuses = [getattr(self, self.devices[i]).set(value) for i, value in enumerate(values)] + st = reduce(lambda a, b: a & b, statuses) + return st + + def get(self): + return [getattr(self, device).get() for device in self.devices] + + # types = {component.cls for component in components} + # if len(types) != 1: + # raise TypeError("All components must have the same type") + + clsdict = OrderedDict( + { + **{"__doc__": "ArrayDevice", "_default_read_attrs": None, "_default_configuration_attrs": None}, + **components, + "devices": list(components.keys()), + } + ) + + _ArrayDevice = type("ArrayDevice", (_ArrayDeviceBase,), clsdict) + return _ArrayDevice(*args, **kwargs) + + +class CmsEnum(Enum): + In = True + Out = False + Unknown = None + + +class CmsFilter(TernaryDevice): + """ + This class is an example about how to create a TernaryDevice specialization + for a specific implementation. + """ + + def __init__(self, index, *args, **kwargs): + super().__init__( + *args, + set_name=f"XF:11BMB-OP{{Fltr:{index}}}Cmd:Opn-Cmd", + reset_name=f"XF:11BMB-OP{{Fltr:{index}}}Cmd:Cls-Cmd", + state_name=f"XF:11BMB-OP{{Fltr:{index}}}Pos-Sts", + state_enum=CmsEnum, + **kwargs, + ) + + +# TODO: Uncomment these lines when ready to test. +# filters = {f'filter{i}': FormattedComponent(CmsFilter, f"{i}") for i in range(8)} +# attenuator = ArrayDevice(filters, name="attenuator") diff --git a/startup/15-optics-utilities.py b/startup/15-optics-utilities.py index 6f04dc5..ea599c7 100644 --- a/startup/15-optics-utilities.py +++ b/startup/15-optics-utilities.py @@ -1,3 +1,5 @@ +print(f"Loading {__file__!r} ...") + from math import sin, cos, tan, asin, acos, atan, pi ##### mono utilities ##### @@ -7,7 +9,9 @@ def getE(q=0): """Returns E(keV) based on the current mono_bragg position (q=1 for quiet)""" - bragg = (pi / 180.0) * caget("XF:11BMA-OP{Mono:DMM-Ax:Bragg}Mtr.RBV") ## in [rad] + # bragg = (pi/180.)*caget('XF:11BMA-OP{Mono:DMM-Ax:Bragg}Mtr.RBV') ## in [rad] + bragg = np.deg2rad(mono_bragg.position) ## in [rad] + wavelen = 2.0 * dmm_dsp * sin(bragg) ## in [Ang] E = hc_over_e / wavelen if q == 0: @@ -104,9 +108,14 @@ def movr_mir_x(del_mm): def ave_mir_y(): """Returns the average height of the toroidal mirror in [mm]""" - usy = caget("XF:11BMA-OP{Mir:Tor-Ax:YU}Mtr.RBV") - dsyi = caget("XF:11BMA-OP{Mir:Tor-Ax:YDI}Mtr.RBV") - dsyo = caget("XF:11BMA-OP{Mir:Tor-Ax:YDO}Mtr.RBV") + # usy = caget('XF:11BMA-OP{Mir:Tor-Ax:YU}Mtr.RBV') + # dsyi = caget('XF:11BMA-OP{Mir:Tor-Ax:YDI}Mtr.RBV') + # dsyo = caget('XF:11BMA-OP{Mir:Tor-Ax:YDO}Mtr.RBV') + + usy = mir_usy.position + dsyi = mir_dsyi.position + dsyo = mir_dsyi.position + ave_y = 0.5 * (usy + 0.5 * (dsyi + dsyo)) print("Average mirror support height = %.4f mm relative to nominal zero height (1400 mm)" % ave_y) return ave_y diff --git a/startup/19-exp_shutter.py b/startup/19-exp_shutter.py index c373c5c..f638084 100644 --- a/startup/19-exp_shutter.py +++ b/startup/19-exp_shutter.py @@ -1,121 +1,47 @@ +print(f"Loading {__file__!r} ...") + ##### Experimental shutters ##### # updated by RL, 20210901 # These shutters are controlled by sending a TTL pulse via Ecat controller. +from ophyd import Device +from ophyd.status import SubscriptionStatus -trigger_new_pv = EpicsSignal("XF:11BM-ES{Shutter}") -shutter_sts1_pv = EpicsSignal("XF:11BM-ES{Psh_blade1}Pos") -shutter_sts2_pv = EpicsSignal("XF:11BM-ES{Psh_blade2}Pos") - -photonshutter_sts = EpicsSignal("XF:11BMA-PPS{PSh}Sts:FailOpn-Sts") -photonshutter_open = EpicsSignal("XF:11BMA-PPS{PSh}Cmd:Opn-Cmd") -photonshutter_cls = EpicsSignal("XF:11BMA-PPS{PSh}Cmd:Cls-Cmd") +class TwoBladeShutter(Device): + cmd = Cpt(EpicsSignal, "{Shutter}", kind="hinted", string=True) + blade1_pos = Cpt(EpicsSignalRO, "{Psh_blade1}Pos", kind="hinted", string=True) + blade2_pos = Cpt(EpicsSignalRO, "{Psh_blade2}Pos", kind="hinted", string=True) -def shutter_on(verbosity=3): - # ii = 0 - # yield from bps.mv(trigger_new_pv, 1) - # time.sleep(0.1) - while shutter_state(verbosity=0) != 1: - yield from bps.mv(trigger_new_pv, 1) - time.sleep(0.01) - # ii += 1 + def set(self, value): + if value not in {"OPEN", "CLOSE"}: + raise ValueError(f"Value: {value} must be either 'OPEN' or 'CLOSE") + target = value - # print(ii) - if verbosity >= 3: - shutter_state(verbosity=verbosity) + def cb(*, value, **kwargs): + return target == value + st = SubscriptionStatus(self.blade1_pos, cb) & SubscriptionStatus(self.blade2_pos, cb) + self.cmd.set(value) + return st -def shutter_off(verbosity=3): - while shutter_state(verbosity=0) != 0: - yield from bps.mv(trigger_new_pv, 0) - time.sleep(0.01) - - if verbosity >= 3: - shutter_state(verbosity=verbosity) - - -def shutter_state(verbosity=3): - if shutter_sts1_pv.get() == 1 & shutter_sts2_pv.get() == 1: - status = 1 - if verbosity >= 3: - print("Shutter is OPEN.") - else: - status = 0 - if verbosity >= 3: - print("Shutter is CLOSED.") - - return status +two_blade_shutter = TwoBladeShutter("XF:11BM-ES", name="two_blade_shutter") -# old control, abandoned in 2021C3 -# These shutters are controlled by sending a 5V pulse via QEM output on the Delta Tau controller MC06 -# (the same unit that controls slits S5). Both the opening and closing of the shutter are triggered -# by the rise of the pulse. -# -# Note: -# - PV for the QEM output on MC06 is: -# XF:11BMB-CT{MC:06}Asyn.AOUT -# - This PV is located under Slit 5/Asyn --> asynRecord/More... --> asynOctet interface I/O --> ASCII -# - 'M112=1' sets the state to high -# - 'M112=0' sets the state to low -# - 'M111=1' launches the change in state -# - A sleep time of ~2 ms between successive caput commands is needed to get proper response; 1 ms is too short -##### +# photonshutter_sts = EpicsSignal("XF:11BMA-PPS{PSh}Sts:FailOpn-Sts") +# photonshutter_open = EpicsSignal("XF:11BMA-PPS{PSh}Cmd:Opn-Cmd") +# photonshutter_cls = EpicsSignal("XF:11BMA-PPS{PSh}Cmd:Cls-Cmd") -# global xshutter_state -xshutter_state = 0 ## TODO: read the shutter state and set this accordingly - -## Open shutter -def xshutter_trigger(): - sleep_time = 0.005 - caput("XF:11BMB-CT{MC:06}Asyn.AOUT", "M112=1") - sleep(sleep_time) - caput("XF:11BMB-CT{MC:06}Asyn.AOUT", "M111=1") - sleep(sleep_time) - caput("XF:11BMB-CT{MC:06}Asyn.AOUT", "M112=0") - sleep(sleep_time) - caput("XF:11BMB-CT{MC:06}Asyn.AOUT", "M111=1") - - -trigger_pv = EpicsSignal("XF:11BMB-CT{MC:06}Asyn.AOUT") -# shutter_sts1_pv = EpicsSignal('XF:11BMB-OP{PSh:2}Pos:1-Sts') -# shutter_sts2_pv = EpicsSignal('XF:11BMB-OP{PSh:2}Pos:2-Sts') - - -def xshutter_trigger_RE(verbosity=3): - yield from bps.mv(trigger_pv, "M112=1") - yield from bps.mv(trigger_pv, "M111=1") - yield from bps.mv(trigger_pv, "M112=0") - yield from bps.mv(trigger_pv, "M111=1") - if verbosity >= 3: - value = yield from bps.read(shutter_sts_pv.read()) - print(value[shutter_sts_pv.name]["value"]) +def shutter_on(verbosity=3): + yield from bps.mv(two_blade_shutter, "OPEN") -def xshutter(inout, q=0): - global xshutter_state +def shutter_off(verbosity=3): + yield from bps.mv(two_blade_shutter, "CLOSE") - if inout == "o" or inout == "open" or inout == 1: - if xshutter_state == 0: - xshutter_trigger() - xshutter_state = 1 - if q == 0: - print("Experimental shutter opened") - return xshutter_state - elif xshutter_state == 1: - print("Experimental shutter is already open; no changes made") - else: - print("xshutter_state is neither 0 nor 1; no changes made") - if inout == "c" or inout == "close" or inout == 0: - if xshutter_state == 1: - xshutter_trigger() - xshutter_state = 0 - if q == 0: - print("Experimental shutter closed") - return xshutter_state - elif xshutter_state == 0: - print("Experimental shutter is already closed; no changes made") - else: - print("xshutter_state is neither 0 nor 1; no changes made") +def shutter_state(verbosity=3): + result = yield from bps.read(two_blade_shutter) + if result is None: + return 1 + return int(all(sig["value"] == "OPEN" for sig in result.values())) diff --git a/startup/20-area-detectors.py b/startup/20-area-detectors.py index 9c06b7d..d6feb1e 100644 --- a/startup/20-area-detectors.py +++ b/startup/20-area-detectors.py @@ -1,3 +1,5 @@ +print(f"Loading {__file__!r} ...") + # import time as ttime # tea time # from datetime import datetime from ophyd import ( @@ -44,12 +46,16 @@ elif beamline_stage == "default": Pilatus800_on = True Pilatus800_2_on = False +elif beamline_stage == "testing": + Pilatus800_on = True + Pilatus800_2_on = False # Pilatus800_on = True # Pilatus800_2_on = False Pilatus800_2_on = True + class TIFFPluginWithFileStore(TIFFPlugin, FileStoreTIFFIterativeWrite): pass @@ -198,12 +204,7 @@ class PilatusV33(SingleTriggerV33, PilatusDetector): ) def setExposureTime(self, exposure_time, verbosity=3): - yield from mv( - self.cam.acquire_time, - exposure_time, - self.cam.acquire_period, - exposure_time + 0.1, - ) + yield from mv(self.cam.acquire_time, exposure_time, self.cam.acquire_period, exposure_time + 0.1) # caput('XF:11BMB-ES{Det:SAXS}:cam1:AcquireTime', exposure_time) # caput('XF:11BMB-ES{Det:SAXS}:cam1:AcquirePeriod', exposure_time+0.1) @@ -252,12 +253,7 @@ class Pilatus800V33(SingleTriggerV33, PilatusDetector): # root='/') def setExposureTime(self, exposure_time, verbosity=3): - yield from mv( - self.cam.acquire_time, - exposure_time, - self.cam.acquire_period, - exposure_time + 0.1, - ) + yield from mv(self.cam.acquire_time, exposure_time, self.cam.acquire_period, exposure_time + 0.1) # self.cam.acquire_time.put(exposure_time) # self.cam.acquire_period.put(exposure_time+.1) # caput('XF:11BMB-ES{Det:PIL2M}:cam1:AcquireTime', exposure_time) @@ -325,12 +321,7 @@ def setExposureTime(self, exposure_time, verbosity=3): # self.cam.stage_sigs['acquire_time'] = exposure_time # self.cam.stage_sigs['acquire_period'] = exposure_time+.1 - yield from mv( - self.cam.acquire_time, - exposure_time, - self.cam.acquire_period, - exposure_time + 0.1, - ) + yield from mv(self.cam.acquire_time, exposure_time, self.cam.acquire_period, exposure_time + 0.1) # yield from mv(self.cam.acquire_period, exposure_time+0.1) @@ -361,12 +352,7 @@ class Pilatus2MV33(SingleTriggerV33, PilatusDetector): # root='/') def setExposureTime(self, exposure_time, verbosity=3): - yield from mv( - self.cam.acquire_time, - exposure_time, - self.cam.acquire_period, - exposure_time + 0.1, - ) + yield from mv(self.cam.acquire_time, exposure_time, self.cam.acquire_period, exposure_time + 0.1) # self.cam.acquire_time.put(exposure_time) # self.cam.acquire_period.put(exposure_time+.1) # caput('XF:11BMB-ES{Det:PIL2M}:cam1:AcquireTime', exposure_time) @@ -431,7 +417,7 @@ def stage(self): time.sleep(1) fs4 = StandardProsilicaV33("XF:11BMB-BI{FS:4-Cam:1}", name="fs4") time.sleep(1) -fs5 = StandardProsilicaV33("XF:11BMB-BI{FS:Test-Cam:1}", name="fs5") +# fs5 = StandardProsilicaV33('XF:11BMB-BI{FS:Test-Cam:1}', name='fs5') # class StandardsimDetectorV33(SingleTriggerV33, ProsilicaDetector): @@ -460,19 +446,19 @@ def stage(self): all_standard_pros = [fs2, fs3, fs4] -# for camera in all_standard_pros: -# camera.read_attrs = ['stats1', 'stats2','stats3','stats4','stats5'] -# # camera.tiff.read_attrs = [] # leaving just the 'image' -# for stats_name in ['stats1', 'stats2','stats3','stats4','stats5']: -# stats_plugin = getattr(camera, stats_name) -# stats_plugin.read_attrs = ['total'] -# #camera.stage_sigs[stats_plugin.blocking_callbacks] = 1 +for camera in all_standard_pros: + camera.read_attrs = ["stats1", "stats2", "stats3", "stats4", "stats5"] + # camera.tiff.read_attrs = [] # leaving just the 'image' + for stats_name in ["stats1", "stats2", "stats3", "stats4", "stats5"]: + stats_plugin = getattr(camera, stats_name) + stats_plugin.read_attrs = ["total"] + # camera.stage_sigs[stats_plugin.blocking_callbacks] = 1 -# camera.stage_sigs[camera.roi1.blocking_callbacks] = 1 -# camera.stage_sigs[camera.trans1.blocking_callbacks] = 1 -# camera.cam.ensure_nonblocking() + # camera.stage_sigs[camera.roi1.blocking_callbacks] = 1 + # camera.stage_sigs[camera.trans1.blocking_callbacks] = 1 + # camera.cam.ensure_nonblocking() -# camera.stage_sigs[camera.cam.trigger_mode] = 'Fixed Rate' + # camera.stage_sigs[camera.cam.trigger_mode] = 'Fixed Rate' # for camera in [xray_eye1_writing, xray_eye2_writing, xray_eye3_writing]: @@ -601,7 +587,9 @@ def stage(self): stats_plugin = getattr(pilatus2M, stats_name) stats_plugin.read_attrs = ["total"] pilatus2M.cam.ensure_nonblocking() - pilatus2M.tiff.ensure_blocking() + pilatus2M.tiff.ensure_nonblocking() + # pilatus2M.tiff.ensure_blocking() + pilatus2M.stats2.total.kind = "hinted" pilatus2M.stats3.total.kind = "hinted" pilatus2M.stats4.total.kind = "hinted" diff --git a/startup/21-fix-area-detector-ports.py b/startup/21-fix-area-detector-ports.py index 855eae8..d7b6546 100644 --- a/startup/21-fix-area-detector-ports.py +++ b/startup/21-fix-area-detector-ports.py @@ -1,11 +1,15 @@ +print(f"Loading {__file__!r} ...") + # for cam_number, fs in zip([1,2,3,4], [fs1, fs2, fs3, fs4]): -for cam_number, fs in zip([2, 3, 4], [fs2, fs3, fs4]): - G, port_dict = fs.get_asyn_digraph() - cam = port_dict["cam{:02}".format(cam_number)] - for v in port_dict.values(): - try: - if v.nd_array_port.get() == "CAM": - v.nd_array_port.set("cam{:02}".format(cam_number)) - except AttributeError: - pass - fs.validate_asyn_ports() + +if not testing: + for cam_number, fs in zip([2, 3, 4], [fs2, fs3, fs4]): + G, port_dict = fs.get_asyn_digraph() + cam = port_dict["cam{:02}".format(cam_number)] + for v in port_dict.values(): + try: + if v.nd_array_port.get() == "CAM": + v.nd_array_port.set("cam{:02}".format(cam_number)) + except AttributeError: + pass + fs.validate_asyn_ports() diff --git a/startup/22-area-detector-utilities.py b/startup/22-area-detector-utilities.py index 0ea5600..6478af5 100644 --- a/startup/22-area-detector-utilities.py +++ b/startup/22-area-detector-utilities.py @@ -1,3 +1,6 @@ +print(f"Loading {__file__!r} ...") + + def xp_set(seconds): # sleep_time=0.002 # caput('XF:11BMB-ES{Det:SAXS}:cam1:AcquireTime',seconds) diff --git a/startup/23-psccd.py b/startup/23-psccd.py index 4024037..e988c1c 100644 --- a/startup/23-psccd.py +++ b/startup/23-psccd.py @@ -1,3 +1,5 @@ +print(f"Loading {__file__!r} ...") + import time # import select @@ -229,8 +231,7 @@ def detector_measure(self, exposure_time=None, savename="_current", verbosity=3, ): percentage = 100 * (time.time() - start_time) / exposure_time print( - "Exposing {:6.2f} s ({:3.0f}%) \r".format((time.time() - start_time), percentage), - end="", + "Exposing {:6.2f} s ({:3.0f}%) \r".format((time.time() - start_time), percentage), end="" ) time.sleep(poling_period) else: diff --git a/startup/25-scalers.py b/startup/25-scalers.py index 9d42815..38e670e 100644 --- a/startup/25-scalers.py +++ b/startup/25-scalers.py @@ -1,3 +1,5 @@ +print(f"Loading {__file__!r} ...") + import ophyd ##### FOE ##### diff --git a/startup/30-beam-monitors.py b/startup/30-beam-monitors.py index 3823009..d52f288 100644 --- a/startup/30-beam-monitors.py +++ b/startup/30-beam-monitors.py @@ -1,3 +1,5 @@ +print(f"Loading {__file__!r} ...") + ########## FOE ########## diff --git a/startup/33_OmegaTemp.py b/startup/33_OmegaTemp.py new file mode 100644 index 0000000..f300096 --- /dev/null +++ b/startup/33_OmegaTemp.py @@ -0,0 +1,14 @@ +print(f"Loading {__file__!r} ...") + +from epics import caput, caget + + +class OmegaTempCntl78000(Device): + temperature_current = Cpt(EpicsSignal, "{LA:Omega}_T_RBV") + temperature_setpoint = Cpt(EpicsSignal, "{LA:Omega}_SP") + + def setTemperature(self, temperature): + return self.temperature_setpoint.put(temperature) + + +tempCntlOmega = OmegaTempCntl78000("XF:11BM", name="omega") diff --git a/startup/41-endstation-serial-dev.py b/startup/41-endstation-serial-dev.py index 8932828..0dc1a5c 100644 --- a/startup/41-endstation-serial-dev.py +++ b/startup/41-endstation-serial-dev.py @@ -1,3 +1,5 @@ +print(f"Loading {__file__!r} ...") + import time # import select diff --git a/startup/41-endstation-serial-dev.py.bak b/startup/41-endstation-serial-dev.py.bak deleted file mode 100755 index 85d3083..0000000 --- a/startup/41-endstation-serial-dev.py.bak +++ /dev/null @@ -1,538 +0,0 @@ -import time -#import select -import re -from ophyd import Device - - -#class SerialDevice(): - -# def __init__(self, prefix='', *args, read_attrs=None, configuration_attrs=None, -# name='SerialDevice', parent=None, **kwargs): - - #super().__init__(prefix=prefix, *args, read_attrs=read_attrs, configuration_attrs=configuration_attrs, name=name, parent=parent, **kwargs) - - - - - -class Agilent_34970A(Device): - # Note: Command terminator is a newline character \n. - # Note: On serial cable, data transmit/receive pins (pins 2 and 3 on Dsub-9 connector) must be reversed. - # Settings as of 07/25/2017: Baud rate = 19200 bits/s, Stop bits = 1, Parity = None, Flow control = None - # Moxa port 9: socket = 10.11.130.53:4009 - - def __init__(self, prefix='', *args, read_attrs=None, configuration_attrs=None, - name='Agilent_34970A', parent=None, **kwargs): - - super().__init__(prefix=prefix, *args, read_attrs=read_attrs, configuration_attrs=configuration_attrs, name=name, parent=parent, **kwargs) - - #self.port_number = 9 - #self.server_port = 4000 + self.port_number - self.connect_socket() - self.HP34901_channel = 100 # 20 channel multiplexer module card in slot 1 - self.HP34907_channel = 300 # DIO/DAC card in slot 3 - - # Essential socket interaction - ######################################## - - def connect_socket(self): - - #self.server_address= '10.11.130.51' - self.server_address= '10.11.130.53' # Moxa inside Endstation hutch - #self.server_IP = '10.11.129.2' - self.port_number = 9 - self.server_port = 4000 + self.port_number - - import socket - #self.sock = socket.socket() - self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - print(self.server_address) - self.sock.connect((self.server_address, self.server_port)) - - self.sock.settimeout(0.5) - - - def disconnect_socket(self): - - self.sock.close() - - - def send_socket(self, msg): - - #self.sock.send(chr(13).encode('ascii', 'ignore')) # Carriage return - self.sock.send(msg.encode('ascii', 'ignore')) - #self.sock.send(msg.encode('utf-8')) - - - def send_get_reply(self, msg, verbosity=3): - - #self.send_socket('\r') - self.send_socket(msg) - - time.sleep(0.5) - - return self.read_socket(verbosity=verbosity) - - - def read_socket(self, timeout_s=3, verbosity=3): - - start_time = time.time() - terminator = chr(0x18) - - # Look for the response - amount_received = 0 - amount_cutoff = 5000 - - txt = '' - msg_received = '' - - while terminator not in txt and time.time()-start_timetimeout_s: - if verbosity>=1: - print('Read timeout after {:.1f} s.'.format(time.time()-start_time)) - return '' - - else: - if verbosity>=2: - print(msg_received) - return msg_received - - - # Commands for Agilent 34970A unit - ######################################## - - # Reset Agilent 34970A unit to factory default settings. - def reset_Agilent34970A(self, verbosity = 3): - self.send_socket('*RST\n') - - - # Commands for HP34901 20-channel muliplexer module card - ######################################## - - # Reset HP34901 to factory default settings. - def reset_HP34901(self, verbosity = 3): - self.send_socket('SYSTEM:CPON {chan}\n'.format(chan=self.HP34901_channel)) - - - # Read DC voltage on specified channel. - def readDCV(self, channel, verbosity = 1): - if (channel < 1 or channel > 20): - print('Invalid multiplexer channel number; must be 1-20.\n') - return 0 - - read_channel = int(self.HP34901_channel + channel) - self.send_socket('INPUT:IMP:AUTO ON, (@{chan})\n'.format(chan=read_channel)) - self.send_socket('SENSE:ZERO:AUTO ON, (@{chan})\n'.format(chan=read_channel)) - self.send_socket('MEAS:VOLT:DC? AUTO,MAX, (@{chan})\n'.format(chan=read_channel)) - dcv = float(self.read_socket(verbosity=1)) - - if (verbosity > 1): - print('Channel {chan} is {volts} VDC.\n'.format(chan=channel, volts=dcv)) - - return dcv - - - # Commands for HP34907 DIO/DAC card - ######################################## - - # Output specified voltage on specified DAC channel - def setDAC(self, channel, voltage, verbosity = 1): - - if (channel < 1 or channel > 2): - print('Invalid DAC channel number; must be 1 or 2.\n') - return 0 - - if (voltage < -12.0 or voltage > 12.0): - print('Invalid DAC voltage value; must be within +/-12 volts.\n') - return 0 - - dac_channel = int(self.HP34907_channel + channel + 3) - self.send_socket('SOURCE:VOLTAGE {volts}, (@{chan})\n'.format(volts=voltage, chan=dac_channel)) - #self.send_socket('SOURCE:VOLTAGE {volts}, (@{chan})\r'.format(volts=voltage, chan=dac_channel)) - - if (verbosity > 1): - print('DAC output channel {chan} set to {volts} VDC.\n'.format(chan=channel, volts=voltage)) - - return 1 - - - # Query voltage setting on specified DAC channel - def readDAC(self, channel, verbosity = 1): - - if (channel < 1 or channel > 2): - print('Invalid DAC channel number; must be 1 or 2.\n') - return 0 - - dac_channel = int(self.HP34907_channel + channel + 3) - self.send_socket('SOURCE:VOLTAGE? (@{chan})\n'.format(chan=dac_channel)) - voltage = float(self.read_socket(verbosity=1)) - - if (verbosity > 1): - print('DAC output channel {chan} set to {volts} VDC.\n'.format(chan=channel, volts=voltage)) - - return voltage - - - # Write digital byte to specified DIO channel - def writeByteDIO(self, channel, value, verbosity = 1): - - if (channel < 1 or channel > 2): - print('Invalid DIO channel number; must be 1 or 2.\n') - return 0 - - dio_channel = int(self.HP34907_channel + channel) - diovalue = ((value ^ 0xf) & 0xf) - #self.send_socket('SOURCE:DIGITAL:DATA:BYTE {byte}, (@{chan})\n'.format(byte=diovalue, chan=dio_channel)) - self.send_socket('SOURCE:DIGITAL:DATA:BYTE {byte}, (@{chan})\n'.format(byte=value, chan=dio_channel)) - - if (verbosity > 1): - print('DIO output channel {chan} set to {val}.\n'.format(chan=channel, val=value)) - - return 1 - - - # Read digital byte on specified DIO channel - def readByteDIO(self, channel, verbosity = 1): - - if (channel < 1 or channel > 2): - print('Invalid DIO channel number; must be 1 or 2.\n') - return 0 - - dio_channel = int(self.HP34907_channel + channel) - self.send_socket('SOURCE:DIGITAL:DATA:BYTE? (@{chan})\n'.format(chan=dio_channel)) - value = int(self.read_socket(verbosity=1)) - diovalue = ((value ^ 0xf) & 0xf) - - if (verbosity > 1): - print('DIO output channel {chan} set to {val}.\n'.format(chan=channel, val=value)) - - return value - - - -class Keithley_2000(Device): - # Note: Command terminator is a carriage-return character \r. - # Settings as of 07/25/2017: Baud rate = 19200 bits/s, Stop bits = 1, Parity = None, Flow control = None - # Moxa port 10: socket = 10.11.130.53:4010 - - def __init__(self, prefix='', *args, read_attrs=None, configuration_attrs=None, - name='Keithley_2000', parent=None, **kwargs): - - super().__init__(prefix=prefix, *args, read_attrs=read_attrs, configuration_attrs=configuration_attrs, name=name, parent=parent, **kwargs) - - #self.port_number = 10 - #self.server_port = 4000 + self.port_number - self.connect_socket() - - # Essential socket interaction - ######################################## - - def connect_socket(self): - - #self.server_address= '10.11.130.51' - self.server_address= '10.11.130.53' # Moxa inside Endstation hutch - #self.server_IP = '10.11.129.2' - self.port_number = 10 - self.server_port = 4000 + self.port_number - - import socket - #self.sock = socket.socket() - self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - print(self.server_address) - self.sock.connect((self.server_address, self.server_port)) - - self.sock.settimeout(0.5) - - - def disconnect_socket(self): - - self.sock.close() - - - def send_socket(self, msg): - - #self.sock.send(chr(13).encode('ascii', 'ignore')) # Carriage return - self.sock.send(msg.encode('ascii', 'ignore')) - #self.sock.send(msg.encode('utf-8')) - - - def send_get_reply(self, msg, verbosity=3): - - #self.send_socket('\r') - self.send_socket(msg) - - time.sleep(0.5) - - return self.read_socket(verbosity=verbosity) - - - def read_socket(self, timeout_s=3, verbosity=3): - - start_time = time.time() - terminator = chr(0x18) - - # Look for the response - amount_received = 0 - amount_cutoff = 5000 - - txt = '' - msg_received = '' - - while terminator not in txt and time.time()-start_timetimeout_s: - if verbosity>=1: - print('Read timeout after {:.1f} s.'.format(time.time()-start_time)) - return '' - - else: - if verbosity>=2: - print(msg_received) - return msg_received - - - # Select the channel for reading - def selectChannel(self, channel, verbosity = 1): - - if (channel < 1 or channel > 10): - print('Invalid channel number; must be between 1 and 10.\n') - return 0 - - self.send_socket(':ROUT:CLOS (@{chan})\r'.format(chan=channel)) - - if (verbosity > 1): - print('Keithley 2000 channel set to {chan}.\n'.format(chan=channel)) - - return 1 - - - # Read resistance on the selected channel - def readOhm(self, channel, verbosity = 1): - - self.selectChannel(channel, verbosity=1) - time.sleep(0.1) - self.send_socket(':SENS:FUNC \'RES\'\r') - time.sleep(0.1) - self.send_socket(':SENS:DATA?\r') - time.sleep(0.1) - ohm = float(self.read_socket(verbosity=1)) - - if (verbosity > 1): - print('The resistance on channel {chan} is {res} Ohm.\n'.format(chan=channel, res=ohm)) - - return ohm - - - # Read DC voltage on the selected channel - def readDCV(self, channel, verbosity = 1): - - self.selectChannel(channel, verbosity=1) - time.sleep(0.1) - self.send_socket(':SENS:FUNC \'VOLT:DC\'\r') - time.sleep(0.1) - self.send_socket(':SENS:DATA?\r') - time.sleep(0.1) - dcv = float(self.read_socket(verbosity=1)) - - if (verbosity > 1): - print('The DC voltage on channel {chan} is {volts} VDC.\n'.format(chan=channel, volts=dcv)) - - return dcv - - - # Read 30 kOhm thermistor on the selected channel and return T[degC] - def readThermister30kohm(self, channel, verbosity = 1): - - ohm = self.readOhm(channel, verbosity=1) - - coeff_a = 0.000932681 - coeff_b = 0.000221455 - coeff_c = 0.000000126 - - Temp = coeff_a; - Temp += coeff_b * numpy.log(ohm) - Temp += coeff_c * (numpy.log(ohm))**3 - Temp = 1.0/Temp - 273.15 - - if (verbosity > 1): - print('The temperature (30k-ohm thermistor) on channel {chan} is {degC} degC.\n'.format(chan=channel, degC=Temp)) - - return Temp - - - # Read 100 kOhm thermistor on the selected channel and return T[degC] - def readThermister100kohm(self, channel, verbosity = 1): - - ohm = self.readOhm(channel, verbosity=1) - - coeff_a = 0.000827094 - coeff_b = 0.000204256 - coeff_c = 1.15042e-07 - - Temp = coeff_a; - Temp += coeff_b * numpy.log(ohm) - Temp += coeff_c * (numpy.log(ohm))**3 - Temp = 1.0/Temp - 273.15 - - if (verbosity > 1): - print('The temperature (100k-ohm thermistor) on channel {chan} is {degC} degC.\n'.format(chan=channel, degC=Temp)) - - return Temp - - - # Read Pt100 RTD on the selected channel and return T[degC] - def readPt100(self, channel, verbosity = 1): - - ohm = self.readOhm(channel, verbosity=1) - - # Conversion formula from: - # http://www.mosaic-industries.com/embedded-systems/microcontroller-projects/temperature-measurement/platinum-rtd-sensors/resistance-calibration-table - c0 = -245.19 - c1 = 2.5293 - c2 = -0.066046 - c3 = 4.0422e-3 - c4 = -2.0697e-6 - c5 = -0.025422 - c6 = 1.6883e-3 - c7 = -1.3601e-6 - - Temp = ohm * (c1 + ohm * (c2 + ohm * (c3 + c4 * ohm))) - Temp /= 1.0 + ohm * (c5 * ohm * (c6 + c7 * ohm)) - Temp += c0 - - if (verbosity > 1): - print('The temperature (Pt100 RTD) on channel {chan} is {degC} degC.\n'.format(chan=channel, degC=Temp)) - - return Temp - - - -class TTL_control(object): - ''' - Uses the 2 8-bit DIO channels on Agilent34970A - Note: agilent = Agilent_34970A(), unit = Agilent DIO channel number, port 1 = bit 1, etc. - Note: If there is an error reading or setting, try to read/write to Agilent DIO channels directly first, and it should start working. - ''' - - def __init__(self, name='TTL_control', description="", pv=None, **args): - - self.name=name - self.description=description - - - def readPort(self, unit, port, verbosity=2): - - if (unit < 1 or unit > 2): - print('Invalid TTL unit number; must be 1 or 2.\n') - return 0 - - if (port < 1 or port > 8): - print('Invalid TTL port number; must be between 1 and 8.\n') - return 0 - - value = agilent.readByteDIO(unit, verbosity=1) - bit_pos = int(port) - onoff = int(bin(value)[2:].zfill(8)[-bit_pos]) - - if (verbosity > 1): - print('TTL unit {uu} port {pp} is currently set to {oo}.\n'.format(uu=unit, pp=bit_pos, oo=onoff)) - - return onoff - - - def readPorts(self, unit, verbosity=2): - - if (unit < 1 or unit > 2): - print('Invalid TTL unit number; must be 1 or 2.\n') - return 0 - - value = agilent.readByteDIO(unit, verbosity=1) - bits = [] - for i in range(1,8+1): - #b = self.readPort(unit, i, verbosity=verbosity) - b = int(bin(value)[2:].zfill(8)[-i]) - bits.append(b) - - if (verbosity > 1): - print('TTL unit {uu} ports 1-8 are currently set to {ll}.\n'.format(uu=unit, ll=bits)) - - return value - - - def setPort(self, unit, port, onoff, verbosity=2): - - if (unit < 1 or unit > 2): - print('Invalid TTL unit number; must be 1 or 2.\n') - return 0 - - if (port < 1 or port > 8): - print('Invalid TTL port number; must be between 1 and 8.\n') - return 0 - - # check the current setting and don't do anything if already set as requested - b = self.readPort(unit, port, verbosity=1) - if (onoff == b): - if (verbosity > 1): - print('TTL unit {uu} port {pp} is already set to {oo}.\n'.format(uu=unit, pp=port, oo=onoff)) - return 0 - - value = agilent.readByteDIO(unit, verbosity=1) - bit_pos = int(port) - if (onoff == 1): - value += 2**(bit_pos-1) - elif (onoff == 0): - value -= 2**(bit_pos-1) - else: - pass - - agilent.writeByteDIO(unit, value, verbosity=1) - b_new = self.readPort(unit, port, verbosity=1) - if (b_new != onoff): - print('ERROR: TTL unit {uu} port {pp} is still set to {oo}.\n'.format(uu=unit, pp=port, oo=b_new)) - return 0 - else: - if (verbosity > 1): - print('TTL unit {uu} port {pp} has been set to {oo}.\n'.format(uu=unit, pp=port, oo=b_new)) - return 1 - - - def setPortOn(self, unit, port, verbosity=2): - - return self.setPort(unit, port, 1, verbosity=verbosity) - - - def setPortOff(self, unit, port, verbosity=2): - - return self.setPort(unit, port, 0, verbosity=verbosity) - - - - -#agilent = Agilent_34970A() -#keithley = Keithley_2000() -#ttl = TTL_control() - - diff --git a/startup/42-diodebox.py b/startup/42-diodebox.py index 9d61f8f..f929d68 100644 --- a/startup/42-diodebox.py +++ b/startup/42-diodebox.py @@ -1,3 +1,5 @@ +print(f"Loading {__file__!r} ...") + # XF:11BMB-CT{DIODE-Local:3}OutCh00:Data-SP # PV list of Diode box: AO, Analog Output diff --git a/startup/43-endstation-ioLogik.py b/startup/43-endstation-ioLogik.py index 97ef257..f996c25 100644 --- a/startup/43-endstation-ioLogik.py +++ b/startup/43-endstation-ioLogik.py @@ -1,3 +1,5 @@ +print(f"Loading {__file__!r} ...") + import time from ophyd import Device @@ -11,6 +13,8 @@ # MFC: +# 20210907, change the AI/AO/DIO Moxa boxes to Ecat channels. +# add TTL signals, see more in 19_shutter.py # 20210907, change the AI/AO/DIO Moxa boxes to Ecat channels. # add TTL signals, see more in 19_shutter.py @@ -19,6 +23,7 @@ # TTL signals +TTL2 = EpicsSignal("XF:11BM-ES{Ecat:DO1_2}") TTL2 = EpicsSignal("XF:11BM-ES{Ecat:DO1_2}") @@ -173,13 +178,7 @@ def setOff(self, port): print("The port is not valid") def readRH( - self, - AI_chan, - temperature=25.0, - voltage_supply=5.0, - coeff_slope=0.030, - coeff_offset=0.787, - verbosity=3, + self, AI_chan, temperature=25.0, voltage_supply=5.0, coeff_slope=0.030, coeff_offset=0.787, verbosity=3 ): voltage_out = self.read(AI[AI_chan]) corr_voltage_out = voltage_out * (5.0 / voltage_supply) @@ -236,7 +235,7 @@ def readRH( class MassFlowControl(Device): def __init__(self): - self.setDevice() + pass # self.FlowRate_Sts = 'XF:11BMB-ES{FC:1}F-I' # self.FlowRate_SP = 'XF:11BMB-ES{FC:1}F:SP-SP' # self.Mode_Sts = 'XF:11BMB-ES{FC:1}Mode:Opr-Sts' @@ -470,10 +469,7 @@ def setVoltageLinear(self, Vstart, Vend, period, wait_time=0.1, verbosity=3): start_time = time.time() while time.time() - start_time < period + 0.01: - self.put( - self.voltage_setpoint, - Vstart + (Vend - Vstart) * (time.time() - start_time) / period, - ) + self.put(self.voltage_setpoint, Vstart + (Vend - Vstart) * (time.time() - start_time) / period) print(time.time() - start_time) time.sleep(wait_time) diff --git a/startup/44-laserPTA.py b/startup/44-laserPTA.py index d4b50bc..a2f3f79 100644 --- a/startup/44-laserPTA.py +++ b/startup/44-laserPTA.py @@ -1,16 +1,28 @@ +print(f"Loading {__file__!r} ...") + from epics import caput, caget +class NuPhotoThermalAnnealer(Device): + voltage = Cpt(EpicsSignal, "{Ecat:AO1}1") + state = Cpt(EpicsSignal, "{Ecat:DO1_2}") + + +core_laser = NuPhotoThermalAnnealer("XF:11BM-ES", name="laser") + + class PhotoThermalAnnealer: def __init__(self, print_code="PTA> "): # self.controlTTL_PV = 'XF:11BMB-ES{IO}AO:3-SP' - # self.controlTTL_PV = 'XF:11BM-ES{Ecat:DO1_2}' + # self.controlTTL_PV = "XF:11BM-ES{Ecat:DO1_2}" # self.powerV_PV = 'XF:11BMB-ES{IO}AO:4-SP' - # self.powerV_PV = 'XF:11BM-ES{Ecat:AO1}1' + # self.powerV_PV = "XF:11BM-ES{Ecat:AO1}1" + # self.controlTTL_PV = "XF:11BM-ES{Ecat:DO1_2}" - # setting at Feb 2023 - self.powerV_PV = "XF:11BM-ES{Ecat:AO2}1" - self.controlTTL_PV = "XF:11BM-ES{Ecat:DO1_2}" + self.powerV_PV = ( + "XF:11BM-CT{BIOME-MTO:1}LaserVoltsSet:1-SP" # changed at 080323 by RL for the new laser control box + ) + self.controlTTL_PV = "XF:11BM-CT{BIOME-MTO:1}Output:1-Sel" self.print_code = print_code # if verbosity>=3: @@ -226,11 +238,7 @@ def controlTemperature(self, T_target, adjust_strength=0.5, delay_time=0.1, adju if verbosity >= 3: print( "{} T = {:.2f}°C; Adjusting laser power by {:+.2f} W (from {:.2f} W to {:.2f} W)".format( - self.print_code, - T_current, - adjust, - power_W_current, - power_W_current + adjust, + self.print_code, T_current, adjust, power_W_current, power_W_current + adjust ) ) @@ -432,10 +440,7 @@ def double_sweep_laser(self, length, velocity, start=None, delay_at_end=0.1): self.single_sweep_laser(-length, velocity, start=None, delay_at_end=delay_at_end) def anneal_cyclic(self, length, velocity, num_cycles, delay_at_end=0.1): - self.msg( - "Cycling Anneal (%.1fmm X %.1f, @ %.4f mm/s)" % (length, num_cycles, velocity), - 1, - ) + self.msg("Cycling Anneal (%.1fmm X %.1f, @ %.4f mm/s)" % (length, num_cycles, velocity), 1) # Predict how long the anneal will take predicted_duration = ((length / velocity) + delay_at_end) * 2 * num_cycles # Stage motion @@ -444,10 +449,7 @@ def anneal_cyclic(self, length, velocity, num_cycles, delay_at_end=0.1): # finish = time.time() + predicted_duration # date_str = datetime.datetime.fromtimestamp( finish ).strftime("%Y-%m-%d %H:%M:%S") - self.msg( - "Will finish at %s" % (self.timing_prediction_txt(predicted_duration)), - indent=1, - ) + self.msg("Will finish at %s" % (self.timing_prediction_txt(predicted_duration)), indent=1) fractional_sweeps = num_cycles - int(num_cycles) if fractional_sweeps == 0.5: @@ -457,10 +459,7 @@ def anneal_cyclic(self, length, velocity, num_cycles, delay_at_end=0.1): # Anneal cycles for cycle in range(num_cycles): - self.msg( - "Cycle #: %d/%d (%.1f%% done)" % (cycle + 1, num_cycles, (100.0 * cycle / num_cycles)), - 1, - ) + self.msg("Cycle #: %d/%d (%.1f%% done)" % (cycle + 1, num_cycles, (100.0 * cycle / num_cycles)), 1) # self.date_stamp(indent=1) if self.is_timing(): self.timing_msg(indent=1) @@ -486,10 +485,7 @@ def anneal_cyclic_laser( measures=None, cycles_done=0, ): - self.msg( - "Cycling Anneal (%.1fmm X %.1f, @ %.4f mm/s)" % (length, num_cycles, velocity), - 1, - ) + self.msg("Cycling Anneal (%.1fmm X %.1f, @ %.4f mm/s)" % (length, num_cycles, velocity), 1) if measures is None: measures = [1, 2, 4, 8, 16] @@ -509,10 +505,7 @@ def anneal_cyclic_laser( # finish = time.time() + predicted_duration # date_str = datetime.datetime.fromtimestamp( finish ).strftime("%Y-%m-%d %H:%M:%S") - self.msg( - "Will finish at %s" % (self.timing_prediction_txt(predicted_duration)), - indent=1, - ) + self.msg("Will finish at %s" % (self.timing_prediction_txt(predicted_duration)), indent=1) fractional_sweeps = num_cycles - int(num_cycles) if fractional_sweeps == 0.5: @@ -522,10 +515,7 @@ def anneal_cyclic_laser( # Anneal cycles for cycle in range(num_cycles): - self.msg( - "Cycle #: %d/%d (%.1f%% done)" % (cycle + 1, num_cycles, (100.0 * cycle / num_cycles)), - 1, - ) + self.msg("Cycle #: %d/%d (%.1f%% done)" % (cycle + 1, num_cycles, (100.0 * cycle / num_cycles)), 1) # self.date_stamp(indent=1) if self.is_timing(): self.timing_msg(indent=1) @@ -621,12 +611,7 @@ def thermal_gradient_getAlignment(self, position): return 0.0 def thermal_gradient_measure( - self, - exposure_time=10, - power_fractional=1.00, - x_offset=0, - x_step=-0.05, - already_heated=0, + self, exposure_time=10, power_fractional=1.00, x_offset=0, x_step=-0.05, already_heated=0 ): testing = False diff --git a/startup/45-olog.py b/startup/45-olog.py index eb088e0..ea2e9ad 100644 --- a/startup/45-olog.py +++ b/startup/45-olog.py @@ -1,3 +1,5 @@ +print(f"Loading {__file__!r} ...") + # simple_template = """{{- start.plan_name }} ['{{ start.uid[:6] }}'] (scan num: {{ start.scan_id }})""" diff --git a/startup/50-bluesky-devices.py b/startup/50-bluesky-devices.py index 67511b9..1d86dcf 100644 --- a/startup/50-bluesky-devices.py +++ b/startup/50-bluesky-devices.py @@ -1,3 +1,5 @@ +print(f"Loading {__file__!r} ...") + from nslsii.devices import TwoButtonShutter diff --git a/startup/51-linkam-stages.py b/startup/51-linkam-stages.py index 1154c06..626aa1e 100644 --- a/startup/51-linkam-stages.py +++ b/startup/51-linkam-stages.py @@ -1,3 +1,5 @@ +print(f"Loading {__file__!r} ...") + # EPICS interface developed by Jakub # Bsui code adopted from BMM/Bruce Ravel and modified by Ruipeng Li @@ -489,9 +491,9 @@ def states(self): # setting for the tensile part text += f"\nCurrent mode = {self.getMode(verbosity=5)}\n\n" - text += f"\nCurrent distance = {self.distance.get():1f}, setpoint={self.distance_setposition.get():1f}\n\n" - text += f"\nCurrent velocity = {self.velocity.get():1f}, setpoint={self.velocity_setposition.get():1f}\n\n" - text += f"\nCurrent force = {self.force.get():1f}, setpoint={self.force_setposition.get():1f}\n\n" + text += f"\nCurrent distance = {self.distance.get():1f}, setpoint={self.distance_setpoi.get():1f}\n\n" + text += f"\nCurrent velocity = {self.velocity.get():1f}, setpoint={self.velocity_setpoi.get():1f}\n\n" + text += f"\nCurrent force = {self.force.get():1f}, setpoint={self.force_setpoi.get():1f}\n\n" # force = Cpt(EpicsSignal, 'TST_FORCE_SETPOINT') # distance = Cpt(EpicsSignal, 'TST_MTR_DIST_SP') #relative distance diff --git a/startup/55-archiver.py b/startup/55-archiver.py index 618ecbc..45de8e9 100644 --- a/startup/55-archiver.py +++ b/startup/55-archiver.py @@ -1,3 +1,5 @@ +print(f"Loading {__file__!r} ...") + # adopted from CHX # imports for accessing data from channel archiver @@ -14,8 +16,7 @@ def __init__(self): self.arvconf = ArchiverConfig(self.bpl_url) self.cf_update = "/cf-update/" self.pvfinder = PVFinder(self.cf_update) - self.ar_url = "http://epics-services-cms.nsls2.bnl.local:11168" - # self.ar_url = 'http://epics-services-cms:11168' + self.ar_url = "http://epics-services-cms.nsls2.bnl.local:11165" self.ar_tz = "US/Eastern" self.config = {"url": self.ar_url, "timezone": self.ar_tz} self.arvReader = ArchiverReader(self.config) @@ -25,7 +26,7 @@ def __init__(self): self.PVs_name_default = [] self.PV_dict_default = dict() - def setStage(self, stage="LinkamTensile"): + def setStage(self, stage): if stage == "LinkamTensile": self.PVs_default = [ "XF:11BM-ES:{LINKAM}:TEMP", diff --git a/startup/81-beam.py b/startup/81-beam.py index d873904..5b5bb28 100644 --- a/startup/81-beam.py +++ b/startup/81-beam.py @@ -2,6 +2,11 @@ # -*- coding: utf-8 -*- # vi: ts=4 sw=4 +print(f"Loading {__file__!r} ...") + +import bluesky.plan_stubs as bps +from epics import caput, caget + ################################################################################ # Code for querying and controlling beamline components that 'affect' the @@ -78,16 +83,11 @@ def setCalibration(self, direct_beam, distance, detector_position=None, pixel_si self.pixel_size = pixel_size def get_md(self, prefix="detector_SAXS_", **md): - ###TODO: change all ROI settings without caget. - md_return = self.md.copy() x0, y0 = self.direct_beam position_defined_x, position_defined_y = self.detector_position - position_current_x, position_current_y = ( - SAXSx.user_readback.value, - SAXSy.user_readback.value, - ) + position_current_x, position_current_y = SAXSx.user_readback.value, SAXSy.user_readback.value md_return["name"] = self.detector.name md_return["epics_name"] = "{Det:PIL2M}" @@ -97,60 +97,24 @@ def get_md(self, prefix="detector_SAXS_", **md): md_return["distance_m"] = self.distance - # md_return['ROI1_X_min'] = caget('XF:11BMB-ES{}:ROI1:MinX'.format(pilatus_Epicsname)) - # md_return['ROI1_X_size'] = caget('XF:11BMB-ES{}:ROI1:SizeX'.format(pilatus_Epicsname)) - # md_return['ROI1_Y_min'] = caget('XF:11BMB-ES{}:ROI1:MinY'.format(pilatus_Epicsname)) - # md_return['ROI1_Y_size'] = caget('XF:11BMB-ES{}:ROI1:SizeY'.format(pilatus_Epicsname)) - - # md_return['ROI2_X_min'] = caget('XF:11BMB-ES{}:ROI2:MinX'.format(pilatus_Epicsname)) - # md_return['ROI2_X_size'] = caget('XF:11BMB-ES{}:ROI2:SizeX'.format(pilatus_Epicsname)) - # md_return['ROI2_Y_min'] = caget('XF:11BMB-ES{}:ROI2:MinY'.format(pilatus_Epicsname)) - # md_return['ROI2_Y_size'] = caget('XF:11BMB-ES{}:ROI2:SizeY'.format(pilatus_Epicsname)) - - # md_return['ROI3_X_min'] = caget('XF:11BMB-ES{}:ROI3:MinX'.format(pilatus_Epicsname)) - # md_return['ROI3_X_size'] = caget('XF:11BMB-ES{}:ROI3:SizeX'.format(pilatus_Epicsname)) - # md_return['ROI3_Y_min'] = caget('XF:11BMB-ES{}:ROI3:MinY'.format(pilatus_Epicsname)) - # md_return['ROI3_Y_size'] = caget('XF:11BMB-ES{}:ROI3:SizeY'.format(pilatus_Epicsname)) - - # md_return['ROI4_X_min'] = caget('XF:11BMB-ES{}:ROI4:MinX'.format(pilatus_Epicsname)) - # md_return['ROI4_X_size'] = caget('XF:11BMB-ES{}:ROI4:SizeX'.format(pilatus_Epicsname)) - # md_return['ROI4_Y_min'] = caget('XF:11BMB-ES{}:ROI4:MinY'.format(pilatus_Epicsname)) - # md_return['ROI4_Y_size'] = caget('XF:11BMB-ES{}:ROI4:SizeY'.format(pilatus_Epicsname)) - - md_return["ROI1_X_min"] = pilatus_name.roi1.min_xyz.get().min_x - md_return["ROI1_X_size"] = pilatus_name.roi1.size.get().x - md_return["ROI1_Y_min"] = pilatus_name.roi1.min_xyz.get().min_y - md_return["ROI1_Y_size"] = pilatus_name.roi1.size.get().y - - md_return["ROI2_X_min"] = pilatus_name.roi2.min_xyz.get().min_x - md_return["ROI2_X_size"] = pilatus_name.roi2.size.get().x - md_return["ROI2_Y_min"] = pilatus_name.roi2.min_xyz.get().min_y - md_return["ROI2_Y_size"] = pilatus_name.roi2.size.get().y - - md_return["ROI3_X_min"] = pilatus_name.roi3.min_xyz.get().min_x - md_return["ROI3_X_size"] = pilatus_name.roi3.size.get().x - md_return["ROI3_Y_min"] = pilatus_name.roi3.min_xyz.get().min_y - md_return["ROI3_Y_size"] = pilatus_name.roi3.size.get().y - - md_return["ROI4_X_min"] = pilatus_name.roi4.min_xyz.get().min_x - md_return["ROI4_X_size"] = pilatus_name.roi4.size.get().x - md_return["ROI4_Y_min"] = pilatus_name.roi4.min_xyz.get().min_y - md_return["ROI4_Y_size"] = pilatus_name.roi4.size.get().y - - # md_return['ROI2_X_min'] = caget('XF:11BMB-ES{}:ROI2:MinX'.format(pilatus_Epicsname)) - # md_return['ROI2_X_size'] = caget('XF:11BMB-ES{}:ROI2:SizeX'.format(pilatus_Epicsname)) - # md_return['ROI2_Y_min'] = caget('XF:11BMB-ES{}:ROI2:MinY'.format(pilatus_Epicsname)) - # md_return['ROI2_Y_size'] = caget('XF:11BMB-ES{}:ROI2:SizeY'.format(pilatus_Epicsname)) - - # md_return['ROI3_X_min'] = caget('XF:11BMB-ES{}:ROI3:MinX'.format(pilatus_Epicsname)) - # md_return['ROI3_X_size'] = caget('XF:11BMB-ES{}:ROI3:SizeX'.format(pilatus_Epicsname)) - # md_return['ROI3_Y_min'] = caget('XF:11BMB-ES{}:ROI3:MinY'.format(pilatus_Epicsname)) - # md_return['ROI3_Y_size'] = caget('XF:11BMB-ES{}:ROI3:SizeY'.format(pilatus_Epicsname)) - - # md_return['ROI4_X_min'] = caget('XF:11BMB-ES{}:ROI4:MinX'.format(pilatus_Epicsname)) - # md_return['ROI4_X_size'] = caget('XF:11BMB-ES{}:ROI4:SizeX'.format(pilatus_Epicsname)) - # md_return['ROI4_Y_min'] = caget('XF:11BMB-ES{}:ROI4:MinY'.format(pilatus_Epicsname)) - # md_return['ROI4_Y_size'] = caget('XF:11BMB-ES{}:ROI4:SizeY'.format(pilatus_Epicsname)) + md_return["ROI1_X_min"] = yield from bps.rd(self.detector.roi1.min_xyz.min_x) + md_return["ROI1_X_size"] = yield from bps.rd(self.detector.roi1.size.x) + md_return["ROI1_Y_min"] = yield from bps.rd(self.detector.roi1.min_xyz.min_y) + md_return["ROI1_Y_size"] = yield from bps.rd(self.detector.roi1.size.y) + + md_return["ROI2_X_min"] = yield from bps.rd(self.detector.roi2.min_xyz.min_x) + md_return["ROI2_X_size"] = yield from bps.rd(self.detector.roi2.size.x) + md_return["ROI2_Y_min"] = yield from bps.rd(self.detector.roi2.min_xyz.min_y) + md_return["ROI2_Y_size"] = yield from bps.rd(self.detector.roi2.size.y) + + md_return["ROI3_X_min"] = yield from bps.rd(self.detector.roi3.min_xyz.min_x) + md_return["ROI3_X_size"] = yield from bps.rd(self.detector.roi3.size.x) + md_return["ROI3_Y_min"] = yield from bps.rd(self.detector.roi3.min_xyz.min_y) + md_return["ROI3_Y_size"] = yield from bps.rd(self.detector.roi3.size.y) + + md_return["ROI4_X_min"] = yield from bps.rd(self.detector.roi4.min_xyz.min_x) + md_return["ROI4_X_size"] = yield from bps.rd(self.detector.roi4.size.x) + md_return["ROI4_Y_min"] = yield from bps.rd(self.detector.roi4.min_xyz.min_y) # Include the user-specified metadata md_return.update(md) @@ -185,10 +149,7 @@ def get_md(self, prefix="detector_WAXS_", **md): x0, y0 = self.direct_beam position_defined_x, position_defined_y = self.detector_position - position_current_x, position_current_y = ( - WAXSx.user_readback.value, - WAXSy.user_readback.value, - ) + position_current_x, position_current_y = WAXSx.user_readback.value, WAXSy.user_readback.value md_return["name"] = self.detector.name md_return["epics_name"] = "{Det:PIL800K}" @@ -197,33 +158,31 @@ def get_md(self, prefix="detector_WAXS_", **md): # md_return['x0_pix'] = round( x0 + (position_current_x-position_defined_x)/self.pixel_size , 2 ) # md_return['y0_pix'] = round( y0 + (position_current_y-position_defined_y)/self.pixel_size , 2 ) # if pilatus_name==pilatus800: + md_return["x0_pix"] = round(x0 + (position_current_x - position_defined_x) / self.pixel_size, 2) md_return["y0_pix"] = round(y0 + (position_current_y - position_defined_y) / self.pixel_size, 2) - # TODO:WAXS PV - + md_return["ROI1_X_min"] = yield from bps.rd(self.detector.roi1.min_xyz.get().min_x) + md_return["ROI1_X_size"] = yield from bps.rd(self.detector.roi1.size.get().x) + md_return["ROI1_Y_min"] = yield from bps.rd(self.detector.roi1.min_xyz.get().min_y) + md_return["ROI1_Y_size"] = yield from bps.rd(self.detector.roi1.size.get().y) + + md_return["ROI2_X_min"] = yield from bps.rd(self.detector.roi2.min_xyz.get().min_x) + md_return["ROI2_X_size"] = yield from bps.rd(self.detector.roi2.size.get().x) + md_return["ROI2_Y_min"] = yield from bps.rd(self.detector.roi2.min_xyz.get().min_y) + md_return["ROI2_Y_size"] = yield from bps.rd(self.detector.roi2.size.get().y) + + md_return["ROI3_X_min"] = yield from bps.rd(self.detector.roi3.min_xyz.get().min_x) + md_return["ROI3_X_size"] = yield from bps.rd(self.detector.roi3.size.get().x) + md_return["ROI3_Y_min"] = yield from bps.rd(self.detector.roi3.min_xyz.get().min_y) + md_return["ROI3_Y_size"] = yield from bps.rd(self.detector.roi3.size.get().y) + + md_return["ROI4_X_min"] = yield from bps.rd(self.detector.roi4.min_xyz.get().min_x) + md_return["ROI4_X_size"] = yield from bps.rd(self.detector.roi4.size.get().x) + md_return["ROI4_Y_min"] = yield from bps.rd(self.detector.roi4.min_xyz.get().min_y) + md_return["ROI4_Y_size"] = yield from bps.rd(self.detector.roi4.size.get().y) md_return["distance_m"] = self.distance - md_return["ROI1_X_min"] = caget("XF:11BMB-ES{}:ROI1:MinX".format(pilatus_Epicsname)) - md_return["ROI1_X_size"] = caget("XF:11BMB-ES{}:ROI1:SizeX".format(pilatus_Epicsname)) - md_return["ROI1_Y_min"] = caget("XF:11BMB-ES{}:ROI1:MinY".format(pilatus_Epicsname)) - md_return["ROI1_Y_size"] = caget("XF:11BMB-ES{}:ROI1:SizeY".format(pilatus_Epicsname)) - - md_return["ROI2_X_min"] = caget("XF:11BMB-ES{}:ROI2:MinX".format(pilatus_Epicsname)) - md_return["ROI2_X_size"] = caget("XF:11BMB-ES{}:ROI2:SizeX".format(pilatus_Epicsname)) - md_return["ROI2_Y_min"] = caget("XF:11BMB-ES{}:ROI2:MinY".format(pilatus_Epicsname)) - md_return["ROI2_Y_size"] = caget("XF:11BMB-ES{}:ROI2:SizeY".format(pilatus_Epicsname)) - - md_return["ROI3_X_min"] = caget("XF:11BMB-ES{}:ROI3:MinX".format(pilatus_Epicsname)) - md_return["ROI3_X_size"] = caget("XF:11BMB-ES{}:ROI3:SizeX".format(pilatus_Epicsname)) - md_return["ROI3_Y_min"] = caget("XF:11BMB-ES{}:ROI3:MinY".format(pilatus_Epicsname)) - md_return["ROI3_Y_size"] = caget("XF:11BMB-ES{}:ROI3:SizeY".format(pilatus_Epicsname)) - - md_return["ROI4_X_min"] = caget("XF:11BMB-ES{}:ROI4:MinX".format(pilatus_Epicsname)) - md_return["ROI4_X_size"] = caget("XF:11BMB-ES{}:ROI4:SizeX".format(pilatus_Epicsname)) - md_return["ROI4_Y_min"] = caget("XF:11BMB-ES{}:ROI4:MinY".format(pilatus_Epicsname)) - md_return["ROI4_Y_size"] = caget("XF:11BMB-ES{}:ROI4:SizeY".format(pilatus_Epicsname)) - # Include the user-specified metadata md_return.update(md) @@ -234,18 +193,16 @@ def get_md(self, prefix="detector_WAXS_", **md): return md_return +# TODO: Use Ophyd and remove this. class BeamlineElement(object): """Defines a component of the beamline that (may) intersect the x-ray beam.""" - def __init__(self, name, zposition, description="", pv=None, **args): + def __init__(self, name, zposition, description="", obj=None, **args): self.name = name self.zposition = zposition self.description = description - self.conversion_factor = 1 - - self._pv_main = pv - + self._obj = obj self.has_flux = True def state(self): @@ -288,6 +245,7 @@ def flux(self, verbosity=3): return flux +# TODO: Use Ophyd and remove this. class Shutter(BeamlineElement): # Example # XF:11BMA-PPS{PSh}Enbl-Sts @@ -295,8 +253,8 @@ class Shutter(BeamlineElement): # Open: XF:11BMA-PPS{PSh}Cmd:Opn-Cmd # Close: XF:11BMA-PPS{PSh}Cmd:Cls-Cmd - def __init__(self, name, zposition, description="", pv=None, **args): - super().__init__(name=name, zposition=zposition, description=description, pv=pv, **args) + def __init__(self, name, zposition, description="", obj=None, **args): + super().__init__(name=name, zposition=zposition, description=description, obj=obj, **args) self.has_flux = False def state(self): @@ -308,7 +266,7 @@ def state(self): undefined - Element is in an unexpected state. """ - state_n = caget(self._pv_main + "Pos-Sts") + state_n = yield from bps.rd(self._obj.status) if state_n == 0: return "out" @@ -588,12 +546,10 @@ def __init__( self.beam = beam # PVs - import epics - - self.v1 = epics.PV("XF:11BMB-BI{IM:3}:IC1_MON") - self.v2 = epics.PV("XF:11BMB-BI{IM:3}:IC2_MON") - self.h1 = epics.PV("XF:11BMB-BI{IM:3}:IC3_MON") - self.h2 = epics.PV("XF:11BMB-BI{IM:3}:IC4_MON") + self.v1 = EpicsSignal("XF:11BMB-BI{IM:3}:IC1_MON") + self.v2 = EpicsSignal("XF:11BMB-BI{IM:3}:IC2_MON") + self.h1 = EpicsSignal("XF:11BMB-BI{IM:3}:IC3_MON") + self.h2 = EpicsSignal("XF:11BMB-BI{IM:3}:IC4_MON") def state(self): return "in" @@ -613,7 +569,11 @@ def h_position(self): return 0 def reading(self, verbosity=3): - total = self.h1.value + self.h2.value + self.v1.value + self.v2.value + h1 = yield from bps.rd(self.h1) + h2 = yield from bps.rd(self.h2) + v1 = yield from bps.rd(self.v1) + v2 = yield from bps.rd(self.v2) + total = sum([h1, h2, v1, v2]) if verbosity >= 3: print("Reading for {:s} ({:s})".format(self.name, self.description)) @@ -655,14 +615,19 @@ def current_to_flux(self, current): return flux def flux(self, verbosity=3): - if self.reading(verbosity=0) < 5e-10: + rd = yield from self.reading(verbosity=0) + if rd < 5e-10: return 0.0 - h1 = self.current_to_flux(self.h1.value) - h2 = self.current_to_flux(self.h2.value) + h1 = yield from bps.rd(self.h1) + h2 = yield from bps.rd(self.h2) + v1 = yield from bps.rd(self.v1) + v2 = yield from bps.rd(self.v2) + h1 = self.current_to_flux(h1) + h2 = self.current_to_flux(h2) h_total = h1 + h2 - v1 = self.current_to_flux(self.v1.value) - v2 = self.current_to_flux(self.v2.value) + v1 = self.current_to_flux(v1) + v2 = self.current_to_flux(v2) v_total = v1 + v2 total = h_total + v_total @@ -700,21 +665,19 @@ def __init__( self.beam = beam # PVs - import epics - - self.sec = epics.PV("XF:11BMB-BI{IM:4}:GET_PERIOD") # integration time in [sec] - self.cts = epics.PV("XF:11BMB-BI{IM:4}:C1_1") # raw counts + self.sec = EpicsSignal("XF:11BMB-BI{IM:4}:GET_PERIOD") # integration time in [sec] + self.cts = EpicsSignal("XF:11BMB-BI{IM:4}:C1_1") # raw counts def state(self): return "in" def reading(self, verbosity=3): - if self.sec.value == 0.0: + sec = yield from bps.rd(self.sec) + if sec == 0.0: print("Counting time set to zero. Check CSS settings for FMB Oxford C400.") return 0 else: - sec = self.sec.value - cts = self.cts.value + cts = yield from bps.rd(self.cts) cps = cts / sec if verbosity >= 3: @@ -746,10 +709,11 @@ def cps_to_flux(self, cps): return flux def flux(self, verbosity=3): - if self.reading(verbosity=0) < 5e-10: + reading = yield from self.reading(verbosity=0) + if reading < 5e-10: return 0.0 - flux = self.cps_to_flux(self.reading(verbosity=0)) + flux = self.cps_to_flux(reading) if verbosity >= 3: print("Flux for {:s} ({:s})".format(self.name, self.description)) @@ -776,12 +740,10 @@ def __init__( self.beam = beam # PVs - import epics - - self.i0 = epics.PV("XF:11BMB-BI{BPM:1}Cur:I0-I") # upper left - self.i1 = epics.PV("XF:11BMB-BI{BPM:1}Cur:I1-I") # upper right - self.i2 = epics.PV("XF:11BMB-BI{BPM:1}Cur:I2-I") # lower left - self.i3 = epics.PV("XF:11BMB-BI{BPM:1}Cur:I3-I") # lower right + self.i0 = EpicsSignal("XF:11BMB-BI{BPM:1}Cur:I0-I") # upper left + self.i1 = EpicsSignal("XF:11BMB-BI{BPM:1}Cur:I1-I") # upper right + self.i2 = EpicsSignal("XF:11BMB-BI{BPM:1}Cur:I2-I") # lower left + self.i3 = EpicsSignal("XF:11BMB-BI{BPM:1}Cur:I3-I") # lower right def state(self): # TODO: fix this so it queries state of IM:5 @@ -805,7 +767,12 @@ def reading(self, verbosity=3): # total = self.i0.value + self.i1.value + self.i2.value + self.i3.value ## 07/12/2017 Total dark current with beam off is ~9.3e-10 A. dark_current = 9.3e-10 - total = self.i0.value + self.i1.value + self.i2.value + self.i3.value - dark_current + i0 = yield from bps.rd(self.i0) + i1 = yield from bps.rd(self.i1) + i2 = yield from bps.rd(self.i2) + i3 = yield from bps.rd(self.i3) + + total = i0 + i1 + i2 + i3 - dark_current if verbosity >= 3: print("Reading for {:s} ({:s})".format(self.name, self.description)) @@ -862,7 +829,8 @@ def current_to_flux(self, current): return flux def flux(self, verbosity=3): - if self.reading(verbosity=0) < 1e-11: + reading = yield from self.reading(verbosity=0) + if reading < 1e-11: return 0.0 right = self.current_to_flux(self.i1.value + self.i3.value) @@ -1058,7 +1026,8 @@ def energy(self, verbosity=3): """ # Current angle of monochromator multilayer crystal - Bragg_deg = caget(self.mono_bragg_pv) + # Bragg_deg = caget(self.mono_bragg_pv) + Bragg_deg = mono_bragg.position Bragg_rad = np.radians(Bragg_deg) wavelength_A = 2.0 * self.dmm_dsp * np.sin(Bragg_rad) @@ -1085,7 +1054,8 @@ def wavelength(self, verbosity=3): """ # Current angle of monochromator multilayer crystal - Bragg_deg = caget(self.mono_bragg_pv) + # Bragg_deg = caget(self.mono_bragg_pv) + Bragg_deg = mono_bragg.position Bragg_rad = np.radians(Bragg_deg) wavelength_A = 2.0 * self.dmm_dsp * np.sin(Bragg_rad) @@ -1122,13 +1092,28 @@ def setEnergy(self, energy_keV, verbosity=3): return self.energy(verbosity=0) + def setEnergy_YF(self, energy_keV, verbosity=3): + """ + Set the x-ray beam to the specified energy (by changing the + monochromator angle. + """ + + energy_eV = energy_keV * 1000.0 + wavelength_m = self.hc_over_e / energy_eV + wavelength_A = wavelength_m * 1.0e10 + + self.setWavelength(wavelength_A, verbosity=verbosity) + + return self.energy(verbosity=0) + def setWavelength(self, wavelength_A, verbosity=3): """ Set the x-ray beam to the specified wavelength (by changing the monochromator angle. """ - Bragg_deg_initial = caget(self.mono_bragg_pv) + # Bragg_deg_initial = caget(self.mono_bragg_pv) + Bragg_deg = mono_bragg.position wavelength_m = wavelength_A * 1.0e-10 Bragg_rad = np.arcsin(wavelength_A / (2.0 * self.dmm_dsp)) Bragg_deg = np.degrees(Bragg_rad) @@ -1148,6 +1133,34 @@ def setWavelength(self, wavelength_A, verbosity=3): return self.wavelength(verbosity=verbosity) + def setWavelength_YF(self, wavelength_A, verbosity=3): + """ + Set the x-ray beam to the specified wavelength (by changing the + monochromator angle. + """ + + # Bragg_deg_initial = caget(self.mono_bragg_pv) + Bragg_deg = mono_bragg.position + wavelength_m = wavelength_A * 1.0e-10 + Bragg_rad = np.arcsin(wavelength_A / (2.0 * self.dmm_dsp)) + Bragg_deg = np.degrees(Bragg_rad) + + print("mono_bragg will move to {:.4f}g deg".format(Bragg_deg)) + response = input(" Are you sure? (y/[n]) ") + if response == "y" or response == "Y": + # mov(mono_bragg, Bragg_deg) + # mono_bragg.move = Bragg_deg + # mono_bragg.move(Bragg_deg) + yield from bps.mov(mono_bragg, Bragg_deg) + + if verbosity >= 1: + print("mono_bragg moved from {:.4f} deg to {:.4f} deg".format(Bragg_deg_initial, Bragg_deg)) + + elif verbosity >= 1: + print("No move was made.") + + return self.wavelength(verbosity=verbosity) + # Slits ######################################## @@ -1156,8 +1169,8 @@ def size(self, verbosity=3): Returns the current beam size (rough estimate). The return is (size_horizontal, size_vertical) (in mm). """ - size_h = self.beam_defining_slit.xg.user_readback.value - size_v = self.beam_defining_slit.yg.user_readback.value + size_h = self.beam_defining_slit.xg.position + size_v = self.beam_defining_slit.yg.position if verbosity >= 3: print("Beam size:") @@ -1182,6 +1195,24 @@ def setSize(self, horizontal, vertical, verbosity=3): self.beam_defining_slit.yg.user_setpoint.value = vertical + def setSize_YF(self, horizontal, vertical, verbosity=3): + """ + Sets the beam size. + """ + + h, v = self.size(verbosity=0) + + if verbosity >= 3: + print("Changing horizontal beam size from {:.3f} mm to {:.3f} mm".format(h, horizontal)) + yield from bps.mov(self.beam_defining_slit.xg, horizontal) + # self.beam_defining_slit.xg.user_setpoint.value = horizontal + + if verbosity >= 3: + print("Changing vertical beam size from {:.3f} mm to {:.3f} mm".format(v, vertical)) + yield from bps.mov(self.beam_defining_slit.yg, vertical) + + # self.beam_defining_slit.yg.user_setpoint.value = vertical + def divergence(self, verbosity=3): """ Returns the beamline divergence. @@ -1191,8 +1222,11 @@ def divergence(self, verbosity=3): distance_m = 10.0 # distance from source to slits - horizontal_mm = caget("FE:C11B-OP{Slt:12-Ax:X}t2.C") - vertical_mm = caget("FE:C11B-OP{Slt:12-Ax:Y}t2.C") + # horizontal_mm = caget('FE:C11B-OP{Slt:12-Ax:X}t2.C') + # vertical_mm = caget('FE:C11B-OP{Slt:12-Ax:Y}t2.C') + + horizontal_mm = FE_x.position + vertical_mm = FE_y.position horizontal_mrad = horizontal_mm / distance_m vertical_mrad = vertical_mm / distance_m @@ -1243,6 +1277,47 @@ def setDivergence(self, horizontal, vertical, verbosity=3): print("Changing vertical divergence from {:.3f} mrad to {:.3f} mrad.".format(v, vertical)) caput("FE:C11B-OP{Slt:12-Ax:Y}size", vertical_mm) + def setDivergence_YF(self, horizontal, vertical, verbosity=3): + """ + Set beamline divergence (in mrad). + This is controlled using the Front End (FE) slits. + """ + + h, v = self.divergence(verbosity=0) + + distance_m = 10.0 # distance from source to slits + + horizontal_mm = horizontal * distance_m + vertical_mm = vertical * distance_m + + if horizontal < 0: + if verbosity >= 1: + print("Horizontal divergence less than zero ({}) doesn't make sense.".format(horizontal)) + + elif horizontal > 1.5: + if verbosity >= 1: + print("Horizontal divergence should be less than 1.5 mrad.") + + else: + if verbosity >= 3: + print("Changing horizontal divergence from {:.3f} mrad to {:.3f} mrad.".format(h, horizontal)) + # caput('FE:C11B-OP{Slt:12-Ax:X}size', horizontal_mm) + yield from bps.mov(FE_x, horizontal_mm) + + if vertical < 0: + if verbosity >= 1: + print("Vertical divergence less than zero ({}) doesn't make sense.".format(vertical)) + + elif vertical > 0.15: + if verbosity >= 1: + print("Vertical divergence should be less than 0.15 mrad.") + + else: + if verbosity >= 3: + print("Changing vertical divergence from {:.3f} mrad to {:.3f} mrad.".format(v, vertical)) + # caput('FE:C11B-OP{Slt:12-Ax:Y}size', vertical_mm) + yield from bps.mov(FE_y, vertical_mm) + # Experimental Shutter ######################################## @@ -1338,6 +1413,39 @@ def setDivergence(self, horizontal, vertical, verbosity=3): # else: # if verbosity>=4: # print('Beam off (shutter already closed).') + # def blade1_is_on(self, verbosity=3): + # '''Returns true if the beam is on (experimental shutter open).''' + + # blade1 = caget('XF:11BMB-OP{PSh:2}Pos:1-Sts') + + # if blade1==1: + # if verbosity>=4: + # print('Beam on (shutter open).') + + # return True + + # else: + # if verbosity>=4: + # print('Beam off (shutter closed).') + + # return False + + # def blade2_is_on(self, verbosity=3): + # '''Returns true if the beam is on (experimental shutter open).''' + + # blade2 = caget('XF:11BMB-OP{PSh:2}Pos:2-Sts') + + # if blade2==1: + # if verbosity>=4: + # print('Beam on (shutter open).') + + # return True + + # else: + # if verbosity>=4: + # print('Beam off (shutter closed).') + + # return False def is_on(self, verbosity=3): """Returns 1 if the beam is on (experimental shutter open).""" @@ -1345,93 +1453,78 @@ def is_on(self, verbosity=3): shutter_state(verbosity=verbosity) return shutter_state(verbosity=0) - def on( - self, - verbosity=3, - wait_time=0.1, - poling_period=0.10, - retry_time=2.0, - max_retries=5, - ): + def on(self, verbosity=3, wait_time=0.1, poling_period=0.10, retry_time=2.0, max_retries=5): """Turn on the beam (open experimental shutter). - update: 090517, RL: change the wait_time from 0.005 to 0.1, change sleep to time.sleep - """ + update: 090517, RL: change the wait_time from 0.005 to 0.1, change sleep to time.sleep""" if self.is_on(verbosity=0): if verbosity >= 4: print("Beam on (shutter already open.)") else: - RE(shutter_on(verbosity=0)) + yield from shutter_on(verbosity=0) if verbosity >= 4: if self.is_on(verbosity=0): print("Beam on (shutter opened).") else: print("Beam off (shutter didn't open).") - def off( - self, - verbosity=3, - wait_time=0.1, - poling_period=0.10, - retry_time=2.0, - max_retries=5, - ): - """Turn off the beam (close experimental shutter). - update: 090517, RL: change the wait_time from 0.005 to 0.1, change sleep to time.sleep - """ + def on_YF(self, verbosity=3, wait_time=0.1, poling_period=0.10, retry_time=2.0, max_retries=5): + """Turn on the beam (open experimental shutter). + update: 090517, RL: change the wait_time from 0.005 to 0.1, change sleep to time.sleep""" if self.is_on(verbosity=0): - RE(shutter_off(verbosity=0)) - if verbosity >= 4: - if self.is_on(verbosity=0): - print("Beam on (shutter didn't close).") - else: - print("Beam off (shutter closed).") + print("Beam on (shutter already open.)") else: + yield from shutter_on(verbosity=0) + if verbosity >= 4: - print("Beam off (shutter already closed).") + if self.is_on(verbosity=0): + print("Beam on (shutter opened).") + else: + print("Beam off (shutter didn't open).") - def blade1_is_on(self, verbosity=3): - """Returns true if the beam is on (experimental shutter open).""" + def off(self, verbosity=3, wait_time=0.1, poling_period=0.10, retry_time=2.0, max_retries=5): + """Turn off the beam (close experimental shutter). + update: 090517, RL: change the wait_time from 0.005 to 0.1, change sleep to time.sleep""" - blade1 = caget("XF:11BMB-OP{PSh:2}Pos:1-Sts") + if self.is_on(verbosity=0): + yield from shutter_off(verbosity=0) - if blade1 == 1: if verbosity >= 4: - print("Beam on (shutter open).") - - return True + if self.is_on(verbosity=0): + print("Beam on (shutter didn't close).") + else: + print("Beam off (shutter closed).") else: if verbosity >= 4: - print("Beam off (shutter closed).") - - return False + print("Beam off (shutter already closed).") - def blade2_is_on(self, verbosity=3): - """Returns true if the beam is on (experimental shutter open).""" + def off_YF(self, verbosity=3, wait_time=0.1, poling_period=0.10, retry_time=2.0, max_retries=5): + """Turn off the beam (close experimental shutter). + update: 090517, RL: change the wait_time from 0.005 to 0.1, change sleep to time.sleep""" - blade2 = caget("XF:11BMB-OP{PSh:2}Pos:2-Sts") + if self.is_on(verbosity=0): + yield from shutter_off(verbosity=0) - if blade2 == 1: if verbosity >= 4: - print("Beam on (shutter open).") - - return True + if self.is_on(verbosity=0): + print("Beam on (shutter didn't close).") + else: + print("Beam off (shutter closed).") else: if verbosity >= 4: - print("Beam off (shutter closed).") - - return False + print("Beam off (shutter already closed).") # Attenuator/Filter Box ######################################## def transmission(self, verbosity=3): + ###TODO: """ Returns the current beam transmission through the attenuator/filter box. To change the transmission, use 'setTransmission'. @@ -1525,14 +1618,12 @@ def set_attenuation_filters(self, filter_settings, verbosity=3): filters_initial = [caget("XF:11BMB-OP{{Fltr:{:d}}}Pos-Sts".format(ifoil)) for ifoil in range(1, 8 + 1)] print( " initial: {} T = {:.6g}".format( - filters_initial, - self.calc_transmission_filters(filters_initial, verbosity=0), + filters_initial, self.calc_transmission_filters(filters_initial, verbosity=0) ) ) print( " requested: {} T = {:.6g}".format( - filter_settings, - self.calc_transmission_filters(filter_settings, verbosity=0), + filter_settings, self.calc_transmission_filters(filter_settings, verbosity=0) ) ) @@ -1567,8 +1658,75 @@ def set_attenuation_filters(self, filter_settings, verbosity=3): filters_final = [caget("XF:11BMB-OP{{Fltr:{:d}}}Pos-Sts".format(ifoil)) for ifoil in range(1, 8 + 1)] print( " final: {} T = {:.6g}".format( - filters_final, - self.calc_transmission_filters(filters_final, verbosity=0), + filters_final, self.calc_transmission_filters(filters_final, verbosity=0) + ) + ) + + def set_attenuation_filters_YF(self, filter_settings, verbosity=3): + """ + Sets the positions (in/out) for each of the foils in the attenuator/ + filter box. The input 'filter_settings' should be an array of length + 8, where each element is either a zero (foil removed) or a 1 (foil + blocking beam). + """ + # define the list of the foils + foil_series = [EpicsSignal("XF:11BMB-OP{{Fltr:{:d}}}Pos-Sts".format(ifoil)) for ifoil in range(1, 8 + 1)] + + if verbosity >= 4: + print("Filters:") + # The states of the foils in the filter box + + # filters_initial = [ caget('XF:11BMB-OP{{Fltr:{:d}}}Pos-Sts'.format(ifoil)) for ifoil in range(1, 8+1) ] + filters_initial = [item.get() for item in foil_series] + print( + " initial: {} T = {:.6g}".format( + filters_initial, self.calc_transmission_filters(filters_initial, verbosity=0) + ) + ) + print( + " requested: {} T = {:.6g}".format( + filter_settings, self.calc_transmission_filters(filter_settings, verbosity=0) + ) + ) + + if len(filter_settings) != 8: + print("States for all eight foils must be specified.") + + else: + for i, state in enumerate(filter_settings): + ifoil = i + 1 + + if state == 1: + # Put foil #ifoil into the beam + foil_series[i].put(state) + # TODO, double-check the moving command + # caput( 'XF:11BMB-OP{{Fltr:{:d}}}Cmd:In-Cmd'.format(ifoil) , 1 ) + + elif state == 0: + # Remove foil #ifoil + foil_series[i].put(state) + # caput( 'XF:11BMB-OP{{Fltr:{:d}}}Cmd:Out-Cmd'.format(ifoil) , 1 ) + + else: + if verbosity >= 3: + # state_actual = caget( 'XF:11BMB-OP{{Fltr:{:d}}}Pos-Sts'.format(ifoil) ) + state_actual = [item.get() for item in foil_series] + state_actual_str = "IN" if state_actual == 1 else "OUT" + print( + "WARNING: Filter state {} not recognized. Filter {:d} is {:s}.".format( + state, ifoil, state_actual_str + ) + ) + + time.sleep(1.0) # Wait for filter box to settle + + if verbosity >= 4: + # filters_final = [ caget('XF:11BMB-OP{{Fltr:{:d}}}Pos-Sts'.format(ifoil)) for ifoil in range(1, 8+1) ] + + filters_final = [item.get() for item in foil_series] + print( + " final: {} T = {:.6g}".format( + filters_final, self.calc_transmission_filters(filters_final, verbosity=0) ) ) @@ -1640,10 +1798,7 @@ def setTransmission(self, transmission, retries=3, tolerance=0.7, verbosity=3): # time.sleep(0.5) # Try again return self.setTransmission( - transmission, - retries=retries - 1, - tolerance=tolerance, - verbosity=verbosity, + transmission, retries=retries - 1, tolerance=tolerance, verbosity=verbosity ) else: @@ -1672,7 +1827,6 @@ def absorber(self, verbosity=3): else: # The foil layers slot = np.floor((armr.position - self.armr_absorber_o + 3 - 0.1) / 6) - # slot = np.floor((armr.position - self.armr_absorber_o+.1)/10) if slot > 6 or slot < 0: return print("Absorber slot should in the range of [0, 6]") @@ -1702,7 +1856,7 @@ def absorberCalcTransmission(self, slot, verbosity=3): l_Nb = 1.4476e-3 - 5.6011e-4 * E + 1.0401e-4 * E2 + 8.7961e-6 * E3 d_l_Nb = d_Nb / l_Nb - # absorber_transmission = exp(-slot*d_l_Nb) + absorber_transmission = exp(-slot * d_l_Nb) if abs(E - 13.5) < 0.01: self.absorber_transmission_list = [ @@ -1717,22 +1871,7 @@ def absorberCalcTransmission(self, slot, verbosity=3): elif abs(E - 17) < 0.01: self.absorber_transmission_list = self.absorber_transmission_list_17kev elif abs(E - 10) < 0.1: - # self.absorber_transmission_list = self.absorber_transmission_list_10kev - beam_int = np.array( - [ - 3606803 / 403323 * 3296026, - 3606803, - 406113, - 50002, - 6268, - 6268 / 3520688 * 384577, - 6268 / 3520688 * 43940, - 6268 / 3520688 * 5383, - ] - ) - - # - self.absorber_transmission_list = beam_int / beam_int[0] # changed by RL, 202307 + self.absorber_transmission_list = self.absorber_transmission_list_10kev else: tmp_list = [] @@ -1740,8 +1879,6 @@ def absorberCalcTransmission(self, slot, verbosity=3): tmp_list.append(exp(-i * d_l_Nb)) self.absorber_transmission_list = tmp_list - absorber_transmission = self.absorber_transmission_list[int(slot)] - if verbosity >= 1: print("transmission = {:.6g}".format(absorber_transmission)) @@ -1757,20 +1894,52 @@ def setAbsorber(self, slot, retries=3, tolerance=0.5, verbosity=3): if energy_keV < 6.0 or energy_keV > 18.0: print("Transmission data not available at the current X-ray energy ({.2f} keV).".format(energy_keV)) - # elif slot < 0 or slot > 6: - # print('Absorber cannot move beyond [0, 6]') - elif slot < 0 or slot > 7: # changed by RL, 202307 - print("Absorber cannot move beyond [0, 7]") + elif slot < 0 or slot > 6: + print("Absorber cannot move beyond [0, 6]") else: # move to slot # for correct attenuation. - # armr_pos = self.armr_absorber_o+slot*10 # 10 mm wide per slot for OPLS absorber 10mm wide, changed by RL, 202307 - armr_pos = self.armr_absorber_o + slot * 6 # 6 mm wide per slot, changed back by RL, 202309 - # armr.move(self.armr_absorber_o+slot*6) - armr.move(armr_pos) + armr.move(self.armr_absorber_o + slot * 6) # 6 mm wide per slot # Check that absorber was actually correctly moved - if abs(armr.position - armr_pos) > tolerance: + if abs(armr.position - (self.armr_absorber_o + slot * 6)) > tolerance: + if retries > 0: + # time.sleep(0.5) + # Try again + return self.absorberCalcTransmission(slot), self.setAbsorber( + slot, retries=retries - 1, tolerance=tolerance, verbosity=verbosity + ) + + else: + print( + "WARNING: transmission didn't update correctly (request: {}; actual: {})".format( + slot, self.transmission(verbosity=0) + ) + ) + + else: + return self.absorberCalcTransmission(slot) + + def setAbsorber_YF(self, slot, retries=3, tolerance=0.5, verbosity=3): + """ + Set the aborber of Nb foils for XRR measurements. + There are 6 layers of foil which gives the attenuation rate ~5-6% at 13.5kev. + """ + + energy_keV = self.energy(verbosity=0) + + if energy_keV < 6.0 or energy_keV > 18.0: + print("Transmission data not available at the current X-ray energy ({.2f} keV).".format(energy_keV)) + elif slot < 0 or slot > 6: + print("Absorber cannot move beyond [0, 6]") + + else: + # move to slot # for correct attenuation. + # armr.move(self.armr_absorber_o+slot*6) # 6 mm wide per slot + yield from bps.mov(armr, self.armr_absorber_o + slot * 6) + + # Check that absorber was actually correctly moved + if abs(armr.position - (self.armr_absorber_o + slot * 6)) > tolerance: if retries > 0: # time.sleep(0.5) # Try again @@ -1873,12 +2042,7 @@ def fluxes(self, verbosity=3): print( "|{:5.1f} m | {:16.16} | {:s} | {:11.11} | {:11.11} | {:11.11} |".format( - element.zposition, - element.name, - path, - reading_str, - flux_str, - flux_expected_str, + element.zposition, element.name, path, reading_str, flux_str, flux_expected_str ) ) @@ -1988,12 +2152,10 @@ def __init__(self, **kwargs): self.WAXS = CMS_WAXS_Detector(pilatus800) self.MAXS = CMS_SAXS_Detector(pilatus8002) - from epics import PV - - self._chamber_pressure_pv = PV("XF:11BMB-VA{Chm:Det-TCG:1}P-I") - self._PV_Smpl_pressure = PV("XF:11BMB-VA{Chm:Smpl-TCG:1}P-I") - self._PV_Det_pressure = PV("XF:11BMB-VA{Chm:Det-TCG:1}P-I") - self._PV_SAXS_pressure = PV("XF:11BMB-VA{BS:SAXS-TCG:1}P-I") + self._chamber_pressure_pv = EpicsSignal("XF:11BMB-VA{Chm:Det-TCG:1}P-I") + self._PV_Smpl_pressure = EpicsSignal("XF:11BMB-VA{Chm:Smpl-TCG:1}P-I") + self._PV_Det_pressure = EpicsSignal("XF:11BMB-VA{Chm:Det-TCG:1}P-I") + self._PV_SAXS_pressure = EpicsSignal("XF:11BMB-VA{BS:SAXS-TCG:1}P-I") self.detector = [] self.PLOT_Y = [] @@ -2083,29 +2245,63 @@ def modeMeasurement_bim6(self, verbosity=3): if self.beam.GVdsbig.state() != "out" and verbosity >= 1: print("Warning: Sample chamber gate valve (large, downstream) is not open.") - def modeAlignment(self, verbosity=3): + def modeAlignment_YF(self, verbosity=3): self.current_mode = "undefined" # TODO: Check what mode (TSAXS, GISAXS) and respond accordingly # TODO: Check if gate valves are open and flux is okay (warn user) # TODO: Check list: change attenuator for different energy, change the bsx position with beamcenter accordingly - self.beam.off() + yield from self.beam.off_YF() self.beam.setTransmission(1e-8) # 1e-6 for 13.5kev, 1e-8 for 17kev while beam.transmission() > 3e-8: time.sleep(0.5) self.beam.setTransmission(1e-8) # mov(bsx, -10.95) + yield from bps.mv(bsx, self.bsx_pos + 5) + + # detselect(pilatus300, suffix='_stats4_total') + # caput('XF:11BMB-ES{Det:SAXS}:cam1:AcquireTime', 0.5) + # caput('XF:11BMB-ES{Det:SAXS}:cam1:AcquirePeriod', 0.6) + + detselect(pilatus_name, suffix="_stats4_total") + yield from pilatus_name.setExposureTime(0.5) + # Comment out by RL, 071617 + # caput('XF:11BMB-ES{}:cam1:AcquireTime'.format(pilatus_Epicsname), 0.5) + # caput('XF:11BMB-ES{}:cam1:AcquirePeriod'.format(pilatus_Epicsname), 0.6) + # caput('XF:11BMB-ES{Det:PIL2M}:cam1:AcquirePeriod', 0.6) + + # TODO: Update ROI based on current SAXSx, SAXSy and the md in cms ob'XF:11BMB-VA{Chm:Smpl-VV:1_Soft}'ject + + self.current_mode = "alignment" + + # self.beam.bim6.reading() + + def modeAlignment(self, verbosity=3): + self.current_mode = "undefined" + + # TODO: Check what mode (TSAXS, GISAXS) and respond accordingly + # TODO: Check if gate valves are open and flux is okay (warn user) + # TODO: Check list: change attenuator for different energy, change the bsx position with beamcenter accordingly + + # self.beam.off() + yield from shutter_off() + self.beam.setTransmission(1e-8) # 1e-6 for 13.5kev, 1e-8 for 17kev + while beam.transmission() > 3e-8: + yield from bps.sleep(0.5) + self.beam.setTransmission(1e-8) + + # mov(bsx, -10.95) + yield from bps.mv(bsx, self.bsx_pos + 5) # bsx.move(self.bsx_pos+5) - bsx.move(self.bsx_pos + 3) # detselect(pilatus300, suffix='_stats4_total') # caput('XF:11BMB-ES{Det:SAXS}:cam1:AcquireTime', 0.5) # caput('XF:11BMB-ES{Det:SAXS}:cam1:AcquirePeriod', 0.6) detselect(pilatus_name, suffix="_stats4_total") - RE(pilatus_name.setExposureTime(0.5)) + yield from pilatus_name.setExposureTime(0.5) # Comment out by RL, 071617 # caput('XF:11BMB-ES{}:cam1:AcquireTime'.format(pilatus_Epicsname), 0.5) # caput('XF:11BMB-ES{}:cam1:AcquirePeriod'.format(pilatus_Epicsname), 0.6) @@ -2117,6 +2313,34 @@ def modeAlignment(self, verbosity=3): # self.beam.bim6.reading() + def modeMeasurement_YF(self, verbosity=3): + self.current_mode = "undefined" + + yield from self.beam.off_YF() + + # mov(bsx, -15.95) + yield from bps.mv(bsx, self.bsx_pos) + + if abs(bsx.user_readback.value - self.bsx_pos) > 0.1: + print("WARNING: Beamstop did not return to correct position!") + return + + yield from self.beam.setTransmission(1) + + # detselect(pilatus300) + # detselect([pilatus300, psccd]) + detselect(pilatus_name) + # detselect(psccd) + + # if RE.state is not 'idle': + # RE.abort() + + self.current_mode = "measurement" + + # Check if gate valves are open + if self.beam.GVdsbig.state() != "out" and verbosity >= 1: + print("Warning: Sample chamber gate valve (large, downstream) is not open.") + def modeMeasurement(self, verbosity=3): self.current_mode = "undefined" @@ -2354,7 +2578,7 @@ def _ventSample(self): while self._PV_Smpl_pressure.get() < 100: yield from bps.sleep(3) yield from bps.mov(self._vent_Smpl, "Open") - while self._PV_Smpl_pressure.get() < 950: + while self._PV_Smpl_pressure.get() < 980: print("waiting to complete venting.") yield from bps.sleep(3) print("The venting is completed after {}s.".format(time.time() - start_time)) @@ -2370,14 +2594,9 @@ def _changePipe(self): yield from bps.mov(self._pump2_toggle, 0) yield from bps.sleep(1) - def pumpSample(self, threshold=0.7, restartWAXS=False): + def pumpSample(self, threshold=0.7): RE(self._pumpSample(threshold=threshold)) - if restartWAXS == True: # changed by RL 230814 - restartWAXS() - RE(pilatus800.setExposureTime(3.2)) - RE(pilatus800.setExposureTime(0.5)) - def ventSample(self): RE(self._ventSample()) @@ -2883,21 +3102,21 @@ def get_md(self, prefix=None, **md): # md_current['detector'] = self.detector - md_current["motor_SAXSx"] = SAXSx.user_readback.value - md_current["motor_SAXSy"] = SAXSy.user_readback.value - md_current["motor_WAXSx"] = WAXSx.user_readback.value - md_current["motor_WAXSy"] = WAXSy.user_readback.value - md_current["motor_WAXSz"] = WAXSz.user_readback.value - md_current["motor_smx"] = smx.user_readback.value - md_current["motor_smy"] = smy.user_readback.value - md_current["motor_sth"] = sth.user_readback.value + md_current["motor_SAXSx"] = yield from bps.rd(SAXSx) + md_current["motor_SAXSy"] = yield from bps.rd(SAXSy) + md_current["motor_WAXSx"] = yield from bps.rd(WAXSx) + md_current["motor_WAXSy"] = yield from bps.rd(WAXSy) + md_current["motor_WAXSz"] = yield from bps.rd(WAXSz) + md_current["motor_smx"] = yield from bps.rd(smx) + md_current["motor_smy"] = yield from bps.rd(smy) + md_current["motor_sth"] = yield from bps.rd(sth) # md_current['motor_bsx'] = bsx.user_readback.value # md_current['motor_bsy'] = bsy.user_readback.value # md_current['motor_bsphi'] = bsphi.user_readback.value - # md_current.update(self.SAXS.get_md(prefix='detector_SAXS_')) - + saxs_md = yield from self.SAXS.get_md() + md_current.update(saxs_md) md_current.update(md) # Add an optional prefix @@ -2944,10 +3163,7 @@ def setMetadata(self, verbosity=3): ["experiment_user", "The specific user/person running the experiment"], ["experiment_project", "Project name/code"], ["experiment_alias_directory", "Alias directory"], - [ - "experiment_type", - "Type of experiments/measurements (SAXS, GIWAXS, etc.)", - ], + ["experiment_type", "Type of experiments/measurements (SAXS, GIWAXS, etc.)"], ] # TBD: @@ -2970,23 +3186,11 @@ def setMetadata(self, verbosity=3): else: os.makedirs(RE.md["experiment_alias_directory"], exist_ok=True) os.makedirs(os.path.join(RE.md["experiment_alias_directory"], "waxs"), exist_ok=True) - os.makedirs( - os.path.join(RE.md["experiment_alias_directory"], "waxs/raw"), - exist_ok=True, - ) - os.makedirs( - os.path.join(RE.md["experiment_alias_directory"], "waxs/analysis"), - exist_ok=True, - ) + os.makedirs(os.path.join(RE.md["experiment_alias_directory"], "waxs/raw"), exist_ok=True) + os.makedirs(os.path.join(RE.md["experiment_alias_directory"], "waxs/analysis"), exist_ok=True) os.makedirs(os.path.join(RE.md["experiment_alias_directory"], "saxs"), exist_ok=True) - os.makedirs( - os.path.join(RE.md["experiment_alias_directory"], "saxs/raw"), - exist_ok=True, - ) - os.makedirs( - os.path.join(RE.md["experiment_alias_directory"], "saxs/analysis"), - exist_ok=True, - ) + os.makedirs(os.path.join(RE.md["experiment_alias_directory"], "saxs/raw"), exist_ok=True) + os.makedirs(os.path.join(RE.md["experiment_alias_directory"], "saxs/analysis"), exist_ok=True) os.makedirs(os.path.join(RE.md["experiment_alias_directory"], "data"), exist_ok=True) # os.makedirs(os.path.join(RE.md['experiment_alias_directory'], 'saxs'), exist_ok=True) print( @@ -3005,10 +3209,7 @@ def _ask_question(self, key, text, default=None): else: ret = input( " Q{:d}/{:d}. {:s} [{}]: ".format( - self._dialog_question_number, - self._dialog_total_questions, - text, - default, + self._dialog_question_number, self._dialog_total_questions, text, default ) ) if ret == "": @@ -3097,22 +3298,16 @@ def logAllMotors(self, verbosity=3, **md): class CMS_Beamline_GISAXS(CMS_Beamline): - def __init__(self, **kwargs): - super().__init__(**kwargs) - def modeAlignment(self, verbosity=3): - if RE.state != "idle": - RE.abort() - self.current_mode = "undefined" # TODO: Check what mode (TSAXS, GISAXS) and respond accordingly # TODO: Check if gate valves are open and flux is okay (warn user) - self.beam.off() + yield from shutter_off() self.beam.setTransmission(1e-6) while beam.transmission() > 2e-6: - time.sleep(0.5) + yield from bps.sleep(0.5) self.beam.setTransmission(1e-6) # pilatus_name = pilatus2M @@ -3127,7 +3322,7 @@ def modeAlignment(self, verbosity=3): # mov(bsx, -16.53+3) # 07/20/17, GISAXS, 5m, CRoss # mov(bsx, self.bsx_pos+3) - bsx.move(self.bsx_pos + 3) + yield from bps.mv(bsx, self.bsx_pos + 3) self.setReflectedBeamROI() self.setDirectBeamROI() @@ -3138,7 +3333,7 @@ def modeAlignment(self, verbosity=3): # self.setMonitor(monitor=['stats3', 'stats4']) detselect(pilatus_name, suffix="_stats4_total") - RE(pilatus_name.setExposureTime(0.5)) + yield from pilatus_name.setExposureTime(0.5) # caput('XF:11BMB-ES{}:cam1:AcquireTime'.format(pilatus_Epicsname), 0.1) # caput('XF:11BMB-ES{}:cam1:AcquirePeriod'.format(pilatus_Epicsname), 0.6) @@ -3197,8 +3392,56 @@ def modeMeasurement(self, verbosity=3): self.current_mode = "measurement" # Check if gate valves are open - if self.beam.GVdsbig.state() is not "out" and verbosity >= 1: - print("Warning: Sample chamber gate valve (large, downstream) is not open.") + # if self.beam.GVdsbig.state() != "out" and verbosity >= 1: + # print("Warning: Sample chamber gate valve (large, downstream) is not open.") + + def modeMeasurement_plan(self, verbosity=3): + self.current_mode = "undefined" + + yield from shutter_off() + + # pilatus_name = pilatus2M + # pilatus_Epicsname = '{Det:PIL2M}' + # bsx_pos=-16.74 + # mov(bsx, -16.55) + # mov(bsx, -13.83) #change it at 06/02/17, Osuji Beam time + # mov(bsx, -14.73) #change it at 06/04/17, SAXS, 3m, Osuji Beam time + # mov(bsx, -15.03) #change it at 06/04/17, GISAXS, 3m, Osuji Beam time + # mov(bsx, -16.43) #change it at 06/12/17, GISAXS, 3m, LZhu Beam time + # mov(bsx, -16.53) #change it at 06/19/17, GISAXS, 5m, AHexemer Beam time + # mov(bsx, -16.2) #change it at 07/07/17, GISAXS, 3m, TKoga Beam time + # mov(bsx, -16.43) #change it at 07/10/17, GISAXS, 2m, LSita Beam time + # mov(bsx, -16.53) # 07/20/17, GISAXS, 5m, CRoss Beam time + # mov(bsx, -15.84) # 07/26/17, SAXS/WAXS, 2m, BVogt Beam time + # mov(bsx, -16.34) # 08/02/17, TOMO GISAXS, 5m, LRichter Beam time + # mov(bsx, -16.74) # 08/02/17, TOMO GISAXS, 5m, LRichter Beam time + # mov(bsx, self.bsx_pos) + + yield from bps.mv(bsx, self.bsx_pos) + + # if abs(bsx.user_readback.value - -16.74)>0.1: + if abs(bsx.user_readback.value - self.bsx_pos) > 0.1: + print("WARNING: Beamstop did not return to correct position!") + return + + self.beam.setTransmission(1) + + # mov(DETy, -16) + # self.beam.bim6.retract() + + # caput('XF:11BMB-BI{IM:2}EM180:Acquire', 0) # Turn off bim6 + # detselect(pilatus300) + # detselect([pilatus300, psccd]) + detselect(pilatus_name) + # detselect(psccd) + + # self.setMonitor(monitor=None) + + self.current_mode = "measurement" + + # Check if gate valves are open + # if self.beam.GVdsbig.state() != "out" and verbosity >= 1: + # print("Warning: Sample chamber gate valve (large, downstream) is not open.") def setDirectBeamROI(self, size=[10, 4], verbosity=3): """Update the ROI (stats4) for the direct beam on the Pilatus @@ -3206,13 +3449,12 @@ def setDirectBeamROI(self, size=[10, 4], verbosity=3): The size argument controls the size (in pixels) of the ROI itself (in the format [width, height]). A size=[6,4] is reasonable. - The size is changed to [10, 4] for possible beam drift during a user run (changed at 08/16/17) - """ + The size is changed to [10, 4] for possible beam drift during a user run (changed at 08/16/17)""" if pilatus_name.name == "pilatus2M": detector = self.SAXS # These positions are updated based on current detector position - det_md = detector.get_md() + det_md = yield from detector.get_md() x0 = det_md["detector_SAXS_x0_pix"] y0 = det_md["detector_SAXS_y0_pix"] if pilatus_name.name == "pilatus800": @@ -3230,6 +3472,8 @@ def setDirectBeamROI(self, size=[10, 4], verbosity=3): # detselect(pilatus300, suffix='_stats4_total') + pilatus_name.roi4.min_xyz.min_x.put(100) + caput("XF:11BMB-ES{}:ROI4:MinX".format(pilatus_Epicsname), int(x0 - size[0] / 2)) caput("XF:11BMB-ES{}:ROI4:SizeX".format(pilatus_Epicsname), int(size[0])) caput("XF:11BMB-ES{}:ROI4:MinY".format(pilatus_Epicsname), int(y0 - size[1] / 2)) @@ -3237,6 +3481,47 @@ def setDirectBeamROI(self, size=[10, 4], verbosity=3): detselect(pilatus_name, suffix="_stats4_total") + def setDirectBeamROI_YF(self, size=[10, 4], verbosity=3): + """Update the ROI (stats4) for the direct beam on the Pilatus + detector. This (should) update correctly based on the current SAXSx, SAXSy. + + The size argument controls the size (in pixels) of the ROI itself + (in the format [width, height]). A size=[6,4] is reasonable. + The size is changed to [10, 4] for possible beam drift during a user run (changed at 08/16/17)""" + + if pilatus_name.name == "pilatus2M": + detector = self.SAXS + # These positions are updated based on current detector position + det_md = detector.get_md() + x0 = det_md["detector_SAXS_x0_pix"] + y0 = det_md["detector_SAXS_y0_pix"] + if pilatus_name.name == "pilatus800": + detector = self.WAXS + + # These positions are updated based on current detector position + det_md = detector.get_md() + x0 = det_md["detector_WAXS_x0_pix"] + y0 = det_md["detector_WAXS_y0_pix"] + + # caput('XF:11BMB-ES{Det:SAXS}:ROI4:MinX', int(x0-size[0]/2)) + # caput('XF:11BMB-ES{Det:SAXS}:ROI4:SizeX', int(size[0])) + # caput('XF:11BMB-ES{Det:SAXS}:ROI4:MinY', int(y0-size[1]/2)) + # caput('XF:11BMB-ES{Det:SAXS}:ROI4:SizeY', int(size[1])) + + # detselect(pilatus300, suffix='_stats4_total') + + yield from bps.mov(pilatus_name.roi4.min_xyz.min_x, int(x0 - size[0] / 2)) + yield from bps.mov(pilatus_name.roi4.size.x, int(size[0])) + yield from bps.mov(pilatus_name.roi4.min_xyz.min_y, int(y0 - size[0] / 2)) + yield from bps.mov(pilatus_name.roi4.size.y, int(size[1])) + + # caput('XF:11BMB-ES{}:ROI4:MinX'.format(pilatus_Epicsname), int(x0-size[0]/2)) + # caput('XF:11BMB-ES{}:ROI4:SizeX'.format(pilatus_Epicsname), int(size[0])) + # caput('XF:11BMB-ES{}:ROI4:MinY'.format(pilatus_Epicsname), int(y0-size[1]/2)) + # caput('XF:11BMB-ES{}:ROI4:SizeY'.format(pilatus_Epicsname), int(size[1])) + + detselect(pilatus_name, suffix="_stats4_total") + def setReflectedBeamROI(self, total_angle=0.16, size=[10, 2], verbosity=3): """Update the ROI (stats3) for the reflected beam on the Pilatus300k detector. This (should) update correctly based on the current SAXSx, SAXSy. @@ -3247,7 +3532,7 @@ def setReflectedBeamROI(self, total_angle=0.16, size=[10, 2], verbosity=3): if pilatus_name.name == "pilatus2M": detector = self.SAXS # These positions are updated based on current detector position - det_md = detector.get_md() + det_md = yield from detector.get_md() x0 = det_md["detector_SAXS_x0_pix"] y0 = det_md["detector_SAXS_y0_pix"] if pilatus_name.name == "pilatus800": @@ -3300,14 +3585,14 @@ def setROI2ReflectBeamROI(self, total_angle=0.16, size=[10, 100], verbosity=3): if pilatus_name.name == "pilatus2M": detector = self.SAXS # These positions are updated based on current detector position - det_md = detector.get_md() + det_md = yield from detector.get_md() x0 = det_md["detector_SAXS_x0_pix"] y0 = det_md["detector_SAXS_y0_pix"] if pilatus_name.name == "pilatus800": detector = self.WAXS # These positions are updated based on current detector position - det_md = detector.get_md() + det_md = yield from detector.get_md() x0 = det_md["detector_WAXS_x0_pix"] y0 = det_md["detector_WAXS_y0_pix"] @@ -3447,6 +3732,117 @@ def setSpecularReflectivityROI(self, total_angle=0.16, size=[10, 10], default_SA detselect(pilatus_name, suffix="_stats1_total") + def setSpecularReflectivityROI_YF(self, total_angle=0.16, size=[10, 10], default_SAXSy=None, verbosity=3): + """Update the ROIs (stats1, stats2) for the specular reflected beam on the Pilatus + detector. This (should) update correctly based on the current SAXSx, SAXSy. + + The size argument controls the size (in pixels) of the ROI itself + (in the format [width, height]). + + stats1 is centered on the specular reflected beam and has the size specified in + the size argument. + + stats2 is centered on the specular reflected beam and has the size that is twice + as wide as specified in the size argument, for capturing background. + + The background-subtracted intensity for specular reflection is equal to: + 2 * stats1 - stats2 + """ + + detector = self.SAXS + # self.setMonitor() + + if default_SAXSy is not None: + if abs(default_SAXSy - SAXSy.position) > 0.01: + SAXSy.move(default_SAXSy) + print("SAXS detector has been shifted to default SAXSy = {:.3f} mm.".format(SAXSy.position)) + + # These positions are updated based on current detector position + det_md = detector.get_md() + x0 = det_md["detector_SAXS_x0_pix"] + y0 = det_md["detector_SAXS_y0_pix"] + + d = detector.distance * 1000.0 # mm + pixel_size = detector.pixel_size # mm + + y_offset_mm = np.tan(np.radians(total_angle)) * d + y_offset_pix = y_offset_mm / pixel_size + + # for pilatus800k + if pilatus_name.name == "pilatus800": + y_pos = int(y0 - size[1] / 2 - y_offset_pix) + + # for pilatus2M, placed up-side down + # y_pos = int( y0 - size[1]/2 + y_offset_pix ) + + # for pilatus2M, with pattern rotated 180deg. changed at 052918 + if pilatus_name.name == "pilatus2M": + y_pos = int(y0 - size[1] / 2 - y_offset_pix) + + # y pixels for intermodule gaps, for pilatus2M (195 pixels high module, 17 pixels high gap) + y_gap_2M = [] + for i in np.arange(7): + for j in np.arange(17): + y_gap_2M.append((195 + 17) * (i + 1) - 17 + j) + + # y pixels for Spectular Reflectivity ROI + y_roi = [] + for i in np.arange(int(size[1] + 1)): + y_roi.append(y_pos + i) + + # flag for whether the ROI falls on intermodule gap + flag_ROIonGap = len(np.unique(y_gap_2M + y_roi)) < (len(y_gap_2M) + len(y_roi)) + + # Move SAXSy if ROI falls on intermodule gap; if not, move on + if flag_ROIonGap == True: + y_shift = 17 + size[1] + 1 # intermodule gap is 17 pixels high + y_shift_mm = pixel_size * y_shift # mm + SAXSy.move(SAXSy.position + y_shift_mm) + print( + "SAXS detector has been shifted to SAXSy = {:.3f} mm (by {:.3f} mm or {} pixels) to avoid a gap.".format( + SAXSy.position, y_shift_mm, y_shift + ) + ) + + # These positions are updated based on current detector position + det_md = detector.get_md() + x0 = det_md["detector_SAXS_x0_pix"] + y0 = det_md["detector_SAXS_y0_pix"] + + ##for pilatus2M, placed up-side down + # y_pos = int( y0 - size[1]/2 + y_offset_pix ) + + # for pilatus2M, with pattern rotated 180deg. changed at 052918 + y_pos = int(y0 - size[1] / 2 - y_offset_pix) + + # caput('XF:11BMB-ES{Det:SAXS}:ROI3:MinX', int(x0-size[0]/2)) + # caput('XF:11BMB-ES{Det:SAXS}:ROI3:SizeX', int(size[0])) + # caput('XF:11BMB-ES{Det:SAXS}:ROI3:MinY', y_pos) + # caput('XF:11BMB-ES{Det:SAXS}:ROI3:SizeY', int(size[1])) + + # detselect(pilatus300, suffix='_stats3_total') + + # ROI1: Raw signal + # caput('XF:11BMB-ES{}:ROI1:MinX'.format(pilatus_Epicsname), int(x0-size[0]/2)) + # caput('XF:11BMB-ES{}:ROI1:SizeX'.format(pilatus_Epicsname), int(size[0])) + # caput('XF:11BMB-ES{}:ROI1:MinY'.format(pilatus_Epicsname), y_pos) + # caput('XF:11BMB-ES{}:ROI1:SizeY'.format(pilatus_Epicsname), int(size[1])) + yield from bps.mov(pilatus_name.roi1.min_xyz.min_x, int(x0 - size[0] / 2)) + yield from bps.mov(pilatus_name.roi1.size.x, int(size[0])) + yield from bps.mov(pilatus_name.roi1.min_xyz.min_y, y_pos) + yield from bps.mov(pilatus_name.roi1.size.y, int(size[1])) + + # ROI2: Raw signal+background (same as ROI1 for y, but twice as large for x) + # caput('XF:11BMB-ES{}:ROI2:MinX'.format(pilatus_Epicsname), int(x0-size[0])) + # caput('XF:11BMB-ES{}:ROI2:SizeX'.format(pilatus_Epicsname), int(2*size[0])) + # caput('XF:11BMB-ES{}:ROI2:MinY'.format(pilatus_Epicsname), y_pos) + # caput('XF:11BMB-ES{}:ROI2:SizeY'.format(pilatus_Epicsname), int(size[1])) + yield from bps.mov(pilatus_name.roi2.min_xyz.min_x, int(x0 - size[0] / 2)) + yield from bps.mov(pilatus_name.roi2.size.x, int(2 * size[0])) + yield from bps.mov(pilatus_name.roi2.min_xyz.min_y, y_pos) + yield from bps.mov(pilatus_name.roi2.size.y, int(size[1])) + detselect(pilatus_name, suffix="_stats1_total") + def setSpecularReflectivityROI_SAXSyPOS( self, total_angle=0.16, size=[10, 10], default_SAXSy=None, verbosity=3 ): @@ -3686,7 +4082,7 @@ def modeXRMeasurement(self, verbosity=3): self.definePos(size=[10, 4]) # Check if gate valves are open - if self.beam.GVdsbig.state() is not "out" and verbosity >= 1: + if self.beam.GVdsbig.state() != "out" and verbosity >= 1: print("Warning: Sample chamber gate valve (large, downstream) is not open.") def modeXRAlignment(self, verbosity=3): @@ -3732,8 +4128,7 @@ def setDirectBeamROI_WAXS(self, size=[10, 4], verbosity=3): The size argument controls the size (in pixels) of the ROI itself (in the format [width, height]). A size=[6,4] is reasonable. - The size is changed to [10, 4] for possible beam drift during a user run (changed at 08/16/17) - """ + The size is changed to [10, 4] for possible beam drift during a user run (changed at 08/16/17)""" detector = self.WAXS @@ -3882,7 +4277,7 @@ def setXRROI_WAXSy(self, total_angle=0.16, size=[10, 10], default_WAXSy=None, ve for i in np.arange(int(size[1] + 1)): y_roi.append(y_pos + i) - # flag for whether the ROI falls on intermodule gap + # flag for whether the ROI falls on intermodule gap k flag_ROIonGap = len(np.unique(y_gap_800 + y_roi)) < (len(y_gap_800) + len(y_roi)) # Move SAXSy if ROI falls on intermodule gap; if not, move on diff --git a/startup/90-bluesky.py b/startup/90-bluesky.py index 6331891..b67d322 100644 --- a/startup/90-bluesky.py +++ b/startup/90-bluesky.py @@ -1,3 +1,6 @@ +print(f"Loading {__file__!r} ...") + + def detselect(detector_object, suffix="_stats4_total"): """Switch the active detector and set some internal state""" @@ -24,9 +27,6 @@ def detselect(detector_object, suffix="_stats4_total"): ##### I/O devices -from epics import caget, caput - - def pneumatic(inout, pv_r, pv_in, pv_out, ss1, quiet): if inout == 1: caput(pv_in, 1) @@ -337,6 +337,7 @@ def pump_chm(onoff, q=0): pv_w = "XF:11BMB-VA{Chm:Det-Pmp:1}Cmd:Enbl-Cmd" if onoff == 1: caput(pv_w, 0) + yield from bps.mv(EpicsSignal(pv_w)) time.sleep(0.2) caput(pv_w, 1) ss = "Chamber pump has been turned ON" @@ -352,9 +353,7 @@ def pump_chm(onoff, q=0): print(ss) -# PROFILE_ROOT = os.path.dirname(__file__) -# PROFILE_ROOT = '/nsls2/data/cms/legacy/xf11bm/ipython_profiles/profile_collection/startup' -PROFILE_ROOT = "/home/xf11bm/.ipython/profile_collection/startup" +PROFILE_ROOT = os.path.dirname(__file__) CMS_CONFIG_FILENAME = os.path.join(PROFILE_ROOT, ".cms_config") ## CMS config file @@ -387,7 +386,7 @@ def config_update(): # load the previous config file cms_config = pds.read_csv(CMS_CONFIG_FILENAME, index_col=0) - cms_config_update = pds.concat([cms_config, current_config_DF], ignore_index=True) + cms_config_update = cms_config.append(current_config_DF, ignore_index=True) # save to file cms_config_update.to_csv(CMS_CONFIG_FILENAME) @@ -435,10 +434,7 @@ def data_output(experiment_cycle=None, experiment_alias_directory=None): # headers = db(experiment_cycle='2017_3', experiment_group= 'I. Herman (Columbia U.) group', experiment_alias_directory='/nsls2/xf11bm/data/2017_3/IHerman' ) if experiment_cycle is not None: - headers = db( - experiment_cycle=experiment_cycle, - experiment_alias_directory=experiment_alias_directory, - ) + headers = db(experiment_cycle=experiment_cycle, experiment_alias_directory=experiment_alias_directory) else: headers = db(experiment_alias_directory=experiment_alias_directory) @@ -446,8 +442,7 @@ def data_output(experiment_cycle=None, experiment_alias_directory=None): dtable = header.table() dtable.to_csv( "{}/data/{}.csv".format( - header.get("start").get("experiment_alias_directory"), - header.get("start").get("scan_id"), + header.get("start").get("experiment_alias_directory"), header.get("start").get("scan_id") ) ) @@ -490,8 +485,7 @@ def data_output_seires(id_range): dtable = header.table() dtable.to_csv( "{}/data/{}.csv".format( - header.get("start").get("experiment_alias_directory"), - header.get("start").get("scan_id"), + header.get("start").get("experiment_alias_directory"), header.get("start").get("scan_id") ) ) @@ -531,8 +525,7 @@ def metadata_output(output_file, SAF=None, experiment_alias_directory=None): } current = pds.DataFrame(data=current_data, index=[1]) - # output_data = output_data.append(current_data, ignore_index=True) - output_data = pds.concat([output_data, current_data], ignore_index=True) + output_data = output_data.append(current_data, ignore_index=True) # output_data = output_data.iloc[0:0] diff --git a/startup/91-fit_scan.py b/startup/91-fit_scan.py index 85c6d49..f6a1721 100644 --- a/startup/91-fit_scan.py +++ b/startup/91-fit_scan.py @@ -1,3 +1,5 @@ +print(f"Loading {__file__!r} ...") + # Classes and functions to make it easy to do a dscan with realtime fitting to # a custom function. @@ -195,7 +197,7 @@ def update_fit(self, stat): xs = np.asarray(self.xdata) ys = np.asarray(self.ydata) - if stat is "max": + if stat == "max": idx = np.argmax(ys) x0 = xs[idx] y0 = ys[idx] @@ -203,7 +205,7 @@ def update_fit(self, stat): self.result.values["x_max"] = x0 self.result.values["y_max"] = y0 - elif stat is "min": + elif stat == "min": idx = np.argmin(ys) x0 = xs[idx] y0 = ys[idx] @@ -211,14 +213,14 @@ def update_fit(self, stat): self.result.values["x_min"] = x0 self.result.values["y_min"] = y0 - elif stat is "COM": + elif stat == "COM": x0 = np.sum(xs * ys) / np.sum(ys) y0 = np.interp(x0, xs, ys) self.result.values["x_COM"] = x0 self.result.values["y_COM"] = y0 - elif stat is "HM": + elif stat == "HM": """Half-maximum, using the point(s) closest to HM.""" idx_max = np.argmax(ys) half_max = 0.5 * ys[idx_max] @@ -250,7 +252,7 @@ def update_fit(self, stat): self.result.values["x_HM"] = x0 self.result.values["y_HM"] = y0 - elif stat is "HMi": + elif stat == "HMi": """Half-maximum, with averaging of values near HW.""" idx_max = np.argmax(ys) half_max = 0.5 * ys[idx_max] @@ -291,17 +293,7 @@ def update_fit(self, stat): class LiveStatPlot(LivePlot): - def __init__( - self, - livestat, - *, - scan_range=None, - legend_keys=None, - xlim=None, - ylim=None, - ax=None, - **kwargs, - ): + def __init__(self, livestat, *, scan_range=None, legend_keys=None, xlim=None, ylim=None, ax=None, **kwargs): kwargs_update = { "color": "b", "linewidth": 0, @@ -311,13 +303,7 @@ def __init__( kwargs_update.update(kwargs) super().__init__( - livestat.y_name, - livestat.x_name, - legend_keys=legend_keys, - xlim=xlim, - ylim=xlim, - ax=ax, - **kwargs_update, + livestat.y_name, livestat.x_name, legend_keys=legend_keys, xlim=xlim, ylim=xlim, ax=ax, **kwargs_update ) self.livestat = livestat @@ -390,18 +376,7 @@ def stop(self, doc): class LivePlot_Custom(LivePlot): - def __init__( - self, - y, - x=None, - *, - legend_keys=None, - xlim=None, - ylim=None, - ax=None, - fig=None, - **kwargs, - ): + def __init__(self, y, x=None, *, legend_keys=None, xlim=None, ylim=None, ax=None, fig=None, **kwargs): kwargs_update = { "color": "k", "linewidth": 3.5, @@ -422,16 +397,7 @@ def __init__( # For more rcParam options: http://matplotlib.org/users/customizing.html plt.matplotlib.rcParams.update(rcParams_update) - super().__init__( - y, - x, - legend_keys=legend_keys, - xlim=xlim, - ylim=ylim, - ax=ax, - fig=fig, - **kwargs_update, - ) + super().__init__(y, x, legend_keys=legend_keys, xlim=xlim, ylim=ylim, ax=ax, fig=fig, **kwargs_update) # super().setup() # self.ax.figure.canvas.manager.toolbar.pan() @@ -529,31 +495,14 @@ class LiveFitPlot_Custom(LiveFitPlot): All additional keyword arguments are passed through to ``Axes.plot``. """ - def __init__( - self, - livefit, - *, - legend_keys=None, - xlim=None, - ylim=None, - ax=None, - scan_range=None, - **kwargs, - ): + def __init__(self, livefit, *, legend_keys=None, xlim=None, ylim=None, ax=None, scan_range=None, **kwargs): kwargs_update = { "color": "b", "linewidth": 2.5, } kwargs_update.update(kwargs) - super().__init__( - livefit, - legend_keys=legend_keys, - xlim=xlim, - ylim=ylim, - ax=ax, - **kwargs_update, - ) + super().__init__(livefit, legend_keys=legend_keys, xlim=xlim, ylim=ylim, ax=ax, **kwargs_update) self.y_guess = 0 self.scan_range = scan_range @@ -639,15 +588,7 @@ class LiveFit_Custom(LiveFit): result : lmfit.ModelResult """ - def __init__( - self, - model_name, - y, - independent_vars, - scan_range, - update_every=1, - background=None, - ): + def __init__(self, model_name, y, independent_vars, scan_range, update_every=1, background=None): self.x_start = min(scan_range) self.x_stop = max(scan_range) self.x_span = abs(self.x_stop - self.x_start) @@ -676,33 +617,27 @@ def __init__( lm_model += self.get_model(background) init_guess.update(self.get_initial_guess(background)) - super().__init__( - lm_model, - y, - independent_vars, - init_guess=init_guess, - update_every=update_every, - ) + super().__init__(lm_model, y, independent_vars, init_guess=init_guess, update_every=update_every) def get_model(self, model_name): - if model_name is "gauss": + if model_name == "gauss": def model_function(x, x0, prefactor, sigma): return prefactor * np.exp(-((x - x0) ** 2) / (2 * sigma**2)) - elif model_name is "lorentz": + elif model_name == "lorentz": def model_function(x, x0, prefactor, gamma): return prefactor * (gamma**2) / ((x - x0) ** 2 + (gamma**2)) - elif model_name is "doublesigmoid": + elif model_name == "doublesigmoid": def model_function(x, x0, prefactor, sigma, fwhm): left = prefactor / (1 + np.exp(-(x - (x0 - fwhm * 0.5)) / sigma)) right = prefactor / (1 + np.exp(-(x - (x0 + fwhm * 0.5)) / sigma)) return prefactor * (left - right) - elif model_name is "square": + elif model_name == "square": def model_function(x, x0, prefactor, fwhm): sigma = fwhm * 0.02 @@ -710,54 +645,54 @@ def model_function(x, x0, prefactor, fwhm): right = prefactor / (1 + np.exp(-(x - (x0 + fwhm * 0.5)) / sigma)) return prefactor * (left - right) - elif model_name is "sigmoid": + elif model_name == "sigmoid": def model_function(x, x0, prefactor, sigma): return prefactor / (1 + np.exp(-(x - x0) / sigma)) - elif model_name is "sigmoid_r": + elif model_name == "sigmoid_r": def model_function(x, x0, prefactor, sigma): return prefactor / (1 + np.exp(+(x - x0) / sigma)) - elif model_name is "step": + elif model_name == "step": def model_function(x, x0, prefactor, sigma): return prefactor / (1 + np.exp(-(x - x0) / sigma)) - elif model_name is "step_r": + elif model_name == "step_r": def model_function(x, x0, prefactor, sigma): return prefactor / (1 + np.exp(+(x - x0) / sigma)) - elif model_name is "tanh": + elif model_name == "tanh": def model_function(x, x0, prefactor, sigma): return prefactor * 0.5 * (np.tanh((x - x0) / sigma) + 1.0) - elif model_name is "tanh_r": + elif model_name == "tanh_r": def model_function(x, x0, prefactor, sigma): return prefactor * 0.5 * (np.tanh(-(x - x0) / sigma) + 1.0) - elif model_name is "erf": + elif model_name == "erf": import scipy def model_function(x, x0, prefactor, sigma): return prefactor * 0.5 * (scipy.special.erf((x - x0) / sigma) + 1.0) - elif model_name is "erf_r": + elif model_name == "erf_r": import scipy def model_function(x, x0, prefactor, sigma): return prefactor * 0.5 * (scipy.special.erf(-(x - x0) / sigma) + 1.0) - elif model_name is "constant": + elif model_name == "constant": def model_function(x, offset): return x * 0 + offset - elif model_name is "linear": + elif model_name == "linear": def model_function(x, m, b): return m * x + b @@ -973,7 +908,7 @@ def fit_scan( fig = plt.figure(figsize=(11, 7), facecolor="white") fig.canvas.manager.toolbar.pan() - fig.canvas.manager.set_window_title(title) + # fig.canvas.set_window_title(title) ax = fig.gca() subs = [] @@ -998,13 +933,7 @@ def fit_scan( # Perform a fit # livefit = LiveFit(lm_model, plot_y, {'x': motor.name}, init_guess) - livefit = LiveFit_Custom( - fit, - plot_y, - {"x": motor.name}, - scan_range=[start, stop], - background=background, - ) + livefit = LiveFit_Custom(fit, plot_y, {"x": motor.name}, scan_range=[start, stop], background=background) # livefitplot = LiveFitPlot(livefit, color='k') livefitplot = LiveFitPlot_Custom(livefit, ax=ax, scan_range=[start, stop]) @@ -1061,15 +990,7 @@ def fit_scan( def fit_edge( - motor, - span, - num=11, - detectors=None, - detector_suffix="", - plot=True, - toggle_beam=True, - wait_time=None, - md={}, + motor, span, num=11, detectors=None, detector_suffix="", plot=True, toggle_beam=True, wait_time=None, md={} ): """ Optimized fit_scan for finding a (decreasing) step-edge. @@ -1125,7 +1046,7 @@ def fit_edge( title = "fit_scan: {} vs. {}".format(detectors[0].name, motor.name) fig = None for i in plt.get_fignums(): - title_cur = plt.figure(i).canvas.manager.window.windowTitle() + # title_cur = plt.figure(i).canvas.manager.window.windowTitle() if title_cur == title: fig = plt.figure(i) break @@ -1136,7 +1057,7 @@ def fit_edge( fig = plt.figure(figsize=(11, 7), facecolor="white") fig.canvas.manager.toolbar.pan() - fig.canvas.manager.set_window_title(title) + # fig.canvas.set_window_title(title) ax = fig.gca() liveplot = LivePlot_Custom(plot_y, motor.name, ax=ax) @@ -1224,9 +1145,7 @@ def func2minimize(params, x, data): if plot: xe = 0.25 fit_x = np.linspace( - np.min(livetable.xdata) - xe * x_span, - np.max(livetable.xdata) + xe * x_span, - num=500, + np.min(livetable.xdata) - xe * x_span, np.max(livetable.xdata) + xe * x_span, num=500 ) fit_y = model(lm_result.params.valuesdict(), fit_x) # liveplot.add_line(fit_x, fit_y, color='b', linewidth=2.5) @@ -1336,7 +1255,7 @@ def _test_fit_scan( fig = plt.figure(figsize=(11, 7), facecolor="white") fig.canvas.manager.toolbar.pan() - fig.canvas.manager.set_window_title(title) + fig.canvas.set_window_title(title) ax = fig.gca() subs = [] @@ -1361,13 +1280,7 @@ def _test_fit_scan( # Perform a fit # livefit = LiveFit(lm_model, plot_y, {'x': motor.name}, init_guess) - livefit = LiveFit_Custom( - fit, - plot_y, - {"x": motor.name}, - scan_range=[start, stop], - background=background, - ) + livefit = LiveFit_Custom(fit, plot_y, {"x": motor.name}, scan_range=[start, stop], background=background) # livefitplot = LiveFitPlot(livefit, color='k') livefitplot = LiveFitPlot_Custom(livefit, ax=ax, scan_range=[start, stop]) diff --git a/startup/92-magics.py b/startup/92-magics.py index 7b2230e..42497e7 100644 --- a/startup/92-magics.py +++ b/startup/92-magics.py @@ -1,3 +1,5 @@ +print(f"Loading {__file__!r} ...") + # BlueskyMagics were imported and registered in 00-startup.py BlueskyMagics.detectors = [pilatus2M] diff --git a/startup/93-supplemental-data.py b/startup/93-supplemental-data.py index bd9d547..87224d1 100644 --- a/startup/93-supplemental-data.py +++ b/startup/93-supplemental-data.py @@ -1 +1,3 @@ +print(f"Loading {__file__!r} ...") + sd.baseline = [] diff --git a/startup/94-sample.py b/startup/94-sample.py index d66c90c..e2170c6 100644 --- a/startup/94-sample.py +++ b/startup/94-sample.py @@ -2,6 +2,8 @@ # -*- coding: utf-8 -*- # vi: ts=4 sw=4 +print(f"Loading {__file__!r} ...") + ################################################################################ # Code for defining a 'Sample' object, which keeps track of its state, and # simplifies the task of aligning, measuring, etc. @@ -174,10 +176,7 @@ def multiple_string_replacements(self, text, replacements, word_boundaries=False if word_boundaries: replacements = dict((r"\b" + re.escape(k.lower()) + r"\b", v) for k, v in replacements.items()) pattern = re.compile("|".join(replacements.keys()), re.IGNORECASE) - text = pattern.sub( - lambda m: replacements[r"\b" + re.escape(m.group(0).lower()) + r"\b"], - text, - ) + text = pattern.sub(lambda m: replacements[r"\b" + re.escape(m.group(0).lower()) + r"\b"], text) else: replacements = dict((re.escape(k.lower()), v) for k, v in replacements.items()) @@ -848,11 +847,7 @@ def search( if verbosity >= 3: print( " {} = {:.3f} {}; value : {} ({:.1f}%)".format( - self.name, - self.get_position(verbosity=0), - self.units, - value, - 100.0 * value / intensity, + self.name, self.get_position(verbosity=0), self.units, value, 100.0 * value / intensity ) ) @@ -873,211 +868,6 @@ def search( bec.enable_table() - def search_plan( - self, - motor=smy, - step_size=1.0, - min_step=0.05, - intensity=None, - target=0.5, - detector=None, - detector_suffix=None, - polarity=+1, - fastsearch=False, - verbosity=3, - ): - """Moves this axis, searching for a target value. - - Parameters - ---------- - step_size : float - The initial step size when moving the axis - min_step : float - The final (minimum) step size to try - intensity : float - The expected full-beam intensity readout - target : 0.0 to 1.0 - The target ratio of full-beam intensity; 0.5 searches for half-max. - The target can also be 'max' to find a local maximum. - detector, detector_suffix - The beamline detector (and suffix, such as '_stats4_total') to trigger to measure intensity - polarity : +1 or -1 - Positive motion assumes, e.g. a step-height 'up' (as the axis goes more positive) - """ - - @stage_decorator([detector]) - def inner_search(): - if not get_beamline().beam.is_on(): - print("WARNING: Experimental shutter is not open.") - - if intensity is None: - intensity = RE.md["beam_intensity_expected"] - - if detector is None: - # detector = gs.DETS[0] - detector = get_beamline().detector[0] - if detector_suffix is None: - # value_name = gs.TABLE_COLS[0] - value_name = get_beamline().TABLE_COLS[0] - else: - value_name = detector.name + detector_suffix - - bec.disable_table() - - # Check current value - yield from bps.trigger_and_read([detector]) - # RE(count([detector])) - value = detector.read()[value_name]["value"] - - if fastsearch == True: - intenisty_threshold = 10 - if ( - abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) < 20 - and detector.stats2.max_value.get() > intenisty_threshold - ): - # continue the fast alignment - print("The reflective beam is found! Continue the fast alignment") - return - - if target == "max": - if verbosity >= 5: - print("Performing search on axis '{}' target is 'max'".format(self.name)) - - max_value = value - max_position = self.get_position(verbosity=0) - - direction = +1 * polarity - - while step_size >= min_step: - if verbosity >= 4: - print(" move {} by {} × {}".format(self.name, direction, step_size)) - - pos = yield from bps.rd(motor) - yield from bps.mv(motor, pos + direction * step_size) - # self.move_relative(move_amount=direction*step_size, verbosity=verbosity-2) - - prev_value = value - yield from bps.trigger_and_read([detector]) - # RE(count([detector])) - - value = detector.read()[value_name]["value"] - if verbosity >= 3: - print( - " {} = {:.3f} {}; value : {}".format( - self.name, - self.get_position(verbosity=0), - self.units, - value, - ) - ) - - if value > max_value: - max_value = value - # max_position = self.get_position(verbosity=0) - - if value > prev_value: - # Keep going in this direction... - pass - else: - # Switch directions! - direction *= -1 - step_size *= 0.5 - - elif target == "min": - if verbosity >= 5: - print("Performing search on axis '{}' target is 'min'".format(self.name)) - - direction = +1 * polarity - - while step_size >= min_step: - if verbosity >= 4: - print(" move {} by {} × {}".format(self.name, direction, step_size)) - - pos = yield from bps.rd(motor) - yield from bps.mv(motor, pos + direction * step_size) - # self.move_relative(move_amount=direction*step_size, verbosity=verbosity-2) - - prev_value = value - RE(count([detector])) - value = detector.read()[value_name]["value"] - if verbosity >= 3: - print( - " {} = {:.3f} {}; value : {}".format( - self.name, - self.get_position(verbosity=0), - self.units, - value, - ) - ) - - if value < prev_value: - # Keep going in this direction... - pass - else: - # Switch directions! - direction *= -1 - step_size *= 0.5 - - else: - target_rel = target - target = target_rel * intensity - - if verbosity >= 5: - print( - "Performing search on axis '{}' target {} × {} = {}".format( - self.name, target_rel, intensity, target - ) - ) - if verbosity >= 4: - print(" value : {} ({:.1f}%)".format(value, 100.0 * value / intensity)) - - # Determine initial motion direction - if value > target: - direction = -1 * polarity - else: - direction = +1 * polarity - - while step_size >= min_step: - if verbosity >= 4: - print(" move {} by {} × {}".format(self.name, direction, step_size)) - - pos = yield from bps.rd(motor) - yield from bps.mv(motor, pos + direction * step_size) - # self.move_relative(move_amount=direction*step_size, verbosity=verbosity-2) - - yield from bps.trigger_and_read([detector]) - # RE(count([detector])) - value = detector.read()[value_name]["value"] - if verbosity >= 3: - print( - " {} = {:.3f} {}; value : {} ({:.1f}%)".format( - self.name, - self.get_position(verbosity=0), - self.units, - value, - 100.0 * value / intensity, - ) - ) - - # Determine direction - if value > target: - new_direction = -1.0 * polarity - else: - new_direction = +1.0 * polarity - - if abs(direction - new_direction) < 1e-4: - # Same direction as we've been going... - # ...keep moving this way - pass - else: - # Switch directions! - direction *= -1 - step_size *= 0.5 - - bec.enable_table() - - yield from inner_search() - def _search( self, step_size=1.0, @@ -1231,11 +1021,7 @@ def _search( if verbosity >= 3: print( " {} = {:.3f} {}; value : {} ({:.1f}%)".format( - self.name, - self.get_position(verbosity=0), - self.units, - value, - 100.0 * value / intensity, + self.name, self.get_position(verbosity=0), self.units, value, 100.0 * value / intensity ) ) @@ -1360,6 +1146,21 @@ def __init__(self, name, base=None, **md): # if base is not None: # base.addSample(self) + # Signals + self.xf_11bmb_es_det_saxs_cam1_filenumber_rbv = EpicsSignalRO("XF:11BMB-ES{Det:SAXS}:cam1:FileNumber_RBV") + self.xf_11bmb_es_det_pil2m_cam1_filenumber_rbv = EpicsSignalRO( + "XF:11BMB-ES{Det:PIL2M}:cam1:FileNumber_RBV" + ) + + self.xf_11bm_es_env_01_out_1_t_sp = EpicsSignal("XF:11BM-ES{Env:01-Out:1}T-SP") + self.xf_11bm_es_env_01_out_2_t_sp = EpicsSignal("XF:11BM-ES{Env:01-Out:2}T-SP") + self.xf_11bm_es_env_01_out_3_t_sp = EpicsSignal("XF:11BM-ES{Env:01-Out:3}T-SP") + self.xf_11bm_es_env_01_out_4_t_sp = EpicsSignal("XF:11BM-ES{Env:01-Out:4}T-SP") + self.xf_11bm_es_env_01_chan_a_t_c_i = EpicsSignalRO("XF:11BM-ES{Env:01-Chan:A}T:C-I") + self.xf_11bm_es_env_01_chan_b_t_c_i = EpicsSignalRO("XF:11BM-ES{Env:01-Chan:B}T:C-I") + self.xf_11bm_es_env_01_chan_c_t_c_i = EpicsSignalRO("XF:11BM-ES{Env:01-Chan:C}T:C-I") + self.xf_11bm_es_env_01_chan_d_t_c_i = EpicsSignalRO("XF:11BM-ES{Env:01-Chan:D}T:C-I") + self.reset_clock() def _set_axes_definitions(self): @@ -1479,9 +1280,6 @@ def get_attribute(self, attribute): return SAXSy.position if attribute == "SAXSx": return SAXSx.position - # if attribute=='temperature_Linkam': - # # return caget('XF:11BM-ES:{LINKAM}:TEMP') - # return LThermal.temperature() if attribute in self.md: return self.md[attribute] if attribute == "energy": @@ -1559,11 +1357,11 @@ def get_md(self, prefix="sample_", include_marks=True, **md): # Add md that varies over time md_return["clock"] = self.clock() - md_return["temperature"] = self.temperature(temperature_probe="A", verbosity=0) - md_return["temperature_A"] = self.temperature(temperature_probe="A", verbosity=0) - md_return["temperature_B"] = self.temperature(temperature_probe="B", verbosity=0) - md_return["temperature_C"] = self.temperature(temperature_probe="C", verbosity=0) - md_return["temperature_D"] = self.temperature(temperature_probe="D", verbosity=0) + md_return["temperature"] = yield from self.temperature(temperature_probe="A", verbosity=0) + md_return["temperature_A"] = yield from self.temperature(temperature_probe="A", verbosity=0) + md_return["temperature_B"] = yield from self.temperature(temperature_probe="B", verbosity=0) + md_return["temperature_C"] = yield from self.temperature(temperature_probe="C", verbosity=0) + md_return["temperature_D"] = yield from self.temperature(temperature_probe="D", verbosity=0) # md_return['temperature_E'] = self.temperature(temperature_probe='E', verbosity=0) # md_return['humidity'] = self.humidity(verbosity=0) @@ -1737,21 +1535,29 @@ def setTemperature(self, temperature, verbosity=3): def temperature(self, verbosity=3): return self.base_stage.temperature(verbosity=verbosity) + def max_exposure_time(self): + exposure_times = [] + for detector in get_beamline().detector: + exposure_time = yield from bps.rd(detector.cam.acquire_time) + exposure_times.append(exposure_time) + if not exposure_times: + return 0.1 + else: + return max(0.01, max(exposure_times)) + # Measurement methods ######################################## def get_measurement_md(self, prefix=None, **md): - # md_current = {} md_current = {k: v for k, v in RE.md.items()} # Global md - # md_current['detector_sequence_ID'] = caget('XF:11BMB-ES{Det:SAXS}:cam1:FileNumber_RBV') - # md_current['detector_sequence_ID'] = caget('XF:11BMB-ES{}:cam1:FileNumber_RBV'.format(pilatus_Epicsname)) - if get_beamline().detector[0].name is "pilatus300": - md_current["detector_sequence_ID"] = caget("XF:11BMB-ES{Det:SAXS}:cam1:FileNumber_RBV") - elif get_beamline().detector[0].name is "pilatus2M": - md_current["detector_sequence_ID"] = caget("XF:11BMB-ES{Det:PIL2M}:cam1:FileNumber_RBV") + if get_beamline().detector[0].name == "pilatus300": + md_current["detector_sequence_ID"] = yield from bps.rd(self.xf_11bmb_es_det_saxs_cam1_filenumber_rbv) + elif get_beamline().detector[0].name == "pilatus2M": + md_current["detector_sequence_ID"] = yield from bps.rd(self.xf_11bmb_es_det_pil2m_cam1_filenumber_rbv) - md_current.update(get_beamline().get_md()) + new_md = yield from get_beamline().get_md() + md_current.update(new_md) md_current.update(md) @@ -1766,53 +1572,44 @@ def _expose_manual(self, exposure_time=None, verbosity=3, poling_period=0.1, **m # TODO: Improve this (switch to Bluesky methods) # TODO: Store metadata - if "measure_type" not in md: md["measure_type"] = "expose" self.log("{} for {}.".format(md["measure_type"], self.name), **md) + detector = get_beamline().detector[0] + if exposure_time is not None: # Prep detector - # caput('XF:11BMB-ES{Det:SAXS}:cam1:AcquireTime', exposure_time) - # caput('XF:11BMB-ES{Det:SAXS}:cam1:AcquirePeriod', exposure_time+0.1) - # caput('XF:11BMB-ES{}:cam1:AcquireTime'.format(pilatus_Epicsname), exposure_time) - # caput('XF:11BMB-ES{}:cam1:AcquirePeriod'.format(pilatus_Epicsname), exposure_time+0.1) - - if get_beamline().detector[0].name is "pilatus300": - caput("XF:11BMB-ES{Det:SAXS}:cam1:AcquireTime", exposure_time) - caput("XF:11BMB-ES{Det:SAXS}:cam1:AcquirePeriod", exposure_time + 0.1) - elif get_beamline().detector[0].name is "pilatus2M": - caput("XF:11BMB-ES{Det:PIL2M}:cam1:AcquireTime", exposure_time) - caput("XF:11BMB-ES{Det:PIL2M}:cam1:AcquirePeriod", exposure_time + 0.1) + yield from bps.mv(detector.cam.acquire_time, exposure_time) + yield from bps.mv(detector.cam.acquire_period, exposure_time + 0.1) get_beamline().beam.on() # Trigger acquisition manually - caput("XF:11BMB-ES{}:cam1:Acquire".format(pilatus_Epicsname), 1) - + yield from bps.mv(detector.cam.acquire, 1) if verbosity >= 2: start_time = time.time() - while caget("XF:11BMB-ES{}:cam1:Acquire".format(pilatus_Epicsname)) == 1 and ( - time.time() - start_time - ) < (exposure_time + 20): + acquiring = yield from bps.rd(detector.cam.acquire) + while acquiring and (time.time() - start_time) < (exposure_time + 20): percentage = 100 * (time.time() - start_time) / exposure_time print( - "Exposing {:6.2f} s ({:3.0f}%) \r".format((time.time() - start_time), percentage), - end="", + "Exposing {:6.2f} s ({:3.0f}%) \r".format((time.time() - start_time), percentage), end="" ) time.sleep(poling_period) + acquiring = yield from bps.rd(detector.cam.acquire) else: time.sleep(exposure_time) - if verbosity >= 3 and caget("XF:11BMB-ES{}:cam1:Acquire".format(pilatus_Epicsname)) == 1: + acquiring = yield from bps.rd(detector.cam.acquire) + if verbosity >= 3 and acquiring: print("Warning: Detector still not done acquiring.") get_beamline().beam.off() + @bpp.finalize_decorator(final_plan=shutter_off) def expose(self, exposure_time=None, extra=None, handlefile=True, verbosity=3, poling_period=0.1, **md): """Internal function that is called to actually trigger a measurement.""" """TODO: **md doesnot work in RE(count). """ - if "measure_type" not in md: md["measure_type"] = "expose" # self.log('{} for {}.'.format(md['measure_type'], self.name), **md) @@ -1822,94 +1619,34 @@ def expose(self, exposure_time=None, extra=None, handlefile=True, verbosity=3, p exposure_time = abs(exposure_time) # for detector in gs.DETS: for detector in get_beamline().detector: - if ( - exposure_time != detector.cam.acquire_time.get() - ): # caget('XF:11BMB-ES{Det:PIL2M}:cam1:AcquireTime'): - RE(detector.setExposureTime(exposure_time, verbosity=verbosity)) - # if detector.name is 'pilatus800' and exposure_time != detector.cam.acquire_time.get(): #caget('XF:11BMB-ES{Det:PIL2M}:cam1:AcquireTime'): - # RE(detector.setExposureTime(exposure_time, verbosity=verbosity)) - # if detector.name is 'pilatus300' and exposure_time != detector.cam.acquire_time.get(): - # detector.setExposureTime(exposure_time, verbosity=verbosity) - ##extra wait time when changing the exposure time. - ##time.sleep(2) - ############################################# - ##extra wait time for adjusting pilatus2M - ##this extra wait time has to be added. Otherwise, the exposure will be skipped when the exposure time is increased - ##Note by 091918 - ############################################# - # time.sleep(2) - # elif detector.name is 'PhotonicSciences_CMS': - # detector.setExposureTime(exposure_time, verbosity=verbosity) + if exposure_time != detector.cam.acquire_time.get(): + yield from detector.setExposureTime(exposure_time, verbosity=verbosity) # Do acquisition - get_beamline().beam.on() + yield from shutter_on() + # get_beamline().beam.on() md["plan_header_override"] = md["measure_type"] start_time = time.time() - # md_current = self.get_md() - md["beam_int_bim3"] = beam.bim3.flux(verbosity=0) - md["beam_int_bim4"] = beam.bim4.flux(verbosity=0) - md["beam_int_bim5"] = beam.bim5.flux(verbosity=0) + # md_current = yield from self.get_md() + md["beam_int_bim3"] = yield from beam.bim3.flux(verbosity=0) + md["beam_int_bim4"] = yield from beam.bim4.flux(verbosity=0) + md["beam_int_bim5"] = yield from beam.bim5.flux(verbosity=0) # md['trigger_time'] = self.clock() # md.update(md_current) # uids = RE(count(get_beamline().detector, 1), **md) - uids = RE(count(get_beamline().detector), **md) + # uids = yield from count(get_beamline().detector + [core_laser, laser, laserx, lasery, smy, smx, sth, schi], md=md) + uids = yield from count(get_beamline().detector + [laserx, lasery, smy, smx, sth, schi], md=md) # yield from (count(get_beamline().detector), **md) # get_beamline().beam.off() # print('shutter is off') # Wait for detectors to be ready - max_exposure_time = 0.1 - for detector in get_beamline().detector: - if detector.name is "pilatus300": - current_exposure_time = detector.cam.acquire_time.get() - max_exposure_time = max(max_exposure_time, current_exposure_time) - elif detector.name is "pilatus2M": - current_exposure_time = detector.cam.acquire_time.get() - max_exposure_time = max(max_exposure_time, current_exposure_time) - elif detector.name is "pilatus800" or detector.name is "pilatus8002": - current_exposure_time = detector.cam.acquire_time.get() - max_exposure_time = max(max_exposure_time, current_exposure_time) - - # if detector.name is 'pilatus300': - # current_exposure_time = caget('XF:11BMB-ES{Det:SAXS}:cam1:AcquireTime') - # max_exposure_time = max(max_exposure_time, current_exposure_time) - # elif detector.name is 'pilatus2M': - # current_exposure_time = caget('XF:11BMB-ES{Det:PIL2M}:cam1:AcquireTime') - # max_exposure_time = max(max_exposure_time, current_exposure_time) - # elif detector.name is 'pilatus800': - # current_exposure_time = caget('XF:11BMB-ES{Det:PIL800K}:cam1:AcquireTime') - # max_exposure_time = max(max_exposure_time, current_exposure_time) - # elif detector.name is 'PhotonicSciences_CMS': - # current_exposure_time = detector.exposure_time - # max_exposure_time = max(max_exposure_time, current_exposure_time) - else: - if verbosity >= 1: - print("WARNING: Didn't recognize detector '{}'.".format(detector.name)) - - if verbosity >= 2: - status = 0 - while (status == 0) and (time.time() - start_time) < (max_exposure_time + 20): - percentage = 100 * (time.time() - start_time) / max_exposure_time - print( - "Exposing {:6.2f} s ({:3.0f}%) \r".format((time.time() - start_time), percentage), - end="", - ) - - time.sleep(poling_period) - - status = 1 - for detector in get_beamline().detector: - if detector.cam.acquire.get() == 1: - status *= 0 - - # print('counting .... percentage = {}'.format(percentage)) - - else: - time.sleep(max_exposure_time) + max_exposure_time = self.max_exposure_time() + # yield from self.wait_for_detectors(start_time=start_time, period=poling_period) # special solution for 2022_1/TKoga2 if verbosity >= 5: @@ -1918,51 +1655,19 @@ def expose(self, exposure_time=None, extra=None, handlefile=True, verbosity=3, p while percentage < pct_threshold: print("sth is wrong .... percentage = {} < {}%".format(percentage, pct_threshold)) start_time = time.time() - uids = RE(count(get_beamline().detector), **md) - # yield from (count(get_beamline().detector), **md) + uids = yield from count(get_beamline().detector, md=md) # get_beamline().beam.off() # print('shutter is off') # Wait for detectors to be ready - max_exposure_time = 0.1 - for detector in get_beamline().detector: - if detector.name is "pilatus300": - current_exposure_time = detector.cam.acquire_time.get() - max_exposure_time = max(max_exposure_time, current_exposure_time) - elif detector.name is "pilatus2M": - current_exposure_time = detector.cam.acquire_time.get() - max_exposure_time = max(max_exposure_time, current_exposure_time) - elif detector.name is "pilatus800" or detector.name is "pilatus8002": - current_exposure_time = detector.cam.acquire_time.get() - max_exposure_time = max(max_exposure_time, current_exposure_time) + max_exposure_time = yield from self.max_exposure_time() percentage = 100 * (time.time() - start_time) / max_exposure_time print("After re-exposing .... percentage = {} ".format(percentage)) - # if detector.name is 'pilatus300': - # if caget('XF:11BMB-ES{Det:SAXS}:cam1:Acquire')==1: - # status *= 0 - # elif detector.name is 'pilatus2M': - # if caget('XF:11BMB-ES{Det:PIL2M}:cam1:Acquire')==1: - # status *= 0 - # elif detector.name is 'pilatus800': - # if caget('XF:11BMB-ES{Det:PIL800K}:cam1:Acquire')==1: - # status *= 0 - # elif detector.name is 'PhotonicSciences_CMS': - # if not detector.detector_is_ready(verbosity=0): - # status *= 0 - - # if verbosity>=3 and caget('XF:11BMB-ES{Det:PIL800K}:cam1:Acquire')==1: - # print('Warning: Detector pilatus300 still not done acquiring.') - - # #if verbosity>=3 and caget('XF:11BMB-ES{Det:SAXS}:cam1:Acquire')==1: - # #print('Warning: Detector pilatus300 still not done acquiring.') - - # if verbosity>=3 and caget('XF:11BMB-ES{Det:PIL2M}:cam1:Acquire')==1: - # print('Warning: Detector pilatus2M still not done acquiring.') - - get_beamline().beam.off() + # get_beamline().beam.off() + # yield from shutter_off() # save the percentage information # if verbosity>=5: @@ -2007,24 +1712,10 @@ def _expose_test(self, exposure_time=None, extra=None, handlefile=True, verbosit exposure_time = abs(exposure_time) # for detector in gs.DETS: for detector in get_beamline().detector: - if ( - exposure_time != detector.cam.acquire_time.get() - ): # caget('XF:11BMB-ES{Det:PIL2M}:cam1:AcquireTime'): - RE(detector.setExposureTime(exposure_time, verbosity=verbosity)) - # if detector.name is 'pilatus800' and exposure_time != detector.cam.acquire_time.get(): #caget('XF:11BMB-ES{Det:PIL2M}:cam1:AcquireTime'): - # RE(detector.setExposureTime(exposure_time, verbosity=verbosity)) - # if detector.name is 'pilatus300' and exposure_time != detector.cam.acquire_time.get(): - # detector.setExposureTime(exposure_time, verbosity=verbosity) - ##extra wait time when changing the exposure time. - ##time.sleep(2) - ############################################# - ##extra wait time for adjusting pilatus2M - ##this extra wait time has to be added. Otherwise, the exposure will be skipped when the exposure time is increased - ##Note by 091918 - ############################################# - # time.sleep(2) - # elif detector.name is 'PhotonicSciences_CMS': - # detector.setExposureTime(exposure_time, verbosity=verbosity) + acquire_time = yield from bps.rd(detector.cam.acquire_time) + if exposure_time != acquire_time: + yield from bps.mv(detector.cam.acquire_time, exposure_time) + print("2", time.time() - start_time) # Do acquisition @@ -2034,7 +1725,7 @@ def _expose_test(self, exposure_time=None, extra=None, handlefile=True, verbosit md["plan_header_override"] = md["measure_type"] # start_time = time.time() - # md_current = self.get_md() + # md_current = yield from self.get_md() md["beam_int_bim3"] = beam.bim3.flux(verbosity=0) md["beam_int_bim4"] = beam.bim4.flux(verbosity=0) md["beam_int_bim5"] = beam.bim5.flux(verbosity=0) @@ -2043,7 +1734,7 @@ def _expose_test(self, exposure_time=None, extra=None, handlefile=True, verbosit print("3", time.time() - start_time) # uids = RE(count(get_beamline().detector, 1), **md) - uids = RE(count(get_beamline().detector), **md) + uids = yield from count(get_beamline().detector, md=md) # yield from (count(get_beamline().detector), **md) print("4", time.time() - start_time) @@ -2051,61 +1742,28 @@ def _expose_test(self, exposure_time=None, extra=None, handlefile=True, verbosit # print('shutter is off') # Wait for detectors to be ready - max_exposure_time = 0.1 - for detector in get_beamline().detector: - if detector.name is "pilatus300": - current_exposure_time = caget("XF:11BMB-ES{Det:SAXS}:cam1:AcquireTime") - max_exposure_time = max(max_exposure_time, current_exposure_time) - elif detector.name is "pilatus2M": - current_exposure_time = caget("XF:11BMB-ES{Det:PIL2M}:cam1:AcquireTime") - max_exposure_time = max(max_exposure_time, current_exposure_time) - elif detector.name is "pilatus800": - current_exposure_time = caget("XF:11BMB-ES{Det:PIL800K}:cam1:AcquireTime") - max_exposure_time = max(max_exposure_time, current_exposure_time) - # elif detector.name is 'PhotonicSciences_CMS': - # current_exposure_time = detector.exposure_time - # max_exposure_time = max(max_exposure_time, current_exposure_time) - else: - if verbosity >= 1: - print("WARNING: Didn't recognize detector '{}'.".format(detector.name)) + max_exposure_time = self.max_exposure_time() print("5", time.time() - start_time) if verbosity >= 2: - status = 0 - while (status == 0) and (time.time() - start_time) < (max_exposure_time + 20): + status = True + while status and (time.time() - start_time) < (max_exposure_time + 20): percentage = 100 * (time.time() - start_time) / max_exposure_time print( - "Exposing {:6.2f} s ({:3.0f}%) \r".format((time.time() - start_time), percentage), - end="", + "Exposing {:6.2f} s ({:3.0f}%) \r".format((time.time() - start_time), percentage), end="" ) time.sleep(poling_period) - status = 1 + statuses = [] for detector in get_beamline().detector: - if detector.name is "pilatus300": - if caget("XF:11BMB-ES{Det:SAXS}:cam1:Acquire") == 1: - status *= 0 - elif detector.name is "pilatus2M": - if caget("XF:11BMB-ES{Det:PIL2M}:cam1:Acquire") == 1: - status *= 0 - elif detector.name is "pilatus800": - if caget("XF:11BMB-ES{Det:PIL800K}:cam1:Acquire") == 1: - status *= 0 - # elif detector.name is 'PhotonicSciences_CMS': - # if not detector.detector_is_ready(verbosity=0): - # status *= 0 + acquire = yield from bps.rd(detector.cam.acquire) + status.append(acquire) + status = any(statuses) print("6", time.time() - start_time) - else: time.sleep(max_exposure_time) print("7", time.time() - start_time) - # if verbosity>=3 and caget('XF:11BMB-ES{Det:SAXS}:cam1:Acquire')==1: - # print('Warning: Detector pilatus300 still not done acquiring.') - - if verbosity >= 3 and caget("XF:11BMB-ES{Det:PIL2M}:cam1:Acquire") == 1: - print("Warning: Detector pilatus2M still not done acquiring.") - get_beamline().beam.off() print("8", time.time() - start_time) @@ -2117,13 +1775,13 @@ def _expose_test(self, exposure_time=None, extra=None, handlefile=True, verbosit def handle_file(self, detector, extra=None, verbosity=3, subdirs=True, linksave=True, **md): subdir = "" if subdirs: - if detector.name is "pilatus300" or detector.name is "pilatus8002": + if detector.name == "pilatus300" or detector.name == "pilatus8002": subdir = "/maxs/raw/" detname = "maxs" - elif detector.name is "pilatus2M": + elif detector.name == "pilatus2M": subdir = "/saxs/raw/" detname = "saxs" - elif detector.name is "pilatus800": + elif detector.name == "pilatus800": subdir = "/waxs/raw/" detname = "waxs" else: @@ -2142,7 +1800,6 @@ def handle_file(self, detector, extra=None, verbosity=3, subdirs=True, linksave= # if md['measure_type'] is not 'snap': if True: - # self.set_attribute('exposure_time', caget('XF:11BMB-ES{Det:SAXS}:cam1:AcquireTime')) self.set_attribute("exposure_time", detector.cam.acquire_time.get()) # RL, 20210831 # Create symlink @@ -2164,164 +1821,6 @@ def handle_file(self, detector, extra=None, verbosity=3, subdirs=True, linksave= if verbosity >= 3: print(" Data linked as: {}".format(link_name)) - def _old_handle_file(self, detector, extra=None, verbosity=3, subdirs=True, linksave=True, **md): - subdir = "" - - if detector.name is "pilatus300" or detector.name is "pilatus8002": - # chars = caget('XF:11BMB-ES{Det:SAXS}:TIFF1:FullFileName_RBV') - # filename = ''.join(chr(char) for char in chars)[:-1] - filename = detector.tiff.full_file_name.get() # RL, 20210831 - - # Alternate method to get the last filename - # filename = '{:s}/{:s}.tiff'.format( detector.tiff.file_path.get(), detector.tiff.file_name.get() ) - - if verbosity >= 3: - print(" Data saved to: {}".format(filename)) - - if subdirs: - subdir = "/maxs/raw/" - # TODO: - # subdir = '/maxs/raw/' - - # if md['measure_type'] is not 'snap': - if True: - # self.set_attribute('exposure_time', caget('XF:11BMB-ES{Det:SAXS}:cam1:AcquireTime')) - self.set_attribute("exposure_time", detector.cam.acquire_time.get()) # RL, 20210831 - - # Create symlink - # link_name = '{}/{}{}'.format(RE.md['experiment_alias_directory'], subdir, md['filename']) - # savename = md['filename'][:-5] - - # savename = self.get_savename(savename_extra=extra) - savename = md["filename"] - # link_name = '{}/{}{}_{:04d}_maxs.tiff'.format(RE.md['experiment_alias_directory'], subdir, savename, RE.md['scan_id']-1) - link_name = "{}/{}{}_maxs.tiff".format(RE.md["experiment_alias_directory"], subdir, savename) - - if os.path.isfile(link_name): - i = 1 - while os.path.isfile("{}.{:d}".format(link_name, i)): - i += 1 - os.rename(link_name, "{}.{:d}".format(link_name, i)) - os.symlink(filename, link_name) - - if verbosity >= 3: - print(" Data linked as: {}".format(link_name)) - - elif detector.name is "pilatus2M": - foldername = "/nsls2/xf11bm/" - - # chars = caget('XF:11BMB-ES{Det:PIL2M}:TIFF1:FullFileName_RBV') - - # filename = ''.join(chr(char) for char in chars)[:-1] - # filename = foldername + filename - filename = detector.tiff.full_file_name.get() # RL, 20210831 - - # chars = caget('XF:11BMB-ES{Det:PIL2M}:TIFF1:FullFileName_RBV') - # filename = ''.join(chr(char) for char in chars)[:-1] - - # Alternate method to get the last filename - # filename = '{:s}/{:s}.tiff'.format( detector.tiff.file_path.get(), detector.tiff.file_name.get() ) - - if verbosity >= 3: - print(" Data saved to: {}".format(filename)) - - if subdirs: - subdir = "/saxs/raw/" - # TODO: - # subdir = '/saxs/raw/' - - # if md['measure_type'] is not 'snap': - if True: - # self.set_attribute('exposure_time', caget('XF:11BMB-ES{Det:PIL2M}:cam1:AcquireTime')) - self.set_attribute("exposure_time", detector.cam.acquire_time.get()) # RL, 20210831 - - # Create symlink - # link_name = '{}/{}{}'.format(RE.md['experiment_alias_directory'], subdir, md['filename']) - # savename = md['filename'][:-5] - - # savename = self.get_savename(savename_extra=extra) - savename = md["filename"] - link_name = "{}/{}{}_saxs.tiff".format(RE.md["experiment_alias_directory"], subdir, savename) - # link_name = '{}/{}{}_{:04d}_saxs.tiff'.format(RE.md['experiment_alias_directory'], subdir, savename, RE.md['scan_id']-1) - - if os.path.isfile(link_name): - i = 1 - while os.path.isfile("{}.{:d}".format(link_name, i)): - i += 1 - os.rename(link_name, "{}.{:d}".format(link_name, i)) - os.symlink(filename, link_name) - - if verbosity >= 3: - print(" Data linked as: {}".format(link_name)) - - elif detector.name is "pilatus800": - foldername = "/nsls2/xf11bm/" - - # chars = caget('XF:11BMB-ES{Det:PIL800K}:TIFF1:FullFileName_RBV') - # chars = pilatus800.tiff.full_file_name.get() #RL, 20210831 - - # filename = ''.join(chr(char) for char in chars)[:-1] - # filename = foldername + filename - filename = detector.tiff.full_file_name.get() # RL, 20210831 - # Alternate method to get the last filename - # filename = '{:s}/{:s}.tiff'.format( detector.tiff.file_path.get(), detector.tiff.file_name.get() ) - - if verbosity >= 3: - print(" Data saved to: {}".format(filename)) - - if subdirs: - subdir = "/waxs/raw/" - # TODO: - # subdir = '/waxs/raw/' - # if md['measure_type'] is not 'snap': - if True: - # self.set_attribute('exposure_time', caget('XF:11BMB-ES{Det:PIL800K}:cam1:AcquireTime')) - self.set_attribute("exposure_time", detector.cam.acquire_time.get()) # RL, 20210831 - - # Create symlink - # link_name = '{}/{}{}'.format(RE.md['experiment_alias_directory'], subdir, md['filename']) - # savename = md['filename'][:-5] - - # savename = self.get_savename(savename_extra=extra) - savename = md["filename"] - - link_name = "{}/{}{}_waxs.tiff".format(RE.md["experiment_alias_directory"], subdir, savename) - # link_name = '{}/{}{}_{:04d}_saxs.tiff'.format(RE.md['experiment_alias_directory'], subdir, savename, RE.md['scan_id']-1) - - if os.path.isfile(link_name): - i = 1 - while os.path.isfile("{}.{:d}".format(link_name, i)): - i += 1 - os.rename(link_name, "{}.{:d}".format(link_name, i)) - os.symlink(filename, link_name) - - if verbosity >= 3: - print(" Data linked as: {}".format(link_name)) - - # elif detector.name is 'PhotonicSciences_CMS': - - # self.set_attribute('exposure_time', detector.exposure_time) - - # filename = '{:s}/{:s}.tif'.format( detector.file_path, detector.file_name ) - - # if subdirs: - # subdir = '/waxs/' - - ##savename = md['filename'][:-5] - ##savename = self.get_savename(savename_extra=extra) - # savename = md['filename'] - ##savename = '{}/{}{}_{:04d}_waxs.tiff'.format(RE.md['experiment_alias_directory'], subdir, savename, RE.md['scan_id']-1) - # savename = '{}/{}{}_waxs.tiff'.format(RE.md['experiment_alias_directory'], subdir, savename) - - # shutil.copy(filename, savename) - # if verbosity>=3: - # print(' Data saved to: {}'.format(savename)) - - else: - if verbosity >= 1: - print("WARNING: Can't do file handling for detector '{}'.".format(detector.name)) - return - def snap(self, exposure_time=None, extra=None, measure_type="snap", verbosity=3, **md): """Take a quick exposure (without saving data).""" @@ -2360,7 +1859,7 @@ def _measure( 'ygaps' : try to cover the vertical gaps in the Pilatus detector """ - if tiling is "xygaps": + if tiling == "xygaps": if cms.detector == [pilatus2M]: SAXSy_o = SAXSy.user_readback.value SAXSx_o = SAXSx.user_readback.value @@ -2481,7 +1980,7 @@ def _measure( if WAXSy.user_readback.value != WAXSy_o: WAXSy.move(WAXSy_o) - elif tiling is "ygaps": + elif tiling == "ygaps": if cms.detector == [pilatus2M]: SAXSy_o = SAXSy.user_readback.value SAXSx_o = SAXSx.user_readback.value @@ -2614,7 +2113,7 @@ def measure( 'ygaps' : try to cover the vertical gaps in the Pilatus detector """ - if tiling is "xygaps": + if tiling == "xygaps": SAXSy_o = SAXSy.user_readback.value SAXSx_o = SAXSx.user_readback.value WAXSy_o = WAXSy.user_readback.value @@ -2683,7 +2182,7 @@ def measure( if SAXSy.user_readback.value != SAXSy_o: SAXSy.move(SAXSy_o) - elif tiling is "ygaps": + elif tiling == "ygaps": SAXSy_o = SAXSy.user_readback.value SAXSx_o = SAXSx.user_readback.value WAXSy_o = WAXSy.user_readback.value @@ -2729,7 +2228,7 @@ def measure( else: # Just do a normal measurement - self.measure_single( + yield from self.measure_single( exposure_time=exposure_time, extra=extra, measure_type=measure_type, verbosity=verbosity, **md ) @@ -2778,10 +2277,9 @@ def measureRock( ) if verbosity >= 1 and len(get_beamline().detector) < 1: - print("ERROR: No detectors defined in cms.detector") - return + raise ValueError("No detectors defined in cms.detector") - md_current = self.get_md() + md_current = yield from self.get_md() md_current.update(self.get_measurement_md()) md_current["sample_savename"] = savename md_current["measure_type"] = measure_type @@ -2801,22 +2299,9 @@ def measureRock( if exposure_time is not None: # for detector in gs.DETS: for detector in get_beamline().detector: - if ( - exposure_time != detector.cam.acquire_time.get() - ): # caget('XF:11BMB-ES{Det:PIL2M}:cam1:AcquireTime'): - RE(detector.setExposureTime(exposure_time, verbosity=verbosity)) - # if detector.name is 'pilatus300' and exposure_time != detector.cam.acquire_time.get(): - # detector.setExposureTime(exposure_time, verbosity=verbosity) - ##extra wait time when changing the exposure time. - ##time.sleep(2) - ############################################# - ##extra wait time for adjusting pilatus2M - ##this extra wait time has to be added. Otherwise, the exposure will be skipped when the exposure time is increased - ##Note by 091918 - ############################################# - # time.sleep(2) - # elif detector.name is 'PhotonicSciences_CMS': - # detector.setExposureTime(exposure_time, verbosity=verbosity) + acquire_time = yield from bps.rd(detector.cam.acquire_time) + if exposure_time != acquire_time: + yield from bps.mv(detector.cam.acquire_time, exposure_time) # Do acquisition get_beamline().beam.on() @@ -2829,76 +2314,15 @@ def measureRock( armr, [0], per_step=lambda detectors, motor, step: rock_motor_per_step( - detectors, - motor, - step, - rock_motor=rock_motor, - rock_motor_limits=rock_motor_limits, + detectors, motor, step, rock_motor=rock_motor, rock_motor_limits=rock_motor_limits ), ) # uids = RE(count(get_beamline().detector, 1), **md) uids = RE(rock_scan, **md_current) # Wait for detectors to be ready - max_exposure_time = 0 - for detector in get_beamline().detector: - if detector.name is "pilatus300" or "pilatus800" or "pilatus2M" or "pilatus8002": - max_exposure_time = detector.cam.acquire_time.get() - - # if detector.name is 'pilatus300': - # current_exposure_time = caget('XF:11BMB-ES{Det:SAXS}:cam1:AcquireTime') - # max_exposure_time = max(max_exposure_time, current_exposure_time) - # elif detector.name is 'pilatus2M': - # current_exposure_time = caget('XF:11BMB-ES{Det:PIL2M}:cam1:AcquireTime') - # max_exposure_time = max(max_exposure_time, current_exposure_time) - # elif detector.name is 'pilatus800': - # current_exposure_time = caget('XF:11BMB-ES{Det:PIL800K}:cam1:AcquireTime') - # max_exposure_time = max(max_exposure_time, current_exposure_time) - # elif detector.name is 'PhotonicSciences_CMS': - # current_exposure_time = detector.exposure_time - # max_exposure_time = max(max_exposure_time, current_exposure_time) - else: - if verbosity >= 1: - print("WARNING: Didn't recognize detector '{}'.".format(detector.name)) - - if verbosity >= 2: - status = 0 - while (status == 0) and (time.time() - start_time) < (max_exposure_time + 20): - percentage = 100 * (time.time() - start_time) / max_exposure_time - print( - "Exposing {:6.2f} s ({:3.0f}%) \r".format((time.time() - start_time), percentage), - end="", - ) - time.sleep(poling_period) - - status = 1 - for detector in get_beamline().detector: - if detector.cam.acquire.get(): - status *= 0 - - # if detector.name is 'pilatus300': - # if caget('XF:11BMB-ES{Det:SAXS}:cam1:Acquire')==1: - # status *= 0 - # elif detector.name is 'pilatus2M': - # if caget('XF:11BMB-ES{Det:PIL2M}:cam1:Acquire')==1: - # status *= 0 - # elif detector.name is 'pilatus800': - # if caget('XF:11BMB-ES{Det:PIL800K}:cam1:Acquire')==1: - # status *= 0 - # elif detector.name is 'PhotonicSciences_CMS': - # if not detector.detector_is_ready(verbosity=0): - # status *= 0 - print("") - - else: - time.sleep(max_exposure_time) - - # if verbosity>=3 and caget('XF:11BMB-ES{Det:SAXS}:cam1:Acquire')==1: - # print('Warning: Detector pilatus300 still not done acquiring.') - # if verbosity>=3 and caget('XF:11BMB-ES{Det:PIL2M}:cam1:Acquire')==1: - # print('Warning: Detector pilatus2M still not done acquiring.') - # if verbosity>=3 and caget('XF:11BMB-ES{Det:PIL800K}:cam1:Acquire')==1: - # print('Warning: Detector pilatus800 still not done acquiring.') + max_exposure_time = yield from self.max_exposure_time() + yield from self.wait_for_detectors(start_time=start_time, period=poling_period) get_beamline().beam.off() @@ -2918,7 +2342,6 @@ def measure_single(self, exposure_time=None, extra=None, measure_type="measure", Extra information about this particular measurement (which is typically included in the savename/filename). """ - if exposure_time is not None: self.set_attribute("exposure_time", exposure_time) # else: @@ -2932,19 +2355,19 @@ def measure_single(self, exposure_time=None, extra=None, measure_type="measure", ) if verbosity >= 1 and len(get_beamline().detector) < 1: - print("ERROR: No detectors defined in cms.detector") - return + raise ValueError("ERROR: No detectors defined in cms.detector") - md_current = self.get_md() - md_current.update(self.get_measurement_md()) + md_current = yield from self.get_md() + new_md = yield from self.get_measurement_md() + md_current.update(new_md) md_current["sample_savename"] = savename md_current["measure_type"] = measure_type # md_current['filename'] = '{:s}_{:04d}.tiff'.format(savename, md_current['detector_sequence_ID']) # md_current['filename'] = '{:s}_{:04d}.tiff'.format(savename, RE.md['scan_id']) - md_current["filename"] = "{:s}_{:06d}".format(savename, RE.md["scan_id"]) + md_current["filename"] = "{:s}_{:06d}".format(savename, RE.md.get("scan_id", -1)) md_current.update(md) - self.expose(exposure_time, extra=extra, verbosity=verbosity, **md_current) + yield from self.expose(exposure_time, extra=extra, verbosity=verbosity, **md_current) # self.expose(exposure_time, extra=extra, verbosity=verbosity, **md) self.md["measurement_ID"] += 1 @@ -2985,19 +2408,19 @@ def _test_measure_single( ) if verbosity >= 1 and len(get_beamline().detector) < 1: - print("ERROR: No detectors defined in cms.detector") - return + raise ValueError("No detectors defined in cms.detector") # print('2') #0.0004s # print(time.time()) - md_current = self.get_md() + md_current = yield from self.get_md() md_current["sample_savename"] = savename md_current["measure_type"] = measure_type md_current.update(self.get_measurement_md()) # md_current['filename'] = '{:s}_{:04d}.tiff'.format(savename, md_current['detector_sequence_ID']) - md_current["filename"] = "{:s}_{:04d}.tiff".format(savename, RE.md["scan_id"]) + # TODO: Garrett, may need to remove the get to raise exception. + md_current["filename"] = "{:s}_{:04d}.tiff".format(savename, RE.md.get("scan_id", -1)) md_current.update(md) # print('3') #0.032s @@ -3055,60 +2478,8 @@ def _test_expose( # print('shutter is off') # Wait for detectors to be ready - max_exposure_time = 0 - for detector in get_beamline().detector: - if detector.name is "pilatus300" or "pilatus2M": - current_exposure_time = caget("XF:11BMB-ES{}:cam1:AcquireTime".format(pilatus_Epicsname)) - max_exposure_time = max(max_exposure_time, current_exposure_time) - elif detector.name is "PhotonicSciences_CMS": - current_exposure_time = detector.exposure_time - max_exposure_time = max(max_exposure_time, current_exposure_time) - else: - if verbosity >= 1: - print("WARNING: Didn't recognize detector '{}'.".format(detector.name)) - - print("4") # 4.3193 - print(self.clock()) - - if verbosity >= 2: - status = 0 - print("status1 = ", status) - - while (status == 0) and (time.time() - start_time) < (max_exposure_time + 20): - percentage = 100 * (time.time() - start_time) / max_exposure_time - print( - "Exposing {:6.2f} s ({:3.0f}%) \r".format((time.time() - start_time), percentage), - end="", - ) - print("status2 = ", status) - - time.sleep(poling_period) - - status = 1 - for detector in get_beamline().detector: - if detector.name is "pilatus300" or "pilatus2M": - print("status2.5 = ", status) - if caget("XF:11BMB-ES{}:cam1:Acquire".format(pilatus_Epicsname)) == 1: - status = 0 - print("status3 = ", status) - print("status3.5 = ", status) - - elif detector.name is "PhotonicSciences_CMS": - if not detector.detector_is_ready(verbosity=0): - status = 0 - print("5") # 3.0 - print(self.clock()) - print("6") # 3.0 - print(self.clock()) - - else: - time.sleep(max_exposure_time) - - # print('5') #4.4193 - # print(self.clock()) - - if verbosity >= 3 and caget("XF:11BMB-ES{}:cam1:Acquire".format(pilatus_Epicsname)) == 1: - print("Warning: Detector still not done acquiring.") + max_exposure_time = yield from self.max_exposure_time() + yield from self.wait_for_detectors(start_time=start_time, poling_period=poling_period) if shutteronoff == True: get_beamline().beam.off() @@ -3439,14 +2810,13 @@ def scan_measure( "WARNING: Beamline is not in measurement mode (mode is '{}')".format(get_beamline().current_mode) ) if verbosity >= 1 and len(cms.detector) < 1: - print("ERROR: No detectors defined in cms.detector") - return + raise ValueError("No detectors defined in cms.detector") # set exposure time for detector in get_beamline().detector: detector.setExposureTime(exposure_time, verbosity=verbosity) # set metadata - md_current = self.get_md() + md_current = yield from self.get_md() md_current["sample_savename"] = savename md_current["measure_type"] = measure_type md_current["scan"] = "scan_measure" @@ -3464,29 +2834,18 @@ def scan_measure( # get_beamline().beam._test_on(wait_time=0.1) get_beamline().beam.on() # RE(relative_scan(gs.DETS, motor, start, stop, num_frames+1, per_step=per_step, md=md_current)) - RE( - relative_scan( - cms.detector, - motor, - start, - stop, - num_frames + 1, - per_step=per_step, - md=md_current, - ), - LiveTable([motor, "motor_setpoint"]), + # TODO: Figure out how to do live table. + # yield from relative_scan(cms.detector, motor, start, stop, num_frames+1, per_step=per_step,md=md_current), LiveTable([motor, 'motor_setpoint']) + yield from relative_scan( + cms.detector, motor, start, stop, num_frames + 1, per_step=per_step, md=md_current ) - # if verbosity>=3 and caget('XF:11BMB-ES{Det:SAXS}:cam1:Acquire')==1: stage = 1 for detector in cms.detector: - if detector.cam.acquire.get() == 1: - # if verbosity>=3 and caget('XF:11BMB-ES{Det:SAXS}:cam1:Acquire')==1: - + acquire = yield from bps.rd(detector.cam.acquire) + if acquire == 1: print("Warning: Detector {} still not done acquiring.".format(detector.name)) - # elif verbosity>=3 and caget('XF:11BMB-ES{Det:PIL2M}:cam1:Acquire')==1: - # print('Warning: Detector Pilatus2M still not done acquiring.') - # get_beamline().beam._test_off(wait_time=0.1) + get_beamline().beam.off() self.md["measurement_ID"] += 1 @@ -3534,13 +2893,11 @@ def series_measure( # Set exposure time for detector in get_beamline().detector: - if exposure_time != detector.cam.acquire_time.get(): - RE(detector.setExposureTime(exposure_time)) - # detector.cam.acquire_time.put(exposure_time) - # detector.cam.acquire_period.put(exposure_period) - # detector.cam.num_images.put(num_frames) - RE(detector.setExposurePeriod(exposure_period)) - RE(detector.setExposureNumber(num_frames)) + acquire_time = yield from bps.rd(detector.cam.acquire_time) + if exposure_time != acquire_time: + yield from bps.mv(detector.cam.acquire_time, exposure_time) + yield from bps.mv(detector.cam.acquire_period, exposure_period) + yield from bps.mv(detector.cam.num_images, num_frames) # bec.disable_plots() # bec.disable_table() @@ -3552,10 +2909,9 @@ def series_measure( ) if verbosity >= 1 and len(get_beamline().detector) < 1: - print("ERROR: No detectors defined in cms.detector") - return + raise ValueError("No detectors defined in cms.detector") - md_current = self.get_md() + md_current = yield from self.get_md() md_current["sample_savename"] = savename md_current["measure_type"] = measure_type md_current["series"] = "series_measure" @@ -3590,64 +2946,36 @@ def series_measure( print("handling the file names") self.handle_fileseries(detector, num_frames=num_frames, extra=extra, verbosity=verbosity, **md) - # if detector.name is 'pilatus2M': - # caput('XF:11BMB-ES{Det:PIL2M}:cam1:NumImages', 1) - # if detector.name is 'pilatus300' : - # caput('XF:11BMB-ES{Det:SAXS}:cam1:NumImages', 1) - # if detector.name is 'pilatus800' : - # caput('XF:11BMB-ES{Det:PIL800K}:cam1:NumImages', 1) - def initialDetector(self): # reset the num_frame back to 1 for detector in get_beamline().detector: detector.cam.num_images.put(1) - # if detector.name is 'pilatus2M': - # caput('XF:11BMB-ES{Det:PIL2M}:cam1:NumImages', 1) - # if detector.name is 'pilatus300' : - # caput('XF:11BMB-ES{Det:SAXS}:cam1:NumImages', 1) - # if detector.name is 'pilatus800' : - # caput('XF:11BMB-ES{Det:PIL800K}:cam1:NumImages', 1) def _old_handle_fileseries(self, detector, num_frames=None, extra=None, verbosity=3, subdirs=True, **md): subdir = "" if detector.name == "pilatus300" or detector.name == "pilatus8002": - # chars = caget('XF:11BMB-ES{Det:SAXS}:TIFF1:FullFileName_RBV') - # filename = ''.join(chr(char) for char in chars)[:-1] - # filename_part1 = ''.join(chr(char) for char in chars)[:-13] - filename = detector.tiff.full_file_name.get() # RL, 20210831 print("pilatus300k data handling") - # Alternate method to get the last filename - # filename = '{:s}/{:s}.tiff'.format( detector.tiff.file_path.get(), detector.tiff.file_name.get() ) - - # if verbosity>=3: - # print(' Data saved to: {}'.format(filename)) if subdirs: subdir = "/maxs/raw/" # if md['measure_type'] is not 'snap': if True: - # self.set_attribute('exposure_time', caget('XF:11BMB-ES{Det:SAXS}:cam1:AcquireTime')) - self.set_attribute("exposure_time", detector.cam.acquire_time.get()) # RL, 20210831 + acquire_time = yield from bps.rd(detector.cam.acquire_time) + self.set_attribute("exposure_time", acquire_time) # RL, 20210831 # Create symlink # link_name = '{}/{}{}'.format(RE.md['experiment_alias_directory'], subdir, md['filename']) # savename = md['filename'][:-5] savename = self.get_savename(savename_extra=extra) link_name = "{}/{}{}_{:04d}_maxs.tiff".format( - RE.md["experiment_alias_directory"], - subdir, - savename, - RE.md["scan_id"] - 1, + RE.md["experiment_alias_directory"], subdir, savename, RE.md["scan_id"] - 1 ) link_name_part1 = "{}/{}{}_{:04d}".format( - RE.md["experiment_alias_directory"], - subdir, - savename, - RE.md["scan_id"] - 1, + RE.md["experiment_alias_directory"], subdir, savename, RE.md["scan_id"] - 1 ) if os.path.isfile(link_name): @@ -3665,10 +2993,6 @@ def _old_handle_fileseries(self, detector, num_frames=None, extra=None, verbosit print(" Data {} linked as: {}".format(filename_new, link_name_new)) elif detector.name == "pilatus2M": - # chars = caget('XF:11BMB-ES{Det:PIL2M}:TIFF1:FullFileName_RBV') - # filename = ''.join(chr(char) for char in chars)[:-1] - # filename_part1 = ''.join(chr(char) for char in chars)[:-13] - filename = detector.tiff.full_file_name.get() # RL, 20210831 filename_part1 = detector.tiff.file_path.get() + detector.tiff.file_name.get() @@ -3686,8 +3010,8 @@ def _old_handle_fileseries(self, detector, num_frames=None, extra=None, verbosit # if md['measure_type'] is not 'snap': if True: - # self.set_attribute('exposure_time', caget('XF:11BMB-ES{Det:PIL2M}:cam1:AcquireTime')) - self.set_attribute("exposure_time", detector.cam.acquire_time.get()) # RL, 20210831 + acquire_time = yield from bps.rd(detector.cam.acquire_time) + self.set_attribute("exposure_time", acquire_time) # RL, 20210831 # Create symlink # link_name = '{}/{}{}'.format(RE.md['experiment_alias_directory'], subdir, md['filename']) @@ -3695,16 +3019,10 @@ def _old_handle_fileseries(self, detector, num_frames=None, extra=None, verbosit savename = self.get_savename(savename_extra=extra) link_name = "{}/{}{}_{:04d}_saxs.tiff".format( - RE.md["experiment_alias_directory"], - subdir, - savename, - RE.md["scan_id"] - 1, + RE.md["experiment_alias_directory"], subdir, savename, RE.md["scan_id"] - 1 ) link_name_part1 = "{}/{}{}_{:04d}".format( - RE.md["experiment_alias_directory"], - subdir, - savename, - RE.md["scan_id"] - 1, + RE.md["experiment_alias_directory"], subdir, savename, RE.md["scan_id"] - 1 ) if os.path.isfile(link_name): @@ -3721,19 +3039,9 @@ def _old_handle_fileseries(self, detector, num_frames=None, extra=None, verbosit if num_frame == 0 or num_frame == np.max(num_frames): print(" Data {} linked as: {}".format(filename_new, link_name_new)) - # elif detector.name is 'pilatus800': - # chars = caget('XF:11BMB-ES{Det:PIL800K}:TIFF1:FullFileName_RBV') - # filename = ''.join(chr(char) for char in chars)[:-1] - # filename_part1 = ''.join(chr(char) for char in chars)[:-13] - elif detector.name == "pilatus800": foldername = "/nsls2/xf11bm/" - # chars = caget('XF:11BMB-ES{Det:PIL800K}:TIFF1:FullFileName_RBV') - # filename = ''.join(chr(char) for char in chars)[:-1] - # filename = foldername + filename - # filename_part1 = foldername + ''.join(chr(char) for char in chars)[:-13] - filename = pilatus800.tiff.full_file_name.get() # RL, 20210831 filename_part1 = pilatus800.tiff.file_path.get() + pilatus800.tiff.file_name.get() @@ -3750,8 +3058,8 @@ def _old_handle_fileseries(self, detector, num_frames=None, extra=None, verbosit # if md['measure_type'] is not 'snap': if True: - # self.set_attribute('exposure_time', caget('XF:11BMB-ES{Det:PIL800K}:cam1:AcquireTime')) - self.set_attribute("exposure_time", pilatus800.cam.acquire_time.get()) # RL, 20210831 + acquire_time = yield from bps.rd(pilatus800.cam.acquire_time) + self.set_attribute("exposure_time", acquire_time) # RL, 20210831 # Create symlink # link_name = '{}/{}{}'.format(RE.md['experiment_alias_directory'], subdir, md['filename']) @@ -3759,16 +3067,10 @@ def _old_handle_fileseries(self, detector, num_frames=None, extra=None, verbosit savename = self.get_savename(savename_extra=extra) link_name = "{}/{}{}_{:04d}_waxs.tiff".format( - RE.md["experiment_alias_directory"], - subdir, - savename, - RE.md["scan_id"] - 1, + RE.md["experiment_alias_directory"], subdir, savename, RE.md["scan_id"] - 1 ) link_name_part1 = "{}/{}{}_{:04d}".format( - RE.md["experiment_alias_directory"], - subdir, - savename, - RE.md["scan_id"] - 1, + RE.md["experiment_alias_directory"], subdir, savename, RE.md["scan_id"] - 1 ) if os.path.isfile(link_name): @@ -3821,25 +3123,18 @@ def handle_fileseries(self, detector, num_frames=None, extra=None, verbosity=3, # if md['measure_type'] is not 'snap': if True: - # self.set_attribute('exposure_time', caget('XF:11BMB-ES{Det:SAXS}:cam1:AcquireTime')) - self.set_attribute("exposure_time", detector.cam.acquire_time.get()) # RL, 20210831 + acquire_time = yield from bps.rd(detector.cam.acquire_time) + self.set_attribute("exposure_time", acquire_time) # RL, 20210831 # Create symlink # link_name = '{}/{}{}'.format(RE.md['experiment_alias_directory'], subdir, md['filename']) # savename = md['filename'][:-5] savename = self.get_savename(savename_extra=extra) link_name = "{}/{}{}_{:06d}_{}.tiff".format( - RE.md["experiment_alias_directory"], - subdir, - savename, - RE.md["scan_id"] - 1, - detname, + RE.md["experiment_alias_directory"], subdir, savename, RE.md["scan_id"] - 1, detname ) link_name_part1 = "{}/{}{}_{:06d}".format( - RE.md["experiment_alias_directory"], - subdir, - savename, - RE.md["scan_id"] - 1, + RE.md["experiment_alias_directory"], subdir, savename, RE.md["scan_id"] - 1 ) # link_name = '{}/{}{}_{:06d}_{}.tiff'.format(RE.md['experiment_alias_directory'], subdir, savename, RE.md['scan_id'], detname) # link_name_part1 = '{}/{}{}_{:06d}'.format(RE.md['experiment_alias_directory'], subdir, savename, RE.md['scan_id']) @@ -3868,90 +3163,26 @@ def handle_fileseries(self, detector, num_frames=None, extra=None, verbosity=3, # Control methods ######################################## def setTemperature(self, temperature, output_channel="1", verbosity=3): - # if verbosity>=1: - # print('Temperature functions not implemented in {}'.format(self.__class__.__name__)) - if output_channel == "1": - if verbosity >= 2: - print( - " Changing temperature setpoint from {:.3f}°C to {:.3f}°C".format( - caget("XF:11BM-ES{Env:01-Out:1}T-SP") - 273.15, temperature - ) - ) - caput("XF:11BM-ES{Env:01-Out:1}T-SP", temperature + 273.15) - - if output_channel == "2": - if verbosity >= 2: - print( - " Changing temperature setpoint from {:.3f}°C to {:.3f}°C".format( - caget("XF:11BM-ES{Env:01-Out:2}T-SP") - 273.15, temperature - ) - ) - caput("XF:11BM-ES{Env:01-Out:2}T-SP", temperature + 273.15) - - if output_channel == "3": - if verbosity >= 2: - print( - " Changing temperature setpoint from {:.3f}°C to {:.3f}°C".format( - caget("XF:11BM-ES{Env:01-Out:3}T-SP") - 273.15, temperature - ) - ) - caput("XF:11BM-ES{Env:01-Out:3}T-SP", temperature + 273.15) - - if output_channel == "4": - if verbosity >= 2: - print( - " Changing temperature setpoint from {:.3f}°C to {:.3f}°C".format( - caget("XF:11BM-ES{Env:01-Out:4}T-SP") - 273.15, temperature - ) - ) - caput("XF:11BM-ES{Env:01-Out:4}T-SP", temperature + 273.15) + signal = getattr(self, f"xf_11bm_es_env_01_out_{output_channel.lower()}_t_sp") + if verbosity >= 2: + current_temperature = yield from bps.rd(signal) + print(" Changing temperature setpoint from {:.3f}°C to {:.3f}°C".format(signal, temperature)) + yield from bps.mv(signal, temperature + 273.15) def temperature(self, temperature_probe="A", output_channel="1", RTDchan=2, verbosity=3): - # if verbosity>=1: - # print('Temperature functions not implemented in {}'.format(self.__class__.__name__)) - - if temperature_probe == "A": - current_temperature = caget("XF:11BM-ES{Env:01-Chan:A}T:C-I") - if verbosity >= 3: - print( - " Temperature = {:.3f}°C (setpoint = {:.3f}°C)".format( - current_temperature, - self.temperature_setpoint(output_channel=output_channel) - 273.15, - ) - ) - if temperature_probe == "B": - current_temperature = caget("XF:11BM-ES{Env:01-Chan:B}T:C-I") - if verbosity >= 3: - print( - " Temperature = {:.3f}°C (setpoint = {:.3f}°C)".format( - current_temperature, - self.temperature_setpoint(output_channel=output_channel) - 273.15, - ) - ) - if temperature_probe == "C": - current_temperature = caget("XF:11BM-ES{Env:01-Chan:C}T:C-I") - if verbosity >= 3: - print( - " Temperature = {:.3f}°C (setpoint = {:.3f}°C)".format( - current_temperature, - self.temperature_setpoint(output_channel=output_channel) - 273.15, - ) - ) - if temperature_probe == "D": - current_temperature = caget("XF:11BM-ES{Env:01-Chan:D}T:C-I") - if verbosity >= 3: - print( - " Temperature = {:.3f}°C (setpoint = {:.3f}°C)".format( - current_temperature, - self.temperature_setpoint(output_channel=output_channel) - 273.15, - ) - ) if temperature_probe == "E": try: - current_temperature = ioL.read(RTD[RTDchan]) + readback = ioL.read(RTD[RTDchan]) except TypeError: - current_temperature = -273.15 - return current_temperature + readback = -273.15 + return readback + + setpoint = yield from bps.rd(getattr(self, f"xf_11bm_es_env_01_out_{output_channel.lower()}_t_sp")) + readback = yield from bps.rd(getattr(self, f"xf_11bm_es_env_01_chan_{temperature_probe.lower()}_t_c_i")) + + if verbosity >= 3: + print(" Temperature = {:.3f}°C (setpoint = {:.3f}°C)".format(readback, setpoint - 273.15)) + return readback def humidity(self, AI_chan=4, temperature=25, verbosity=3): return ioL.readRH(AI_chan=AI_chan, temperature=temperature, verbosity=verbosity) @@ -4023,21 +3254,7 @@ def intMeasure(self, output_file, exposure_time): temp_data.to_csv(INT_FILENAME) def temperature_setpoint(self, output_channel="1", verbosity=3): - # if verbosity>=1: - # print('Temperature functions not implemented in {}'.format(self.__class__.__name__)) - - if output_channel == "1": - setpoint_temperature = caget("XF:11BM-ES{Env:01-Out:1}T-SP") - - if output_channel == "2": - setpoint_temperature = caget("XF:11BM-ES{Env:01-Out:2}T-SP") - - if output_channel == "3": - setpoint_temperature = caget("XF:11BM-ES{Env:01-Out:3}T-SP") - - if output_channel == "4": - setpoint_temperature = caget("XF:11BM-ES{Env:01-Out:4}T-SP") - + setpoint = yield from bps.rd(getattr(self, f"xf_11bm_es_env_01_out_{output_channel.lower()}_t_sp")) return setpoint_temperature def monitor_scheme(self, scheme): @@ -4394,107 +3611,22 @@ def gotoSample(self, sample_number): # Control methods ######################################## def setTemperature(self, temperature, output_channel="1", verbosity=3): - # if verbosity>=1: - # print('Temperature functions not implemented in {}'.format(self.__class__.__name__)) - if output_channel == "1": - if verbosity >= 2: - print( - " Changing temperature setpoint from {:.3f}°C to {:.3f}°C".format( - caget("XF:11BM-ES{Env:01-Out:1}T-SP") - 273.15, temperature - ) - ) - caput("XF:11BM-ES{Env:01-Out:1}T-SP", temperature + 273.15) - - if output_channel == "2": - if verbosity >= 2: - print( - " Changing temperature setpoint from {:.3f}°C to {:.3f}°C".format( - caget("XF:11BM-ES{Env:01-Out:2}T-SP") - 273.15, temperature - ) - ) - caput("XF:11BM-ES{Env:01-Out:2}T-SP", temperature + 273.15) - - if output_channel == "3": - if verbosity >= 2: - print( - " Changing temperature setpoint from {:.3f}°C to {:.3f}°C".format( - caget("XF:11BM-ES{Env:01-Out:3}T-SP") - 273.15, temperature - ) - ) - caput("XF:11BM-ES{Env:01-Out:3}T-SP", temperature + 273.15) - - if output_channel == "4": - if verbosity >= 2: - print( - " Changing temperature setpoint from {:.3f}°C to {:.3f}°C".format( - caget("XF:11BM-ES{Env:01-Out:4}T-SP") - 273.15, temperature - ) - ) - caput("XF:11BM-ES{Env:01-Out:4}T-SP", temperature + 273.15) + original_temp = yield from bps.rd(getattr(self, f"xf_11bm_es_env_01_out_{output_channel.lower()}_t_sp")) + if verbosity >= 2: + print(f" Changing temperature setpoint from {original_temp}°C to {temperature}°C") + yield from bps.mv( + getattr(self, "xf_11bm_es_env_01_out_{output_channel.lower()}_t_sp"), temperature + 273.15 + ) def temperature(self, temperature_probe="A", output_channel="1", verbosity=3): - # if verbosity>=1: - # print('Temperature functions not implemented in {}'.format(self.__class__.__name__)) - - if temperature_probe == "A": - current_temperature = caget("XF:11BM-ES{Env:01-Chan:A}T:C-I") - if verbosity >= 3: - print( - " Temperature = {:.3f}°C (setpoint = {:.3f}°C)".format( - current_temperature, - self.temperature_setpoint(output_channel=output_channel) - 273.15, - ) - ) - - if temperature_probe == "B": - current_temperature = caget("XF:11BM-ES{Env:01-Chan:B}T:C-I") - if verbosity >= 3: - print( - " Temperature = {:.3f}°C (setpoint = {:.3f}°C)".format( - current_temperature, - self.temperature_setpoint(output_channel=output_channel) - 273.15, - ) - ) - - if temperature_probe == "C": - current_temperature = caget("XF:11BM-ES{Env:01-Chan:C}T:C-I") - if verbosity >= 3: - print( - " Temperature = {:.3f}°C (setpoint = {:.3f}°C)".format( - current_temperature, - self.temperature_setpoint(output_channel=output_channel) - 273.15, - ) - ) - - if temperature_probe == "D": - current_temperature = caget("XF:11BM-ES{Env:01-Chan:D}T:C-I") - if verbosity >= 3: - print( - " Temperature = {:.3f}°C (setpoint = {:.3f}°C)".format( - current_temperature, - self.temperature_setpoint(output_channel=output_channel) - 273.15, - ) - ) - - return current_temperature + setpoint = yield from bps.rd(getattr(self, f"xf_11bm_es_env_01_out_{output_channel.lower()}_t_sp")) + readback = yield from bps.rd(getattr(self, f"xf_11bm_es_env_01_chan_{temperature_probe.lower()}_t_c_i")) + print(" Temperature = {:.3f}°C (setpoint = {:.3f}°C)".format(readback, setpoint - 273.15)) + return readback def temperature_setpoint(self, output_channel="1", verbosity=3): - # if verbosity>=1: - # print('Temperature functions not implemented in {}'.format(self.__class__.__name__)) - - if output_channel == "1": - setpoint_temperature = caget("XF:11BM-ES{Env:01-Out:1}T-SP") - - if output_channel == "2": - setpoint_temperature = caget("XF:11BM-ES{Env:01-Out:2}T-SP") - - if output_channel == "3": - setpoint_temperature = caget("XF:11BM-ES{Env:01-Out:3}T-SP") - - if output_channel == "4": - setpoint_temperature = caget("XF:11BM-ES{Env:01-Out:4}T-SP") - - return setpoint_temperature + setpoint = yield from bps.rd(getattr(self, f"xf_11bm_es_env_01_out_{output_channel.lower()}_t_sp")) + return setpoint # Action (measurement) methods ######################################## @@ -4535,8 +3667,7 @@ def doTemperature( if verbosity >= 3: print( " setpoint = {:.3f}°C, Temperature = {:.3f}°C \r".format( - self.temperature_setpoint() - 273.15, - self.temperature(verbosity=0), + self.temperature_setpoint() - 273.15, self.temperature(verbosity=0) ), end="", ) @@ -4586,14 +3717,6 @@ def __init__(self, name="PositionalHolder", base=None, **kwargs): self._positional_axis = "x" self.GaragePosition = [] - self.setPosition() - - def setPosition(self): - # add by RL 060823 - self.position = {} - for axis in self._positional_axis: - self.position[axis] = self._axes[axis].origin - # self.position _axes['x'].origin # Sample management ######################################## @@ -4668,13 +3791,7 @@ def listSamplesDetails(self): pos = sample.origin(verbosity=0)[self._positional_axis] print( "%s: %s (%s = %.3f) %s" - % ( - str(sample_number), - sample.name, - self._positional_axis, - pos, - sample.detector, - ) + % (str(sample_number), sample.name, self._positional_axis, pos, sample.detector) ) def addGaragePosition(self, shelf_num, spot_num): @@ -4684,11 +3801,16 @@ def addGaragePosition(self, shelf_num, spot_num): self.GaragePosition = [shelf_num, spot_num] - def intMeasure(self, output_file, exposure_time=1): + def intMeasure(self, output_file, exposure_time): for sample in self.getSamples(): sample.gotoOrigin() sample.intMeasure(output_file, exposure_time=1) + def saveSampleStates(self, output_file=None): + """Print a list of the current samples associated with this holder/bar. + + It can be saved in the output_file under setup""" + def saveSampleStates(self, output_file=None): """Print a list of the current samples associated with this holder/bar. @@ -4727,20 +3849,21 @@ def get_default_stage(): return stg -if False: +if True: # For testing: # %run -i /opt/ipython_profiles/profile_collection/startup/94-sample.py - sam = SampleGISAXS_Generic("testing_of_code") - sam.mark("here") + sam = Sample_Generic("testing_of_code") + # sam.mark("here") # sam.mark('XY_field', 'x', 'y') # sam.mark('specified', x=1, th=0.1) # sam.naming(['name', 'extra', 'clock', 'th', 'exposure_time', 'id']) # sam.thsetOrigin(0.5) # sam.marks() - - hol = CapillaryHolder(base=stg) - hol.addSampleSlot(SampleGISAXS_Generic("test_sample_01"), 1.0) - hol.addSampleSlot(SampleGISAXS_Generic("test_sample_02"), 3.0) - hol.addSampleSlot(SampleGISAXS_Generic("test_sample_03"), 5.0) - - sam = hol.getSample(1) + cms.SAXS.setCalibration([780, 1680 - 605], 5.03, [-60, -73]) # 13.5 keV + # hol = CapillaryHolder(base=stg) + # hol.addSampleSlot( Sample_Generic('test_sample_01'), 1.0 ) + # hol.addSampleSlot( Sample_Generic('test_sample_02'), 3.0 ) + # hol.addSampleSlot( Sample_Generic('test_sample_03'), 5.0 ) + + # sam = hol.getSample(1) + detselect(pilatus2M) diff --git a/startup/94-sample.py.save b/startup/94-sample.py.save deleted file mode 100755 index e8f62b6..0000000 --- a/startup/94-sample.py.save +++ /dev/null @@ -1,2965 +0,0 @@ - -#!/usr/bin/python -# -*- coding: utf-8 -*- -# vi: ts=4 sw=4 - - - - -################################################################################ -# Code for defining a 'Sample' object, which keeps track of its state, and -# simplifies the task of aligning, measuring, etc. -################################################################################ -# Known Bugs: -# N/A -################################################################################ -# TODO: -# - Search for "TODO" below. -# - Ability to have a collection of simultaneous motions? (E.g. build up a set -# of deferred motions?) -# - Use internal naming scheme to control whether 'saxs'/'waxs' is put in the -# filename -################################################################################ - - -import time -import re -import os -import shutil - - - -class CoordinateSystem(object): - """ - A generic class defining a coordinate system. Several coordinate systems - can be layered on top of one another (with a reference to the underlying - coordinate system given by the 'base_stage' pointer). When motion of a given - CoordinateSystem is requested, the motion is passed (with coordinate - conversion) to the underlying stage. - """ - - hint_replacements = { 'positive': 'negative', - 'up': 'down', - 'left': 'right', - 'towards': 'away from', - 'downstream': 'upstream', - 'inboard': 'outboard', - 'clockwise': 'counterclockwise', - 'CW': 'CCW', - } - - - # Core methods - ######################################## - - def __init__(self, name='', base=None, **kwargs): - '''Create a new CoordinateSystem (e.g. a stage or a sample). - - Parameters - ---------- - name : str - Name for this stage/sample. - base : Stage - The stage on which this stage/sample sits. - ''' - - self.name = name - self.base_stage = base - - - self.enabled = True - - self.md = {} - self._marks = {} - - self._set_axes_definitions() - self._init_axes(self._axes_definitions) - - - def _set_axes_definitions(self): - '''Internal function which defines the axes for this stage. This is kept - as a separate function so that it can be over-ridden easily.''' - - # The _axes_definitions array holds a list of dicts, each defining an axis - self._axes_definitions = [] - - - def _init_axes(self, axes): - '''Internal method that generates method names to control the various axes.''' - - # Note: Instead of defining CoordinateSystem() having methods '.x', '.xr', - # '.y', '.yr', etc., we programmatically generate these methods when the - # class (and subclasses) are instantiated. - # Thus, the Axis() class has generic versions of these methods, which are - # appropriated renamed (bound, actually) when a class is instantiated. - - self._axes = {} - - for axis in axes: - - axis_object = Axis(axis['name'], axis['motor'], axis['enabled'], axis['scaling'], axis['units'], axis['hint'], self.base_stage, stage=self) - self._axes[axis['name']] = axis_object - - # Bind the methods of axis_object to appropriately-named methods of - # the CoordinateSystem() class. - setattr(self, axis['name'], axis_object.get_position ) - setattr(self, axis['name']+'abs', axis_object.move_absolute ) - setattr(self, axis['name']+'r', axis_object.move_relative ) - setattr(self, axis['name']+'pos', axis_object.get_position ) - setattr(self, axis['name']+'posMotor', axis_object.get_motor_position ) - - - setattr(self, axis['name']+'units', axis_object.get_units ) - setattr(self, axis['name']+'hint', axis_object.get_hint ) - setattr(self, axis['name']+'info', axis_object.get_info ) - - setattr(self, axis['name']+'set', axis_object.set_current_position ) - setattr(self, axis['name']+'o', axis_object.goto_origin ) - setattr(self, axis['name']+'setOrigin', axis_object.set_origin ) - setattr(self, axis['name']+'mark', axis_object.mark ) - - setattr(self, axis['name']+'search', axis_object.search ) - setattr(self, axis['name']+'scan', axis_object.scan ) - setattr(self, axis['name']+'c', axis_object.center ) - - - def comment(self, text, logbooks=None, tags=None, append_md=True, **md): - '''Add a comment related to this CoordinateSystem.''' - - text += '\n\n[comment for CoordinateSystem: {} ({})].'.format(self.name, self.__class__.__name__) - - if append_md: - - md_current = { k : v for k, v in RE.md.items() } # Global md - md_current.update(get_beamline().get_md()) # Beamline md - - # Self md - #md_current.update(self.get_md()) - - # Specified md - md_current.update(md) - - text += '\n\n\nMetadata\n----------------------------------------' - for key, value in sorted(md_current.items()): - text += '\n{}: {}'.format(key, value) - - - logbook.log(text, logbooks=logbooks, tags=tags) - - - def set_base_stage(self, base): - - self.base_stage = base - self._init_axes(self._axes_definitions) - - - # Convenience/helper methods - ######################################## - - - def multiple_string_replacements(self, text, replacements, word_boundaries=False): - '''Peform multiple string replacements simultaneously. Matching is case-insensitive. - - Parameters - ---------- - text : str - Text to return modified - replacements : dictionary - Replacement pairs - word_boundaries : bool, optional - Decides whether replacements only occur for words. - ''' - - # Code inspired from: - # http://stackoverflow.com/questions/6116978/python-replace-multiple-strings - # Note inclusion of r'\b' sequences forces the regex-match to occur at word-boundaries. - - if word_boundaries: - replacements = dict((r'\b'+re.escape(k.lower())+r'\b', v) for k, v in replacements.items()) - pattern = re.compile("|".join(replacements.keys()), re.IGNORECASE) - text = pattern.sub(lambda m: replacements[r'\b'+re.escape(m.group(0).lower())+r'\b'], text) - - else: - replacements = dict((re.escape(k.lower()), v) for k, v in replacements.items()) - pattern = re.compile("|".join(replacements.keys()), re.IGNORECASE) - text = pattern.sub(lambda m: rep[re.escape(m.group(0))], text) - - return text - - - def _hint_replacements(self, text): - '''Convert a motor-hint into its logical inverse.''' - - # Generates all the inverse replacements - replacements = dict((v, k) for k, v in self.hint_replacements.items()) - replacements.update(self.hint_replacements) - - return self.multiple_string_replacements(text, replacements, word_boundaries=True) - - - # Control methods - ######################################## - def setTemperature(self, temperature, verbosity=3): - if verbosity>=1: - print('Temperature functions not implemented in {}'.format(self.__class__.__name__)) - - - def temperature(self, verbosity=3): - if verbosity>=1: - print('Temperature functions not implemented in {}'.format(self.__class__.__name__)) - - return 0.0 - - - # Motion methods - ######################################## - - - def enable(self): - self.enabled = True - - - def disable(self): - self.enabled = False - - - def is_enabled(self): - return self.enabled - - - def pos(self, verbosity=3): - '''Return (and print) the positions of all axes associated with this - stage/sample.''' - - out = {} - for axis_name, axis_object in sorted(self._axes.items()): - out[axis_name] = axis_object.get_position(verbosity=verbosity) - #if verbosity>=2: print('') # \n - - return out - - def hints(self, verbosity=3): - '''Return (and print) the hints of all axes associated with this - stage/sample.''' - - out = {} - for axis_name, axis_object in sorted(self._axes.items()): - if verbosity>=2: print('{:s}'.format(axis_name)) - out[axis_name] = axis_object.get_hint(verbosity=verbosity) - if verbosity>=2: print('') # \n - - return out - - - def origin(self, verbosity=3): - '''Returns the origin for axes.''' - - out = {} - for axis_name, axis_object in sorted(self._axes.items()): - origin = axis_object.get_origin() - if verbosity>=2: print('{:s} origin = {:.3f} {:s}'.format(axis_name, origin, axis_object.get_units())) - out[axis_name] = origin - - return out - - - def gotoOrigin(self, axes=None): - '''Go to the origin (zero-point) for this stage. All axes are zeroed, - unless one specifies the axes to move.''' - - # TODO: Guard against possibly buggy behavior if 'axes' is a string instead of a list. - # (Python will happily iterate over the characters in a string.) - - if axes is None: - axes_to_move = self._axes.values() - - else: - axes_to_move = [self._axes[axis_name] for axis_name in axes] - - for axis in axes_to_move: - axis.goto_origin() - - - def setOrigin(self, axes, positions=None): - '''Define the current position as the zero-point (origin) for this stage/ - sample. The axes to be considered in this redefinition must be supplied - as a list. - - If the optional positions parameter is passed, then those positions are - used to define the origins for the axes.''' - - if positions is None: - - for axis in axes: - getattr(self, axis+'setOrigin')() - - else: - for axis, pos in zip(axes, positions): - getattr(self, axis+'setOrigin')(pos) - - - def gotoAlignedPosition(self): - '''Goes to the currently-defined 'aligned' position for this stage. If - no specific aligned position is defined, then the zero-point for the stage - is used instead.''' - - # TODO: Optional offsets? (Like goto mark?) - - if 'aligned_position' in self.md and self.md['aligned_position'] is not None: - for axis_name, position in self.md['aligned_position'].items(): - self._axes[axis_name].move_absolute(position) - - else: - self.gotoOrigin() - - - - - - # Motion logging - ######################################## - - def setAlignedPosition(self, axes): - '''Saves the current position as the 'aligned' position for this stage/ - sample. This allows one to return to this position later. One must - specify the axes to be considered. - - WARNING: Currently this position data is not saved persistently. E.g. it will - be lost if you close and reopen the console. - ''' - - positions = {} - for axis_name in axes: - positions[axis_name] = self._axes[axis_name].get_position(verbosity=0) - - self.attributes['aligned_position'] = positions - - - def mark(self, label, *axes, **axes_positions): - '''Set a mark for the stage/sample/etc. - - 'Marks' are locations that have been labelled, which is useful for - later going to a labelled position (using goto), or just to keep track - of sample information (metadata). - - By default, the mark is set at the current position. If no 'axes' are - specified, all motors are logged. Alternately, axes (as strings) can - be specified. If axes_positions are given as keyword arguments, then - positions other than the current position can be specified. - ''' - - positions = {} - - if len(axes)==0 and len(axes_positions)==0: - - for axis_name in self._axes: - positions[axis_name] = self._axes[axis_name].get_position(verbosity=0) - - else: - for axis_name in axes: - positions[axis_name] = self._axes[axis_name].get_position(verbosity=0) - - for axis_name, position in axes_positions.items(): - positions[axis_name] = position - - self._marks[label] = positions - - - def marks(self, verbosity=3): - '''Get a list of the current marks on the stage/sample/etc. 'Marks' - are locations that have been labelled, which is useful for later - going to a labelled position (using goto), or just to keep track - of sample information (metadata).''' - - if verbosity>=3: - print('Marks for {:s} (class {:s}):'.format(self.name, self.__class__.__name__)) - - if verbosity>=2: - for label, positions in self._marks.items(): - print(label) - for axis_name, position in sorted(positions.items()): - print(' {:s} = {:.4f} {:s}'.format(axis_name, position, self._axes[axis_name].get_units())) - - return self._marks - - - def goto(self, label, verbosity=3, **additional): - '''Move the stage/sample to the location given by the label. For this - to work, the specified label must have been 'marked' at some point. - - Additional keyword arguments can be provided. For instance, to move - 3 mm from the left edge: - sam.goto('left edge', xr=+3.0) - ''' - - if label not in self._marks: - if verbosity>=1: - print("Label '{:s}' not recognized. Use '.marks()' for the list of marked positions.".format(label)) - return - - for axis_name, position in sorted(self._marks[label].items()): - - if axis_name+'abs' in additional: - # Override the marked value for this position - position = additional[axis_name+'abs'] - del(additional[axis_name+'abs']) - - - #relative = 0.0 if axis_name+'r' not in additional else additional[axis_name+'r'] - if axis_name+'r' in additional: - relative = additional[axis_name+'r'] - del(additional[axis_name+'r']) - else: - relative = 0.0 - - self._axes[axis_name].move_absolute(position+relative, verbosity=verbosity) - - - # Handle any optional motions not already covered - for command, amount in additional.items(): - if command[-1]=='r': - getattr(self, command)(amount, verbosity=verbosity) - elif command[-3:]=='abs': - getattr(self, command)(amount, verbosity=verbosity) - else: - print("Keyword argument '{}' not understood (should be 'r' or 'abs').".format(command)) - - - # State methods - ######################################## - def save_state(self): - '''Outputs a string you can use to re-initialize this object back - to its current state.''' - #TODO: Save to databroker? - - state = { 'origin': {} } - for axis_name, axis in self._axes.items(): - state['origin'][axis_name] = axis.origin - - return state - - - def restore_state(self, state): - '''Outputs a string you can use to re-initialize this object back - to its current state.''' - - for axis_name, axis in self._axes.items(): - axis.origin = state['origin'][axis_name] - - - # End class CoordinateSystem(object) - ######################################## - - - - -class Axis(object): - '''Generic motor axis. - - Meant to be used within a CoordinateSystem() or Stage() object. - ''' - - def __init__(self, name, motor, enabled, scaling, units, hint, base, stage=None, origin=0.0): - - self.name = name - self.motor = motor - self.enabled = enabled - self.scaling = scaling - self.units = units - self.hint = hint - - self.base_stage = base - self.stage = stage - - self.origin = 0.0 - - - - self._move_settle_max_time = 10.0 - self._move_settle_period = 0.05 - self._move_settle_tolerance = 0.01 - - - - # Coordinate transformations - ######################################## - - - def cur_to_base(self, position): - '''Convert from this coordinate system to the coordinate in the (immediate) base.''' - - base_position = self.get_origin() + self.scaling*position - - return base_position - - - def base_to_cur(self, base_position): - '''Convert from this base position to the coordinate in the current system.''' - - position = (base_position - self.get_origin())/self.scaling - - return position - - - def cur_to_motor(self, position): - '''Convert from this coordinate system to the underlying motor.''' - - if self.motor is not None: - return self.cur_to_base(position) - - else: - base_position = self.cur_to_base(position) - return self.base_stage._axes[self.name].cur_to_motor(base_position) - - def motor_to_cur(self, motor_position): - '''Convert a motor position into the current coordinate system.''' - - if self.motor is not None: - return self.base_to_cur(motor_position) - - else: - base_position = self.base_stage._axes[self.name].motor_to_cur(motor_position) - return self.base_to_cur(base_position) - - - - # Programmatically-defined methods - ######################################## - # Note: Instead of defining CoordinateSystem() having methods '.x', '.xr', - # '.xp', etc., we programmatically generate these methods when the class - # (and subclasses) are instantiated. - # Thus, the Axis() class has generic versions of these methods, which are - # appropriated renamed (bound, actually) when a class is instantiated. - def get_position(self, verbosity=3): - '''Return the current position of this axis (in its coordinate system). - By default, this also prints out the current position.''' - - - if self.motor is not None: - base_position = self.motor.position - - else: - verbosity_c = verbosity if verbosity>=4 else 0 - base_position = getattr(self.base_stage, self.name+'pos')(verbosity=verbosity_c) - - position = self.base_to_cur(base_position) - - - if verbosity>=2: - if self.stage: - stg = self.stage.name - else: - stg = '?' - - if verbosity>=5 and self.motor is not None: - print( '{:s} = {:.3f} {:s}'.format(self.motor.name, base_position, self.get_units()) ) - - print( '{:s}.{:s} = {:.3f} {:s} (origin = {:.3f})'.format(stg, self.name, position, self.get_units(), self.get_origin()) ) - - - return position - - - def get_motor_position(self, verbosity=3): - '''Returns the position of this axis, traced back to the underlying - motor.''' - - if self.motor is not None: - return self.motor.position - - else: - return getattr(self.base_stage, self.name+'posMotor')(verbosity=verbosity) - #return self.base_stage._axes[self.name].get_motor_position(verbosity=verbosity) - - - def move_absolute(self, position=None, wait=True, verbosity=3): - '''Move axis to the specified absolute position. The position is given - in terms of this axis' current coordinate system. The "defer" argument - can be used to defer motions until "move" is called.''' - - - if position is None: - # If called without any argument, just print the current position - return self.get_position(verbosity=verbosity) - - # Account for coordinate transformation - base_position = self.cur_to_base(position) - - if self.is_enabled(): - - if self.motor: - #mov( self.motor, base_position ) - self.motor.user_setpoint.value = base_position - - else: - # Call self.base_stage.xabs(base_position) - getattr(self.base_stage, self.name+'abs')(base_position, verbosity=0) - - - if self.stage: - stg = self.stage.name - else: - stg = '?' - - if verbosity>=2: - - # Show a realtime output of position - start_time = time.time() - current_position = self.get_position(verbosity=0) - while abs(current_position-position)>self._move_settle_tolerance and (time.time()-start_time)=1: - #current_position = self.get_position(verbosity=0) - #print( '{:s}.{:s} = {:5.3f} {:s} '.format(stg, self.name, current_position, self.get_units())) - - - elif verbosity>=1: - print( 'Axis %s disabled (stage %s).' % (self.name, self.stage.name) ) - - - - def move_relative(self, move_amount=None, verbosity=3): - '''Move axis relative to the current position.''' - - if move_amount is None: - # If called without any argument, just print the current position - return self.get_position(verbosity=verbosity) - - target_position = self.get_position(verbosity=0) + move_amount - - return self.move_absolute(target_position, verbosity=verbosity) - - - def goto_origin(self): - '''Move axis to the currently-defined origin (zero-point).''' - - self.move_absolute(0) - - - def set_origin(self, origin=None): - '''Sets the origin (zero-point) for this axis. If no origin is supplied, - the current position is redefined as zero. Alternatively, you can supply - a position (in the current coordinate system of the axis) that should - henceforth be considered zero.''' - - if origin is None: - # Use current position - if self.motor is not None: - self.origin = self.motor.position - - else: - if self.base_stage is None: - print("Error: %s %s has 'base_stage' and 'motor' set to 'None'." % (self.__class__.__name__, self.name)) - else: - self.origin = getattr(self.base_stage, self.name+'pos')(verbosity=0) - - else: - # Use supplied value (in the current coordinate system) - base_position = self.cur_to_base(origin) - self.origin = base_position - - - def set_current_position(self, new_position): - '''Redefines the position value of the current position.''' - current_position = self.get_position(verbosity=0) - self.origin = self.get_origin() + (current_position - new_position)*self.scaling - - - def search(self, step_size=1.0, min_step=0.05, intensity=None, target=0.5, detector=None, detector_suffix=None, polarity=+1, verbosity=3): - '''Moves this axis, searching for a target value. - - Parameters - ---------- - step_size : float - The initial step size when moving the axis - min_step : float - The final (minimum) step size to try - intensity : float - The expected full-beam intensity readout - target : 0.0 to 1.0 - The target ratio of full-beam intensity; 0.5 searches for half-max. - The target can also be 'max' to find a local maximum. - detector, detector_suffix - The beamline detector (and suffix, such as '_stats4_total') to trigger to measure intensity - polarity : +1 or -1 - Positive motion assumes, e.g. a step-height 'up' (as the axis goes more positive) - ''' - - if not get_beamline().beam.is_on(): - print('WARNING: Experimental shutter is not open.') - - - if intensity is None: - intensity = RE.md['beam_intensity_expected'] - - - if detector is None: - #detector = gs.DETS[0] - detector = get_beamline().detector[0] - if detector_suffix is None: - #value_name = gs.TABLE_COLS[0] - value_name = get_beamline().TABLE_COLS[0] - else: - value_name = detector.name + detector_suffix - - bec.disable_table() - - - # Check current value - RE(count([detector])) - value = detector.read()[value_name]['value'] - - - if target is 'max': - - if verbosity>=5: - print("Performing search on axis '{}' target is 'max'".format(self.name)) - - max_value = value - max_position = self.get_position(verbosity=0) - - - direction = +1*polarity - - while step_size>=min_step: - if verbosity>=4: - print(" move {} by {} × {}".format(self.name, direction, step_size)) - self.move_relative(move_amount=direction*step_size, verbosity=verbosity-2) - - prev_value = value - RE(count([detector])) - - value = detector.read()[value_name]['value'] - if verbosity>=3: - print(" {} = {:.3f} {}; value : {}".format(self.name, self.get_position(verbosity=0), self.units, value)) - - if value>max_value: - max_value = value - max_position = self.get_position(verbosity=0) - - if value>prev_value: - # Keep going in this direction... - pass - else: - # Switch directions! - direction *= -1 - step_size *= 0.5 - - - elif target is 'min': - - if verbosity>=5: - print("Performing search on axis '{}' target is 'min'".format(self.name)) - - direction = +1*polarity - - while step_size>=min_step: - if verbosity>=4: - print(" move {} by {} × {}".format(self.name, direction, step_size)) - self.move_relative(move_amount=direction*step_size, verbosity=verbosity-2) - - prev_value = value - RE(count([detector])) - value = detector.read()[value_name]['value'] - if verbosity>=3: - print(" {} = {:.3f} {}; value : {}".format(self.name, self.get_position(verbosity=0), self.units, value)) - - if value=5: - print("Performing search on axis '{}' target {} × {} = {}".format(self.name, target_rel, intensity, target)) - if verbosity>=4: - print(" value : {} ({:.1f}%)".format(value, 100.0*value/intensity)) - - - # Determine initial motion direction - if value>target: - direction = -1*polarity - else: - direction = +1*polarity - - while step_size>=min_step: - - if verbosity>=4: - print(" move {} by {} × {}".format(self.name, direction, step_size)) - self.move_relative(move_amount=direction*step_size, verbosity=verbosity-2) - - RE(count([detector])) - value = detector.read()[value_name]['value'] - if verbosity>=3: - print(" {} = {:.3f} {}; value : {} ({:.1f}%)".format(self.name, self.get_position(verbosity=0), self.units, value, 100.0*value/intensity)) - - # Determine direction - if value>target: - new_direction = -1.0*polarity - else: - new_direction = +1.0*polarity - - if abs(direction-new_direction)<1e-4: - # Same direction as we've been going... - # ...keep moving this way - pass - else: - # Switch directions! - direction *= -1 - step_size *= 0.5 - - bec.enable_table() - - - def scan(self): - print('todo') - - def center(self): - print('todo') - - def mark(self, label, position=None, verbosity=3): - '''Set a mark for this axis. (By default, the current position is - used.)''' - - if position is None: - position = self.get_position(verbosity=0) - - axes_positions = { self.name : position } - self.stage.mark(label, **axes_positions) - - - - - - # Book-keeping - ######################################## - - def enable(self): - self.enabled = True - - - def disable(self): - self.enabled = False - - - def is_enabled(self): - - return self.enabled and self.stage.is_enabled() - - - def get_origin(self): - - return self.origin - - - def get_units(self): - - if self.units is not None: - return self.units - - else: - return getattr(self.base_stage, self.name+'units')() - - - def get_hint(self, verbosity=3): - '''Return (and print) the "motion hint" associated with this axis. This - hint gives information about the expected directionality of the motion.''' - - if self.hint is not None: - s = '%s\n%s' % (self.hint, self.stage._hint_replacements(self.hint)) - if verbosity>=2: - print(s) - return s - - else: - return getattr(self.base_stage, self.name+'hint')(verbosity=verbosity) - - - def get_info(self, verbosity=3): - '''Returns information about this axis.''' - - self.get_position(verbosity=verbosity) - self.get_hint(verbosity=verbosity) - - - def check_base(self): - if self.base_stage is None: - print("Error: %s %s has 'base_stage' set to 'None'." % (self.__class__.__name__, self.name)) - - - - - - -class Sample_Generic(CoordinateSystem): - """ - The Sample() classes are used to define a single, individual sample. Each - sample is created with a particular name, which is recorded during measurements. - Logging of comments also includes the sample name. Different Sample() classes - can define different defaults for alignment, measurement, etc. - """ - - - # Core methods - ######################################## - def __init__(self, name, base=None, **md): - '''Create a new Sample object. - - Parameters - ---------- - name : str - Name for this sample. - base : Stage - The stage/holder on which this sample sits. - ''' - - if base is None: - base = get_default_stage() - #print("Note: No base/stage/holder specified for sample '{:s}'. Assuming '{:s}' (class {:s})".format(name, base.name, base.__class__.__name__)) - - - super().__init__(name=name, base=base) - - self.name = name - - - self.md = { - 'exposure_time' : 1.0 , - 'measurement_ID' : 1 , - } - self.md.update(md) - - self.naming_scheme = ['name', 'extra', 'exposure_time','id'] - self.naming_delimeter = '_' - - - # TODO - #if base is not None: - #base.addSample(self) - - - self.reset_clock() - - - def _set_axes_definitions(self): - '''Internal function which defines the axes for this stage. This is kept - as a separate function so that it can be over-ridden easily.''' - - # The _axes_definitions array holds a list of dicts, each defining an axis - self._axes_definitions = [ {'name': 'x', - 'motor': None, - 'enabled': True, - 'scaling': +1.0, - 'units': None, - 'hint': None, - }, - {'name': 'y', - 'motor': None, - 'enabled': True, - 'scaling': +1.0, - 'units': 'mm', - 'hint': None, - }, - #{'name': 'z', - #'motor': None, - #'enabled': False, - #'scaling': +1.0, - #'units': 'mm', - #'hint': None, - #}, - {'name': 'th', - 'motor': None, - 'enabled': True, - 'scaling': +1.0, - 'units': 'deg', - 'hint': None, - }, - #{'name': 'chi', - #'motor': None, - #'enabled': True, - #'scaling': +1.0, - #'units': 'deg', - #'hint': None, - #}, - #{'name': 'phi', - #'motor': None, - #'enabled': True, - #'scaling': +1.0, - #'units': 'deg', - #'hint': None, - #}, - #{'name': 'yy', - #'motor': None, - #'enabled': True, - #'scaling': +1.0, - #'units': 'mm', - #'hint': None, - #}, - ] - - - - # Metadata methods - ######################################## - # These involve setting or getting values associated with this sample. - - def clock(self): - '''Return the current value of the "clock" variable. This provides a - way to set a clock/timer for a sample. For instance, you can call - "reset_clock" when you initiate some change to the sample. Thereafter, - the "clock" method lets you check how long it has been since that - event.''' - - clock_delta = time.time() - self.clock_zero - return clock_delta - - - def reset_clock(self): - '''Resets the sample's internal clock/timer to zero.''' - - self.clock_zero = time.time() - - return self.clock() - - - - def get_attribute(self, attribute): - '''Return the value of the requested md.''' - - if attribute in self._axes: - return self._axes[attribute].get_position(verbosity=0) - - if attribute=='name': - return self.name - - if attribute=='clock': - return self.clock() - - if attribute=='temperature': - return self.temperature(verbosity=0) - if attribute=='temperature_A': - return self.temperature(temperature_probe='A', verbosity=0) - if attribute=='temperature_B': - return self.temperature(temperature_probe='B',verbosity=0) - if attribute=='temperature_C': - return self.temperature(temperature_probe='C',verbosity=0) - if attribute=='temperature_D': - return self.temperature(temperature_probe='D',verbosity=0) - - - if attribute in self.md: - return self.md[attribute] - - - replacements = { - 'id' : 'measurement_ID' , - 'ID' : 'measurement_ID' , - 'extra' : 'savename_extra' , - } - - if attribute in replacements: - return self.md[replacements[attribute]] - - return None - - - def set_attribute(self, attribute, value): - '''Arbitrary attributes can be set and retrieved. You can use this to - store additional meta-data about the sample. - - WARNING: Currently this meta-data is not saved anywhere. You can opt - to store the information in the sample filename (using "naming"). - ''' - - self.md[attribute] = value - - - def set_md(self, **md): - - self.md.update(md) - - - - def get_md(self, prefix='sample_', include_marks=True, **md): - '''Returns a dictionary of the current metadata. - The 'prefix' argument is prepended to all the md keys, which allows the - metadata to be grouped with other metadata in a clear way. (Especially, - to make it explicit that this metadata came from the sample.)''' - - # Update internal md - #self.md['key'] = value - - - md_return = self.md.copy() - md_return['name'] = self.name - - - if include_marks: - for label, positions in self._marks.items(): - md_return['mark_'+label] = positions - - - # Add md that varies over time - md_return['clock'] = self.clock() - md_return['temperature'] = self.temperature(temperature_probe='A', verbosity=0) - md_return['temperature_A'] = self.temperature(temperature_probe='A', verbosity=0) - md_return['temperature_B'] = self.temperature(temperature_probe='B', verbosity=0) - md_return['temperature_C'] = self.temperature(temperature_probe='C', verbosity=0) - md_return['temperature_D'] = self.temperature(temperature_probe='D', verbosity=0) - - for axis_name, axis in self._axes.items(): - md_return[axis_name] = axis.get_position(verbosity=0) - md_return['motor_'+axis_name] = axis.get_motor_position(verbosity=0) - - - md_return['savename'] = self.get_savename() # This should be over-ridden by 'measure' - - - # Include the user-specified metadata - md_return.update(md) - - - # Add an optional prefix - if prefix is not None: - md_return = { '{:s}{:s}'.format(prefix, key) : value for key, value in md_return.items() } - - return md_return - - - - - - - # Naming scheme methods - ######################################## - # These allow the user to control how data is named. - - def naming(self, scheme=['name', 'extra', 'exposure_time','id'], delimeter='_'): - '''This method allows one to define the naming convention that will be - used when storing data for this sample. The "scheme" variable is an array - that lists the various elements one wants to store in the filename. - - Each entry in "scheme" is a string referring to a particular element/ - value. For instance, motor names can be stored ("x", "y", etc.), the - measurement time can be stored, etc.''' - - self.naming_scheme = scheme - self.naming_delimeter = delimeter - - - def get_naming_string(self, attribute): - - # Handle special cases of formatting the text - - if attribute in self._axes: - return '{:s}{:.3f}'.format(attribute, self._axes[attribute].get_position(verbosity=0)) - - if attribute=='clock': - return '{:.1f}s'.format(self.get_attribute(attribute)) - - if attribute=='exposure_time': - return '{:.2f}s'.format(self.get_attribute(attribute)) - - if attribute=='temperature': - return 'T{:.3f}C'.format(self.get_attribute(attribute)) - if attribute=='temperature_A': - return 'T{:.3f}C'.format(self.get_attribute(attribute)) - if attribute=='temperature_B': - return 'T{:.3f}C'.format(self.get_attribute(attribute)) - if attribute=='temperature_C': - return 'T{:.3f}C'.format(self.get_attribute(attribute)) - if attribute=='temperature_D': - return 'T{:.3f}C'.format(self.get_attribute(attribute)) - - - if attribute=='extra': - # Note: Don't eliminate this check; it will not be properly handled - # by the generic call below. When 'extra' is None, we should - # return None, so that it gets skipped entirely. - return self.get_attribute('savename_extra') - - if attribute=='spot_number': - return 'spot{:d}'.format(self.get_attribute(attribute)) - - - # Generically: lookup the attribute and convert to string - - att = self.get_attribute(attribute) - if att is None: - # If the attribute is not found, simply return the text. - # This allows the user to insert arbitrary text info into the - # naming scheme. - return attribute - - else: - return str(att) - - - def get_savename(self, savename_extra=None): - '''Return the filename that will be used to store data for the upcoming - measurement. The method "naming" lets one control what gets stored in - the filename.''' - - if savename_extra is not None: - self.set_attribute('savename_extra', savename_extra) - - attribute_strings = [] - for attribute in self.naming_scheme: - s = self.get_naming_string(attribute) - if s is not None: - attribute_strings.append(s) - - self.set_attribute('savename_extra', None) - - savename = self.naming_delimeter.join(attribute_strings) - - # Avoid 'dangerous' characters - savename = savename.replace(' ', '_') - #savename = savename.replace('.', 'p') - savename = savename.replace('/', '-slash-') - - return savename - - - - # Logging methods - ######################################## - - def comment(self, text, logbooks=None, tags=None, append_md=True, **md): - '''Add a comment related to this sample.''' - - text += '\n\n[comment for sample: {} ({})].'.format(self.name, self.__class__.__name__) - - if append_md: - - md_current = { k : v for k, v in RE.md.items() } # Global md - md_current.update(get_beamline().get_md()) # Beamline md - - # Sample md - md_current.update(self.get_md()) - - # Specified md - md_current.update(md) - - text += '\n\n\nMetadata\n----------------------------------------' - for key, value in sorted(md_current.items()): - text += '\n{}: {}'.format(key, value) - - - logbook.log(text, logbooks=logbooks, tags=tags) - - - def log(self, text, logbooks=None, tags=None, append_md=True, **md): - - if append_md: - - text += '\n\n\nMetadata\n----------------------------------------' - for key, value in sorted(md.items()): - text += '\n{}: {}'.format(key, value) - - logbook.log(text, logbooks=logbooks, tags=tags) - - - # Control methods - ######################################## - def setTemperature(self, temperature, verbosity=3): - return self.base_stage.setTemperature(temperature, verbosity=verbosity) - - - def temperature(self, verbosity=3): - return self.base_stage.temperature(verbosity=verbosity) - - - - # Measurement methods - ######################################## - - def get_measurement_md(self, prefix=None, **md): - - #md_current = {} - md_current = { k : v for k, v in RE.md.items() } # Global md - - #md_current['detector_sequence_ID'] = caget('XF:11BMB-ES{Det:SAXS}:cam1:FileNumber_RBV') - #md_current['detector_sequence_ID'] = caget('XF:11BMB-ES{}:cam1:FileNumber_RBV'.format(pilatus_Epicsname)) - if get_beamline().detector[0].name is 'pilatus300': - md_current['detector_sequence_ID'] = caget('XF:11BMB-ES{Det:SAXS}:cam1:FileNumber_RBV') - elif get_beamline().detector[0].name is 'pilatus2M': - md_current['detector_sequence_ID'] = caget('XF:11BMB-ES{Det:PIL2M}:cam1:FileNumber_RBV') - - md_current.update(get_beamline().get_md()) - - md_current.update(md) - - # Add an optional prefix - if prefix is not None: - md_return = { '{:s}{:s}'.format(prefix, key) : value for key, value in md_return.items() } - - return md_current - - - def _expose_manual(self, exposure_time=None, verbosity=3, poling_period=0.1, **md): - '''Internal function that is called to actually trigger a measurement.''' - - # TODO: Improve this (switch to Bluesky methods) - # TODO: Store metadata - - if 'measure_type' not in md: - md['measure_type'] = 'expose' - self.log('{} for {}.'.format(md['measure_type'], self.name), **md) - - if exposure_time is not None: - # Prep detector - #caput('XF:11BMB-ES{Det:SAXS}:cam1:AcquireTime', exposure_time) - #caput('XF:11BMB-ES{Det:SAXS}:cam1:AcquirePeriod', exposure_time+0.1) - #caput('XF:11BMB-ES{}:cam1:AcquireTime'.format(pilatus_Epicsname), exposure_time) - #caput('XF:11BMB-ES{}:cam1:AcquirePeriod'.format(pilatus_Epicsname), exposure_time+0.1) - - if get_beamline().detector[0].name is 'pilatus300': - caput('XF:11BMB-ES{Det:SAXS}:cam1:AcquireTime', exposure_time) - caput('XF:11BMB-ES{Det:SAXS}:cam1:AcquirePeriod', exposure_time+0.1) - elif get_beamline().detector[0].name is 'pilatus2M': - caput('XF:11BMB-ES{Det:PIL2M}:cam1:AcquireTime', exposure_time) - caput('XF:11BMB-ES{Det:PIL2M}:cam1:AcquirePeriod', exposure_time+0.1) - - get_beamline().beam.on() - - # Trigger acquisition manually - caput('XF:11BMB-ES{}:cam1:Acquire'.format(pilatus_Epicsname), 1) - - if verbosity>=2: - start_time = time.time() - while caget('XF:11BMB-ES{}:cam1:Acquire'.format(pilatus_Epicsname))==1 and (time.time()-start_time)<(exposure_time+20): - percentage = 100*(time.time()-start_time)/exposure_time - print( 'Exposing {:6.2f} s ({:3.0f}%) \r'.format((time.time()-start_time), percentage), end='') - time.sleep(poling_period) - else: - time.sleep(exposure_time) - - if verbosity>=3 and caget('XF:11BMB-ES{}:cam1:Acquire'.format(pilatus_Epicsname))==1: - print('Warning: Detector still not done acquiring.') - - get_beamline().beam.off() - - - def expose(self, exposure_time=None, extra=None, verbosity=3, poling_period=0.1, **md): - '''Internal function that is called to actually trigger a measurement.''' - '''TODO: **md doesnot work in RE(count). ''' - - if 'measure_type' not in md: - md['measure_type'] = 'expose' - #self.log('{} for {}.'.format(md['measure_type'], self.name), **md) - - - # Set exposure time - if exposure_time is not None: - #for detector in gs.DETS: - for detector in get_beamline().detector: - if detector.name is 'pilatus2M' and exposure_time != caget('XF:11BMB-ES{Det:PIL2M}:cam1:AcquireTime'): - detector.setExposureTime(exposure_time, verbosity=verbosity) - #extra wait time when changing the exposure time. - time.sleep(2) - elif detector.name is 'PhotonicSciences_CMS': - detector.setExposureTime(exposure_time, verbosity=verbosity) - - #extra wait time for adjusting pilatus2M - #time.sleep(2) - - # Do acquisition - get_beamline().beam.on() - - md['plan_header_override'] = md['measure_type'] - start_time = time.time() - - #md_current = self.get_md() - md['beam_int_bim3'] = beam.bim3.flux(verbosity=0) - md['beam_int_bim4'] = beam.bim4.flux(verbosity=0) - md['beam_int_bim5'] = beam.bim5.flux(verbosity=0) - #md.update(md_current) - - #uids = RE(count(get_beamline().detector, 1), **md) - uids = RE(count(get_beamline().detector), **md) - - #get_beamline().beam.off() - #print('shutter is off') - - # Wait for detectors to be ready - max_exposure_time = 0 - for detector in get_beamline().detector: - if detector.name is 'pilatus300': - current_exposure_time = caget('XF:11BMB-ES{Det:SAXS}:cam1:AcquireTime') - max_exposure_time = max(max_exposure_time, current_exposure_time) - elif detector.name is 'pilatus2M': - current_exposure_time = caget('XF:11BMB-ES{Det:PIL2M}:cam1:AcquireTime') - max_exposure_time = max(max_exposure_time, current_exposure_time) - elif detector.name is 'PhotonicSciences_CMS': - current_exposure_time = detector.exposure_time - max_exposure_time = max(max_exposure_time, current_exposure_time) - else: - if verbosity>=1: - print("WARNING: Didn't recognize detector '{}'.".format(detector.name)) - - if verbosity>=2: - status = 0 - while (status==0) and (time.time()-start_time)<(max_exposure_time+20): - percentage = 100*(time.time()-start_time)/max_exposure_time - print( 'Exposing {:6.2f} s ({:3.0f}%) \r'.format((time.time()-start_time), percentage), end='') - time.sleep(poling_period) - - status = 1 - for detector in get_beamline().detector: - if detector.name is 'pilatus300': - if caget('XF:11BMB-ES{Det:SAXS}:cam1:Acquire')==1: - status *= 0 - elif detector.name is 'pilatus2M': - if caget('XF:11BMB-ES{Det:PIL2M}:cam1:Acquire')==1: - status *= 0 - elif detector.name is 'PhotonicSciences_CMS': - if not detector.detector_is_ready(verbosity=0): - status *= 0 - print('') - - - else: - time.sleep(max_exposure_time) - - if verbosity>=3 and caget('XF:11BMB-ES{Det:SAXS}:cam1:Acquire')==1: - print('Warning: Detector pilatus300 still not done acquiring.') - - if verbosity>=3 and caget('XF:11BMB-ES{Det:PIL2M}:cam1:Acquire')==1: - print('Warning: Detector pilatus2M still not done acquiring.') - - - get_beamline().beam.off() - - for detector in get_beamline().detector: - #self.handle_file(detector, extra=extra, verbosity=verbosity, **md) - self.handle_file(detector, extra=extra, verbosity=verbosity) - - - - def handle_file(self, detector, extra=None, verbosity=3, subdirs=True, **md): - - subdir = '' - - if detector.name is 'pilatus300': - chars = caget('XF:11BMB-ES{Det:SAXS}:TIFF1:FullFileName_RBV') - filename = ''.join(chr(char) for char in chars)[:-1] - - # Alternate method to get the last filename - #filename = '{:s}/{:s}.tiff'.format( detector.tiff.file_path.get(), detector.tiff.file_name.get() ) - - if verbosity>=3: - print(' Data saved to: {}'.format(filename)) - - if subdirs: - subdir = '/saxs/' - - #if md['measure_type'] is not 'snap': - if True: - - self.set_attribute('exposure_time', caget('XF:11BMB-ES{Det:SAXS}:cam1:AcquireTime')) - - # Create symlink - #link_name = '{}/{}{}'.format(RE.md['experiment_alias_directory'], subdir, md['filename']) - #savename = md['filename'][:-5] - - savename = self.get_savename(savename_extra=extra) - link_name = '{}/{}{}_{:04d}_saxs.tiff'.format(RE.md['experiment_alias_directory'], subdir, savename, RE.md['scan_id']-1) - - if os.path.isfile(link_name): - i = 1 - while os.path.isfile('{}.{:d}'.format(link_name,i)): - i += 1 - os.rename(link_name, '{}.{:d}'.format(link_name,i)) - os.symlink(filename, link_name) - - if verbosity>=3: - print(' Data linked as: {}'.format(link_name)) - - elif detector.name is 'pilatus2M': - chars = caget('XF:11BMB-ES{Det:PIL2M}:TIFF1:FullFileName_RBV') - filename = ''.join(chr(char) for char in chars)[:-1] - - # Alternate method to get the last filename - #filename = '{:s}/{:s}.tiff'.format( detector.tiff.file_path.get(), detector.tiff.file_name.get() ) - - if verbosity>=3: - print(' Data saved to: {}'.format(filename)) - - if subdirs: - subdir = '/saxs/' - - #if md['measure_type'] is not 'snap': - if True: - - self.set_attribute('exposure_time', caget('XF:11BMB-ES{Det:PIL2M}:cam1:AcquireTime')) - - # Create symlink - #link_name = '{}/{}{}'.format(RE.md['experiment_alias_directory'], subdir, md['filename']) - #savename = md['filename'][:-5] - - savename = self.get_savename(savename_extra=extra) - #link_name = '{}/{}{}_{:04d}_saxs.tiff'.format(RE.md['experiment_alias_directory'], subdir, savename, RE.md['scan_id']) - link_name = '{}/{}{}_{:04d}_saxs.tiff'.format(RE.md['experiment_alias_directory'], subdir, savename, RE.md['scan_id']-1) - - if os.path.isfile(link_name): - i = 1 - while os.path.isfile('{}.{:d}'.format(link_name,i)): - i += 1 - os.rename(link_name, '{}.{:d}'.format(link_name,i)) - os.symlink(filename, link_name) - - if verbosity>=3: - print(' Data linked as: {}'.format(link_name)) - - elif detector.name is 'PhotonicSciences_CMS': - - self.set_attribute('exposure_time', detector.exposure_time) - - filename = '{:s}/{:s}.tif'.format( detector.file_path, detector.file_name ) - - if subdirs: - subdir = '/waxs/' - - #savename = md['filename'][:-5] - savename = self.get_savename(savename_extra=extra) - savename = '{}/{}{}_{:04d}_waxs.tiff'.format(RE.md['experiment_alias_directory'], subdir, savename, RE.md['scan_id']-1) - - shutil.copy(filename, savename) - if verbosity>=3: - print(' Data saved to: {}'.format(savename)) - - - else: - if verbosity>=1: - print("WARNING: Can't do file handling for detector '{}'.".format(detector.name)) - return - - - - - - - - def snap(self, exposure_time=None, extra=None, measure_type='snap', verbosity=3, **md): - '''Take a quick exposure (without saving data).''' - - self.measure(exposure_time=exposure_time, extra=extra, measure_type=measure_type, verbosity=verbosity, **md) - - - def measure(self, exposure_time=None, extra=None, measure_type='measure', verbosity=3, tiling=False, **md): - '''Measure data by triggering the area detectors. - - Parameters - ---------- - exposure_time : float - How long to collect data - extra : string, optional - Extra information about this particular measurement (which is typically - included in the savename/filename). - tiling : string - Controls the detector tiling mode. - None : regular measurement (single detector position) - 'ygaps' : try to cover the vertical gaps in the Pilatus300k - ''' - - if tiling is 'ygaps': - - extra_current = 'pos1' if extra is None else '{}_pos1'.format(extra) - md['detector_position'] = 'lower' - self.measure_single(exposure_time=exposure_time, extra=extra_current, measure_type=measure_type, verbosity=verbosity, **md) - - #movr(SAXSy, 5.16) # move detector up by 30 pixels; 30*0.172 = 5.16 - SAXSy.move(SAXSy.user_readback.value + 5.16) - extra_current = 'pos2' if extra is None else '{}_pos2'.format(extra) - md['detector_position'] = 'upper' - self.measure_single(exposure_time=exposure_time, extra=extra_current, measure_type=measure_type, verbosity=verbosity, **md) - - #movr(SAXSy, -5.16) - SAXSy.move(SAXSy.user_readback.value + -5.16) - - SAXSx.move(SAXSx.user_readback.value + 5.16) - extra_current = 'pos3' if extra is None else '{}_pos3'.format(extra) - md['detector_position'] = 'left' - self.measure_single(exposure_time=exposure_time, extra=extra_current, measure_type=measure_type, verbosity=verbosity, **md) - - SAXSx.move(SAXSx.user_readback.value + -5.16) - - #if tiling is 'big': - # TODO: Use multiple images to fill the entire detector motion range - - else: - # Just do a normal measurement - self.measure_single(exposure_time=exposure_time, extra=extra, measure_type=measure_type, verbosity=verbosity, **md) - - - - def measure_single(self, exposure_time=None, extra=None, measure_type='measure', verbosity=3, **md): - '''Measure data by triggering the area detectors. - - Parameters - ---------- - exposure_time : float - How long to collect data - extra : string, optional - Extra information about this particular measurement (which is typically - included in the savename/filename). - ''' - - if exposure_time is not None: - self.set_attribute('exposure_time', exposure_time) - #else: - #exposure_time = self.get_attribute('exposure_time') - - savename = self.get_savename(savename_extra=extra) - - #caput('XF:11BMB-ES{Det:SAXS}:cam1:FileName', savename) - - if verbosity>=2 and (get_beamline().current_mode != 'measurement'): - print("WARNING: Beamline is not in measurement mode (mode is '{}')".format(get_beamline().current_mode)) - - if verbosity>=1 and len(get_beamline().detector)<1: - print("ERROR: No detectors defined in cms.detector") - return - - md_current = self.get_md() - md_current.update(self.get_measurement_md()) - md_current['sample_savename'] = savename - md_current['measure_type'] = measure_type - #md_current['filename'] = '{:s}_{:04d}.tiff'.format(savename, md_current['detector_sequence_ID']) - md_current['filename'] = '{:s}_{:04d}.tiff'.format(savename, RE.md['scan_id']) - #md_current.update(md) - - - self.expose(exposure_time, extra=extra, verbosity=verbosity, **md_current) - #self.expose(exposure_time, extra=extra, verbosity=verbosity, **md) - - self.md['measurement_ID'] += 1 - - - def _test_time(self): - print(time.time()) - time.time() - - - def _test_measure_single(self, exposure_time=None, extra=None, shutteronoff=True, measure_type='measure', verbosity=3, **md): - '''Measure data by triggering the area detectors. - - Parameters - ---------- - exposure_time : float - How long to collect data - extra : string, optional - Extra information about this particular measurement (which is typically - included in the savename/filename). - ''' - - #print('1') #0s - #print(time.time()) - - if exposure_time is not None: - self.set_attribute('exposure_time', exposure_time) - #else: - #exposure_time = self.get_attribute('exposure_time') - - savename = self.get_savename(savename_extra=extra) - - #caput('XF:11BMB-ES{Det:SAXS}:cam1:FileName', savename) - - if verbosity>=2 and (get_beamline().current_mode != 'measurement'): - print("WARNING: Beamline is not in measurement mode (mode is '{}')".format(get_beamline().current_mode)) - - if verbosity>=1 and len(get_beamline().detector)<1: - print("ERROR: No detectors defined in cms.detector") - return - - #print('2') #0.0004s - #print(time.time()) - - md_current = self.get_md() - md_current['sample_savename'] = savename - md_current['measure_type'] = measure_type - - md_current.update(self.get_measurement_md()) - #md_current['filename'] = '{:s}_{:04d}.tiff'.format(savename, md_current['detector_sequence_ID']) - md_current['filename'] = '{:s}_{:04d}.tiff'.format(savename, RE.md['scan_id']) - md_current.update(md) - - #print('3') #0.032s - #print(time.time()) - - self._test_expose(exposure_time, shutteronoff=shutteronoff, extra=extra, verbosity=verbosity, **md_current) - - #print('4') #5.04s - #print(time.time()) - - self.md['measurement_ID'] += 1 - - #print('5') #5.0401 - #print(time.time()) - - def _test_expose(self, exposure_time=None, extra=None, verbosity=3, poling_period=0.1, shutteronoff=True, **md): - '''Internal function that is called to actually trigger a measurement.''' - - if 'measure_type' not in md: - md['measure_type'] = 'expose' - #self.log('{} for {}.'.format(md['measure_type'], self.name), **md) - - - # Set exposure time - if exposure_time is not None: - for detector in get_beamline().detector: - detector.setExposureTime(exposure_time, verbosity=verbosity) - - #print('1') #5e-5 - #print(self.clock()) - - # Do acquisition - # check shutteronoff, if - if shutteronoff == True: - get_beamline().beam.on() - else: - print('shutter is disabled') - - #print('2') #3.0 - #print(self.clock()) - - md['plan_header_override'] = md['measure_type'] - start_time = time.time() - print('2') #3.0 - print(self.clock()) - - #uids = RE(count(get_beamline().detector, 1), **md) - #uids = RE(count(get_beamline().detector), **md) - yield from (count(get_beamline().detector)) - print('3') #4.3172 - print(self.clock()) - - #get_beamline().beam.off() - #print('shutter is off') - - # Wait for detectors to be ready - max_exposure_time = 0 - for detector in get_beamline().detector: - if detector.name is 'pilatus300' or 'pilatus2M': - current_exposure_time = caget('XF:11BMB-ES{}:cam1:AcquireTime'.format(pilatus_Epicsname)) - max_exposure_time = max(max_exposure_time, current_exposure_time) - elif detector.name is 'PhotonicSciences_CMS': - current_exposure_time = detector.exposure_time - max_exposure_time = max(max_exposure_time, current_exposure_time) - else: - if verbosity>=1: - print("WARNING: Didn't recognize detector '{}'.".format(detector.name)) - - print('4') #4.3193 - print(self.clock()) - - if verbosity>=2: - status = 0 - print('status1 = ', status) - - while (status==0) and (time.time()-start_time)<(max_exposure_time+20): - percentage = 100*(time.time()-start_time)/max_exposure_time - print( 'Exposing {:6.2f} s ({:3.0f}%) \r'.format((time.time()-start_time), percentage), end='') - print('status2 = ', status) - - time.sleep(poling_period) - - status = 1 - for detector in get_beamline().detector: - if detector.name is 'pilatus300' or 'pilatus2M': - print('status2.5 = ', status) - if caget('XF:11BMB-ES{}:cam1:Acquire'.format(pilatus_Epicsname))==1: - status = 0 - print('status3 = ', status) - print('status3.5 = ', status) - - elif detector.name is 'PhotonicSciences_CMS': - if not detector.detector_is_ready(verbosity=0): - status = 0 - print('5') #3.0 - print(self.clock()) - print('6') #3.0 - print(self.clock()) - - - else: - time.sleep(max_exposure_time) - - #print('5') #4.4193 - #print(self.clock()) - - if verbosity>=3 and caget('XF:11BMB-ES{}:cam1:Acquire'.format(pilatus_Epicsname))==1: - print('Warning: Detector still not done acquiring.') - - if shutteronoff == True: - get_beamline().beam.off() - else: - print('shutter is disabled') - - #print('6') #4.9564 - #print(self.clock()) - - for detector in get_beamline().detector: - self.handle_file(detector, extra=extra, verbosity=verbosity, **md) - - #print('7') #4.9589 - #print(self.clock()) - - def _test_measureSpots(self, num_spots=4, translation_amount=0.2, axis='y', exposure_time=None, extra=None, shutteronoff=True, measure_type='measureSpots', tiling=False, **md): - '''Measure multiple spots on the sample.''' - - if 'spot_number' not in self.md: - self.md['spot_number'] = 1 - - start_time = time.time() - - for spot_num in range(num_spots): - - self._test_measure_single(exposure_time=exposure_time, extra=extra, measure_type=measure_type, shutteronoff=shutteronoff, tiling=tiling, **md) - - print(spot_num+1) - print(time.time()-start_time) - getattr(self, axis+'r')(translation_amount) - self.md['spot_number'] += 1 - print('{:d} of {:d} is done'.format(spot_num+1,num_spots)) - print(time.time()-start_time) - - def measureSpots(self, num_spots=4, translation_amount=0.2, axis='y', exposure_time=None, extra=None, measure_type='measureSpots', tiling=False, **md): - '''Measure multiple spots on the sample.''' - - if 'spot_number' not in self.md: - self.md['spot_number'] = 1 - - - for spot_num in range(num_spots): - - self.measure(exposure_time=exposure_time, extra=extra, measure_type=measure_type, tiling=tiling, **md) - - getattr(self, axis+'r')(translation_amount) - self.md['spot_number'] += 1 - print('{:d} of {:d} is done'.format(spot_num+1,num_spots)) - - - def measureTimeSeries(self, exposure_time=None, num_frames=10, wait_time=None, extra=None, measure_type='measureTimeSeries', verbosity=3, tiling=False, fix_name=True, **md): - - if fix_name and ('clock' not in self.naming_scheme): - self.naming_scheme_hold = self.naming_scheme - self.naming_scheme = self.naming_scheme_hold.copy() - self.naming_scheme.insert(-1, 'clock') - - - md['measure_series_num_frames'] = num_frames - - for i in range(num_frames): - - if verbosity>=3: - print('Measuring frame {:d}/{:d} ({:.1f}% complete).'.format(i+1, num_frames, 100.0*i/num_frames)) - - md['measure_series_current_frame'] = i+1 - self.measure(exposure_time=exposure_time, extra=extra, measure_type=measure_type, verbosity=verbosity, tiling=tiling, **md) - if wait_time is not None: - time.sleep(wait_time) - - def measureTimeSeriesAngles(self, exposure_time=None, num_frames=10, wait_time=None, extra=None, measure_type='measureTimeSeries', verbosity=3, tiling=False, fix_name=True, **md): - - if fix_name and ('clock' not in self.naming_scheme): - self.naming_scheme_hold = self.naming_scheme - self.naming_scheme = self.naming_scheme_hold.copy() - self.naming_scheme.insert(-1, 'clock') - - - md['measure_series_num_frames'] = num_frames - - for i in range(num_frames): - - if verbosity>=3: - print('Measuring frame {:d}/{:d} ({:.1f}% complete).'.format(i+1, num_frames, 100.0*i/num_frames)) - - md['measure_series_current_frame'] = i+1 - print('Angles in measure include: {}'.format(sam.incident_angles_default)) - self.measureIncidentAngles(exposure_time=exposure_time, extra=extra, **md) - if wait_time is not None: - time.sleep(wait_time) - #if (i % 2 ==0): - # self.xr(-1) - #else: - # self.xr(1) - #self.pos() - - - def measureTemperature(self, temperature, exposure_time=None, wait_time=None, temperature_probe='A', temperature_tolerance=0.4, extra=None, measure_type='measureTemperature', verbosity=3, tiling=False, poling_period=1.0, fix_name=True, **md): - - # Set new temperature - self.setTemperature(temperature, temperature_probe=temperature_probe, verbosity=verbosity) - - # Wait until we reach the temperature - while abs(self.temperature(temperature_probe=temperature_probe, verbosity=0) - temperature)>temperature_tolerance: - if verbosity>=3: - print(' setpoint = {:.3f}°C, Temperature = {:.3f}°C \r'.format(self.temperature_setpoint(temperature_probe=temperature_probe)-273.15, self.temperature(verbosity=0)), end='') - time.sleep(poling_period) - - # Allow for additional equilibration at this temperature - if wait_time is not None: - time.sleep(wait_time) - - # Measure - #if fix_name and ('temperature' not in self.naming_scheme): - # self.naming_scheme_hold = self.naming_scheme - # self.naming_scheme = self.naming_scheme_hold.copy() - # self.naming_scheme.insert(-1, 'temperature') - - - self.measure(exposure_time=exposure_time, extra=extra, measure_type=measure_type, verbosity=verbosity, tiling=tiling, **md) - - #self.naming_scheme = self.naming_scheme_hold - - - def measureTemperatures(self, temperatures, exposure_time=None, wait_time=None, temperature_probe='A', temperature_tolerance=0.4, extra=None, measure_type='measureTemperature', verbosity=3, tiling=False, poling_period=1.0, fix_name=True, **md): - - for temperature in temperatures: - self.measureTemperature(temperature, exposure_time=exposure_time, wait_time=wait_time, temperature_probe=temperature_probe, temperature_tolerance=temperature_tolerance, measure_type=measure_type, verbosity=verbosity, tiling=tiling, poling_period=poling_period, fix_name=fix_name, **md) - - - def do(self, step=0, verbosity=3, **md): - '''Performs the "default action" for this sample. This usually means - aligning the sample, and taking data. - - The 'step' argument can optionally be given to jump to a particular - step in the sequence.''' - - if verbosity>=4: - print(' doing sample {}'.format(self.name)) - - if step<=1: - if verbosity>=5: - print(' step 1: goto origin') - self.xo() # goto origin - self.yo() - #self.gotoAlignedPosition() - - #if step<=5: - #self.align() - - if step<=10: - if verbosity>=5: - print(' step 10: measuring') - self.measure(**md) - - - # Control methods - ######################################## - def setTemperature(self, temperature, output_channel='1', verbosity=3): - #if verbosity>=1: - #print('Temperature functions not implemented in {}'.format(self.__class__.__name__)) - if output_channel == '1': - if verbosity>=2: - print(' Changing temperature setpoint from {:.3f}°C to {:.3f}°C'.format(caget('XF:11BM-ES{Env:01-Out:1}T-SP')-273.15, temperature)) - caput('XF:11BM-ES{Env:01-Out:1}T-SP', temperature+273.15) - - if output_channel == '2': - if verbosity>=2: - print(' Changing temperature setpoint from {:.3f}°C to {:.3f}°C'.format(caget('XF:11BM-ES{Env:01-Out:2}T-SP')-273.15, temperature)) - caput('XF:11BM-ES{Env:01-Out:2}T-SP', temperature+273.15) - - if output_channel == '3': - if verbosity>=2: - print(' Changing temperature setpoint from {:.3f}°C to {:.3f}°C'.format(caget('XF:11BM-ES{Env:01-Out:3}T-SP')-273.15, temperature)) - caput('XF:11BM-ES{Env:01-Out:3}T-SP', temperature+273.15) - - if output_channel == '4': - if verbosity>=2: - print(' Changing temperature setpoint from {:.3f}°C to {:.3f}°C'.format(caget('XF:11BM-ES{Env:01-Out:4}T-SP')-273.15, temperature)) - caput('XF:11BM-ES{Env:01-Out:4}T-SP', temperature+273.15) - - - def temperature(self, temperature_probe='A', output_channel='1', verbosity=3): - #if verbosity>=1: - #print('Temperature functions not implemented in {}'.format(self.__class__.__name__)) - - if temperature_probe == 'A': - current_temperature = caget('XF:11BM-ES{Env:01-Chan:A}T:C-I') - if verbosity>=3: - print(' Temperature = {:.3f}°C (setpoint = {:.3f}°C)'.format( current_temperature, self.temperature_setpoint(output_channel=output_channel)-273.15 ) ) - - if temperature_probe == 'B': - current_temperature = caget('XF:11BM-ES{Env:01-Chan:B}T:C-I') - if verbosity>=3: - print(' Temperature = {:.3f}°C (setpoint = {:.3f}°C)'.format( current_temperature, self.temperature_setpoint(output_channel=output_channel)-273.15 ) ) - - if temperature_probe == 'C': - current_temperature = caget('XF:11BM-ES{Env:01-Chan:C}T:C-I') - if verbosity>=3: - print(' Temperature = {:.3f}°C (setpoint = {:.3f}°C)'.format( current_temperature, self.temperature_setpoint(output_channel=output_channel)-273.15 ) ) - - if temperature_probe == 'D': - current_temperature = caget('XF:11BM-ES{Env:01-Chan:D}T:C-I') - if verbosity>=3: - print(' Temperature = {:.3f}°C (setpoint = {:.3f}°C)'.format( current_temperature, self.temperature_setpoint(output_channel=output_channel)-273.15 ) ) - - return current_temperature - - - def temperature_setpoint(self, output_channel='1', verbosity=3): - #if verbosity>=1: - #print('Temperature functions not implemented in {}'.format(self.__class__.__name__)) - - if output_channel == '1': - setpoint_temperature = caget('XF:11BM-ES{Env:01-Out:1}T-SP') - - if output_channel == '2': - setpoint_temperature = caget('XF:11BM-ES{Env:01-Out:2}T-SP') - - if output_channel == '3': - setpoint_temperature = caget('XF:11BM-ES{Env:01-Out:3}T-SP') - - if output_channel == '4': - setpoint_temperature = caget('XF:11BM-ES{Env:01-Out:4}T-SP') - - return setpoint_temperature - - - -class SampleTSAXS_Generic(Sample_Generic): - - pass - - -class SampleGISAXS_Generic(Sample_Generic): - - def __init__(self, name, base=None, **md): - - super().__init__(name=name, base=base, **md) - self.naming_scheme = ['name', 'extra', 'th', 'exposure_time'] - self.incident_angles_default = [0.08, 0.10, 0.12, 0.15, 0.20] - - - def measureSpots(self, num_spots=2, translation_amount=0.1, axis='x', exposure_time=None, extra=None, measure_type='measureSpots', **md): - super().measureSpots(num_spots=num_spots, translation_amount=translation_amount, axis=axis, exposure_time=exposure_time, extra=extra, measure_type=measure_type, **md) - - - def measureIncidentAngle(self, angle, exposure_time=None, extra=None, **md): - - self.thabs(angle) - - self.measure(exposure_time=exposure_time, extra=extra, **md) - - - def measureIncidentAngles(self, angles=None, exposure_time=None, extra=None, **md): - - if angles is None: - angles = self.incident_angles_default - - for angle in angles: - self.measureIncidentAngle(angle, exposure_time=exposure_time, extra=extra, **md) - - - def _alignOld(self, step=0): - '''Align the sample with respect to the beam. GISAXS alignment involves - vertical translation to the beam center, and rocking theta to get the - sample plane parralel to the beam. - - The 'step' argument can optionally be given to jump to a particular - step in the sequence.''' - - # TODO: Deprecate and delete - - if step<=0: - # TODO: Check what mode we are in, change if necessary... - # get_beamline().modeAlignment() - beam.on() - - # TODO: Improve implementation - if step<=2: - #fit_scan(smy, 2.6, 35, fit='HM') - fit_scan(smy, 2.6, 35, fit='sigmoid_r') - - - if step<=4: - #fit_scan(smy, 0.6, 17, fit='HM') - fit_scan(smy, 0.6, 17, fit='sigmoid_r') - fit_scan(sth, 1.2, 21, fit='max') - - #if step<=6: - # fit_scan(smy, 0.3, 17, fit='sigmoid_r') - # fit_scan(sth, 1.2, 21, fit='COM') - - if step<=8: - fit_scan(smy, 0.2, 17, fit='sigmoid_r') - fit_scan(sth, 0.8, 21, fit='gauss') - - if step<=9: - #self._testing_refl_pos() - #movr(sth,.1) - #fit_scan(sth, 0.2, 41, fit='gauss') - #fit_scan(smy, 0.2, 21, fit='gauss') - #movr(sth,-.1) - - - beam.off() - - - - def align(self, step=0, reflection_angle=0.08, verbosity=3): - '''Align the sample with respect to the beam. GISAXS alignment involves - vertical translation to the beam center, and rocking theta to get the - sample plane parralel to the beam. Finally, the angle is re-optimized - in reflection mode. - - The 'step' argument can optionally be given to jump to a particular - step in the sequence.''' - - if verbosity>=4: - print(' Aligning {}'.format(self.name)) - - if step<=0: - # Prepare for alignment - - if RE.state!='idle': - RE.abort() - - if get_beamline().current_mode!='alignment': - if verbosity>=2: - print("WARNING: Beamline is not in alignment mode (mode is '{}')".format(get_beamline().current_mode)) - #get_beamline().modeAlignment() - - - get_beamline().setDirectBeamROI() - - beam.on() - - - if step<=2: - if verbosity>=4: - print(' align: searching') - - # Estimate full-beam intensity - value = None - if True: - q # You can eliminate this, in which case RE.md['beam_intensity_expected'] is used by default - self.yr(-2) - #detector = gs.DETS[0] - detector = get_beamline().detector[0] - value_name = get_beamline().TABLE_COLS[0] - RE(count([detector])) - value = detector.read()[value_name]['value'] - self.yr(+2) - - if 'beam_intensity_expected' in RE.md and value=4: - print(' align: fitting') - - fit_scan(smy, 1.2, 21, fit='HMi') - #time.sleep(2) - fit_scan(sth, 1.5, 21, fit='max') - #time.sleep(2) - - #if step<=5: - # #fit_scan(smy, 0.6, 17, fit='sigmoid_r') - # fit_edge(smy, 0.6, 17) - # fit_scan(sth, 1.2, 21, fit='max') - - - if step<=8: - #fit_scan(smy, 0.3, 21, fit='sigmoid_r') - - fit_edge(smy, 0.6, 21) - #time.sleep(2) - #fit_edge(smy, 0.4, 21) - fit_scan(sth, 0.8, 21, fit='COM') - #time.sleep(2) - self.setOrigin(['y', 'th']) - - - if step<=9 and reflection_angle is not None: - # Final alignment using reflected beam - if verbosity>=4: - print(' align: reflected beam') - get_beamline().setReflectedBeamROI(total_angle=reflection_angle*2.0) - #get_beamline().setReflectedBeamROI(total_angle=reflection_angle*2.0, size=[12,2]) - - self.thabs(reflection_angle) - - result = fit_scan(sth, 0.2, 41, fit='max') - #result = fit_scan(sth, 0.2, 81, fit='max') #it's useful for alignment of SmarAct stage - sth_target = result.values['x_max']-reflection_angle - - if result.values['y_max']>10: - th_target = self._axes['th'].motor_to_cur(sth_target) - self.thsetOrigin(th_target) - - #fit_scan(smy, 0.2, 21, fit='max') - self.setOrigin(['y']) - - if step<=10: - self.thabs(0.0) - beam.off() - - - def alignQuick(self, align_step=8, reflection_angle=0.08, verbosity=3): - - get_beamline().modeAlignment() - #self.yo() - self.tho() - beam.on() - self.align(step=align_step, reflection_angle=reflection_angle, verbosity=verbosity) - - - - - def _testing_level(self, step=0,pos_x_left=-5, pos_x_right=5): - - #TODO: Move this code. (This should be a property of the GIBar object.) - - #level GIBar by checking bar height at pos_left and pos_right - print('checking the level of GIBar') - #if step<=1: - # cms.modeAlignment() - #sam.xabs(pos_x_left) - #fit_scan(smy, .6, 17, fit='sigmooid_r') #it's better not to move smy after scan but only the center position - #pos_y_left=smy.user_readback.value - - # - #sam.xabs(pos_x_right) - #fit_scan(smy, .6, 17, fit='sigmooid_r') - #pos_y_right=smy.user_readback.value - - #offset_schi=(pos_y_right-pos_y_left)/(pos_x_right-pos_x_left) - #movr(sch, offset_schi) - - - #double-check the chi offset - #sam.xabs(pos_x_left) - #fit_scan(smy, .6, 17, fit='sigmooid_r') #it's better not to move smy after scan but only the center position - #pos_y_left=smy.user_readback.value - - #sam.xabs(pos_x_right) - #fit_scan(smy, .6, 17, fit='sigmooid_r') - #pos_y_right=smy.user_readback.value - - #offset_schi=(pos_y_right-pos_y_left)/(pos_x_right-pos_x_left) - - #if offset_schi<=0.1: - #print('schi offset is aligned successfully!') - #else: - #print('schi offset is WRONG. Please redo the level command') - pass - - - - def do(self, step=0, align_step=0, **md): - - if step<=1: - get_beamline().modeAlignment() - - if step<=2: - self.xo() # goto origin - - - if step<=4: - self.yo() - self.tho() - - if step<=5: - self.align(step=align_step) - #self.setOrigin(['y','th']) # This is done within align - - #if step<=7: - #self.xr(0.2) - - if step<=8: - get_beamline().modeMeasurement() - - if step<=10: - #detselect([pilatus300, psccd]) - #detselect(psccd) - #detselect(pilatus300) - detselect(pilatus2M) - for detector in get_beamline().detector: - detector.setExposureTime(self.md['exposure_time']) - self.measureIncidentAngles(self.incident_angles_default, **md) - self.thabs(0.0) - - - -class SampleCDSAXS_Generic(Sample_Generic): - - def __init__(self, name, base=None, **md): - - super().__init__(name=name, base=base, **md) - self.naming_scheme = ['name', 'extra', 'phi', 'exposure_time'] - self.rot_angles_default = np.arange(-45, +45+1, +1) - #self.rot_angles_default = np.linspace(-45, +45, num=90, endpoint=True) - - def _set_axes_definitions(self): - '''Internal function which defines the axes for this stage. This is kept - as a separate function so that it can be over-ridden easily.''' - super()._set_axes_definitions() - - self._axes_definitions.append( {'name': 'phi', - 'motor': srot, - 'enabled': True, - 'scaling': +1.0, - 'units': 'deg', - 'hint': None, - } ) - - def measureAngle(self, angle, exposure_time=None, extra=None, measure_type='measure', **md): - - self.phiabs(angle) - - self.measure(exposure_time=exposure_time, extra=extra, measure_type=measure_type, **md) - - - def measureAngles(self, angles=None, exposure_time=None, extra=None, measure_type='measureAngles', **md): - - if angles is None: - angles = self.rot_angles_default - - for angle in angles: - self.measureAngle(angle, exposure_time=exposure_time, extra=extra, measure_type=measure_type, **md) - - - - -class Stage(CoordinateSystem): - - pass - - -class SampleStage(Stage): - - def __init__(self, name='SampleStage', base=None, **kwargs): - - super().__init__(name=name, base=base, **kwargs) - - def _set_axes_definitions(self): - '''Internal function which defines the axes for this stage. This is kept - as a separate function so that it can be over-ridden easily.''' - - # The _axes_definitions array holds a list of dicts, each defining an axis - self._axes_definitions = [ {'name': 'x', - 'motor': smx, - 'enabled': True, - 'scaling': +1.0, - 'units': 'mm', - 'hint': 'positive moves stage left/outboard (beam moves right on sample)', - }, - {'name': 'y', - 'motor': smy, - 'enabled': True, - 'scaling': +1.0, - 'units': 'mm', - 'hint': 'positive moves stage up (beam moves down on sample)', - }, - {'name': 'th', - 'motor': sth, - 'enabled': True, - 'scaling': +1.0, - 'units': 'deg', - 'hint': 'positive tilts clockwise (positive incident angle)', - }, - ] - - - - -class Holder(Stage): - '''The Holder() classes are used to define bars/stages that hold one or more - samples. This class can thus help to keep track of coordinate conversions, - to store the positions of multiple samples, and to automate the measurement - of multiple samples.''' - - # Core methods - ######################################## - - def __init__(self, name='Holder', base=None, **kwargs): - - if base is None: - base = get_default_stage() - - super().__init__(name=name, base=base, **kwargs) - - self._samples = {} - - def _set_axes_definitions(self): - '''Internal function which defines the axes for this stage. This is kept - as a separate function so that it can be over-ridden easily.''' - - # The _axes_definitions array holds a list of dicts, each defining an axis - self._axes_definitions = [ {'name': 'x', - 'motor': None, - 'enabled': True, - 'scaling': +1.0, - 'units': 'mm', - 'hint': 'positive moves stage left/outboard (beam moves right on sample)', - }, - {'name': 'y', - 'motor': None, - 'enabled': True, - 'scaling': +1.0, - 'units': 'mm', - 'hint': 'positive moves stage up (beam moves down on sample)', - }, - {'name': 'th', - 'motor': None, - 'enabled': True, - 'scaling': +1.0, - 'units': 'deg', - 'hint': 'positive tilts clockwise (positive incident angle)', - }, - ] - - # Sample management - ######################################## - - def addSample(self, sample, sample_number=None): - '''Add a sample to this holder/bar.''' - - if sample_number is None: - if len(self._samples)==0: - sample_number = 1 - else: - ki = [ int(key) for key in self._samples.keys() ] - sample_number = np.max(ki) + 1 - - - if sample_number in self._samples.keys(): - print('Warning: Sample number {} is already defined on holder "{:s}". Use "replaceSample" if you are sure you want to eliminate the existing sample from the holder.'.format(sample_number, self.name) ) - - else: - self._samples[sample_number] = sample - - self._samples[sample_number] = sample - - sample.set_base_stage(self) - sample.md['holder_sample_number'] = sample_number - - - def removeSample(self, sample_number): - '''Remove a particular sample from this holder/bar.''' - - del self._samples[sample_number] - - - def removeSamplesAll(self): - - self._samples = {} - - - def replaceSample(self, sample, sample_number): - '''Replace a given sample on this holder/bar with a different sample.''' - - self.removeSample(sample_number) - self.addSample(sample, sample_number) - - - def getSample(self, sample_number, verbosity=3): - '''Return the requested sample object from this holder/bar. - - One can provide an integer, in which case the corresponding sample - (from the holder's inventory) is returned. If a string is provided, - the closest-matching sample (by name) is returned.''' - - if type(sample_number) is int: - if sample_number not in self._samples: - if verbosity>=1: - print('Error: Sample {} not defined.'.format(sample_number)) - return None - - sample_match = self._samples[sample_number] - - if verbosity>=3: - print('{}: {:s}'.format(sample_number, sample_match.name)) - - return sample_match - - - elif type(sample_number) is str: - - # First search for an exact name match - matches = 0 - sample_match = None - sample_i_match = None - for sample_i, sample in sorted(self._samples.items()): - if sample.name==sample_number: - matches += 1 - if sample_match is None: - sample_match = sample - sample_i_match = sample_i - - if matches==1: - if verbosity>=3: - print('{}: {:s}'.format(sample_i_match, sample_match.name)) - return sample_match - - elif matches>1: - if verbosity>=2: - print('{:d} exact matches for "{:s}", returning sample {}: {:s}'.format(matches, sample_number, sample_i_match, sample_match.name)) - return sample_match - - - # Try to find a 'start of name' match - for sample_i, sample in sorted(self._samples.items()): - if sample.name.startswith(sample_number): - matches += 1 - if sample_match is None: - sample_match = sample - sample_i_match = sample_i - - if matches==1: - if verbosity>=3: - print('Beginning-name match: {}: {:s}'.format(sample_i_match, sample_match.name)) - return sample_match - - elif matches>1: - if verbosity>=2: - print('{:d} beginning-name matches for "{:s}", returning sample {}: {:s}'.format(matches, sample_number, sample_i_match, sample_match.name)) - return sample_match - - # Try to find a substring match - for sample_i, sample in sorted(self._samples.items()): - if sample_number in sample.name: - matches += 1 - if sample_match is None: - sample_match = sample - sample_i_match = sample_i - - if matches==1: - if verbosity>=3: - print('Substring match: {}: {:s}'.format(sample_i_match, sample_match.name)) - return sample_match - - elif matches>1: - if verbosity>=2: - print('{:d} substring matches for "{:s}", returning sample {}: {:s}'.format(matches, sample_number, sample_i_match, sample_match.name)) - return sample_match - - if verbosity>=1: - print('No sample has a name matching "{:s}"'.format(sample_number)) - return None - - - else: - - print('Error: Sample designation "{}" not understood.'.format(sample_number)) - return None - - - def getSamples(self, range=None, verbosity=3): - '''Get the list of samples associated with this holder. - - If the optional range argument is provided (2-tuple), then only sample - numbers within that range (inclusive) are run. If range is instead a - string, then all samples with names that match are returned.''' - - samples = [] - - if range is None: - for sample_number in sorted(self._samples): - samples.append(self._samples[sample_number]) - - elif type(range) is list: - start, stop = range - for sample_number in sorted(self._samples): - if sample_number>=start and sample_number<=stop: - samples.append(self._samples[sample_number]) - - elif type(range) is str: - for sample_number, sample in sorted(self._samples.items()): - if range in sample.name: - samples.append(sample) - - elif type(range) is int: - samples.append(self._samples[range]) - - else: - if verbosity>=1: - print('Range argument "{}" not understood.'.format(range)) - - - return samples - - - def listSamples(self): - '''Print a list of the current samples associated with this holder/ - bar.''' - - for sample_number, sample in sorted(self._samples.items()): - print( '{}: {:s}'.format(sample_number, sample.name) ) - - - def gotoSample(self, sample_number): - - sample = self.getSample(sample_number, verbosity=0) - sample.gotoAlignedPosition() - - return sample - - - # Control methods - ######################################## - def setTemperature(self, temperature, output_channel='1', verbosity=3): - #if verbosity>=1: - #print('Temperature functions not implemented in {}'.format(self.__class__.__name__)) - if output_channel == '1': - if verbosity>=2: - print(' Changing temperature setpoint from {:.3f}°C to {:.3f}°C'.format(caget('XF:11BM-ES{Env:01-Out:1}T-SP')-273.15, temperature)) - caput('XF:11BM-ES{Env:01-Out:1}T-SP', temperature+273.15) - - if output_channel == '2': - if verbosity>=2: - print(' Changing temperature setpoint from {:.3f}°C to {:.3f}°C'.format(caget('XF:11BM-ES{Env:01-Out:2}T-SP')-273.15, temperature)) - caput('XF:11BM-ES{Env:01-Out:2}T-SP', temperature+273.15) - - if output_channel == '3': - if verbosity>=2: - print(' Changing temperature setpoint from {:.3f}°C to {:.3f}°C'.format(caget('XF:11BM-ES{Env:01-Out:3}T-SP')-273.15, temperature)) - caput('XF:11BM-ES{Env:01-Out:3}T-SP', temperature+273.15) - - if output_channel == '4': - if verbosity>=2: - print(' Changing temperature setpoint from {:.3f}°C to {:.3f}°C'.format(caget('XF:11BM-ES{Env:01-Out:4}T-SP')-273.15, temperature)) - caput('XF:11BM-ES{Env:01-Out:4}T-SP', temperature+273.15) - - - def temperature(self, temperature_probe='A', output_channel='1', verbosity=3): - #if verbosity>=1: - #print('Temperature functions not implemented in {}'.format(self.__class__.__name__)) - - if temperature_probe == 'A': - current_temperature = caget('XF:11BM-ES{Env:01-Chan:A}T:C-I') - if verbosity>=3: - print(' Temperature = {:.3f}°C (setpoint = {:.3f}°C)'.format( current_temperature, self.temperature_setpoint(output_channel=output_channel)-273.15 ) ) - - if temperature_probe == 'B': - current_temperature = caget('XF:11BM-ES{Env:01-Chan:B}T:C-I') - if verbosity>=3: - print(' Temperature = {:.3f}°C (setpoint = {:.3f}°C)'.format( current_temperature, self.temperature_setpoint(output_channel=output_channel)-273.15 ) ) - - if temperature_probe == 'C': - current_temperature = caget('XF:11BM-ES{Env:01-Chan:C}T:C-I') - if verbosity>=3: - print(' Temperature = {:.3f}°C (setpoint = {:.3f}°C)'.format( current_temperature, self.temperature_setpoint(output_channel=output_channel)-273.15 ) ) - - if temperature_probe == 'D': - current_temperature = caget('XF:11BM-ES{Env:01-Chan:D}T:C-I') - if verbosity>=3: - print(' Temperature = {:.3f}°C (setpoint = {:.3f}°C)'.format( current_temperature, self.temperature_setpoint(output_channel=output_channel)-273.15 ) ) - - return current_temperature - - def temperature_setpoint(self, output_channel='1', verbosity=3): - #if verbosity>=1: - #print('Temperature functions not implemented in {}'.format(self.__class__.__name__)) - - if output_channel == '1': - setpoint_temperature = caget('XF:11BM-ES{Env:01-Out:1}T-SP') - - if output_channel == '2': - setpoint_temperature = caget('XF:11BM-ES{Env:01-Out:2}T-SP') - - if output_channel == '3': - setpoint_temperature = caget('XF:11BM-ES{Env:01-Out:3}T-SP') - - if output_channel == '4': - setpoint_temperature = caget('XF:11BM-ES{Env:01-Out:4}T-SP') - - return setpoint_temperature - - - - # Action (measurement) methods - ######################################## - - def doSamples(self, range=None, verbosity=3, **md): - '''Activate the default action (typically measurement) for all the samples. - - If the optional range argument is provided (2-tuple), then only sample - numbers within that range (inclusive) are run. If range is instead a - string, then all samples with names that match are returned.''' - - for sample in self.getSamples(range=range): - if verbosity>=3: - print('Doing sample {}...'.format(sample.name)) - sample.do(verbosity=verbosity, **md) - - - def doTemperature(self, temperature, wait_time=None, temperature_probe='A', output_channel='1', temperature_tolerance=0.4, range=None, verbosity=3, poling_period=2.0, **md): - - # Set new temperature - self.setTemperature(temperature, output_channel=output_channel, verbosity=verbosity) - - # Wait until we reach the temperature - while abs(self.temperature(verbosity=0) - temperature)>temperature_tolerance: - if verbosity>=3: - print(' setpoint = {:.3f}°C, Temperature = {:.3f}°C \r'.format(self.temperature_setpoint()-273.15, self.temperature(verbosity=0)), end='') - time.sleep(poling_period) - - - # Allow for additional equilibration at this temperature - if wait_time is not None: - time.sleep(wait_time) - - self.doSamples(range=range, verbosity=verbosity, **md) - - - def doTemperatures(self, temperatures, wait_time=None, temperature_probe='A', output_channel='1', temperature_tolerance=0.4, range=None, verbosity=3, **md): - - for temperature in temperatures: - - self.doTemperature(temperature, wait_time=wait_time, temperature_probe=temperature_probe, output_channel=output_channel, temperature_tolerance=temperature_tolerance, range=range, verbosity=verbosity, **md) - - - - -class PositionalHolder(Holder): - '''This class is a sample holder that is one-dimensional. E.g. a bar with a - set of samples lined up, or a holder with a set number of slots for holding - samples. This class thus helps to associate each sample with its position - on the bar.''' - - # Core methods - ######################################## - - def __init__(self, name='PositionalHolder', base=None, **kwargs): - - super().__init__(name=name, base=base, **kwargs) - - self._positional_axis = 'x' - self.GaragePosition=[] - - # Sample management - ######################################## - - def slot(self, sample_number): - '''Moves to the selected slot in the holder.''' - - getattr(self, self._positional_axis+'abs')( self.get_slot_position(sample_number) ) - - - def get_slot_position(self, slot): - '''Return the motor position for the requested slot number.''' - # This method should be over-ridden in sub-classes, so as to properly - # implement the positioning appropriate for that holder. - - position = 0.0 + slot*1.0 - - return position - - - def addSampleSlot(self, sample, slot, detector_opt='SAXS'): - '''Adds a sample to the specified "slot" (defined/numbered sample - holding spot on this holder).''' - - self.addSample(sample, sample_number=slot) - sample.setOrigin( [self._positional_axis], [self.get_slot_position(slot)] ) - sample.detector=detector_opt - - def addSampleSlotPosition(self, sample, slot, position, detector_opt='SAXS'): - '''Adds a sample to the specified "slot" (defined/numbered sample - holding spot on this holder).''' - - self.addSample(sample, sample_number=slot) - sample.setOrigin( [self._positional_axis], [position] ) - sample.detector=detector_opt - - - def listSamplesPositions(self): - '''Print a list of the current samples associated with this holder/ - bar.''' - - for sample_number, sample in self._samples.items(): - #pos = getattr(sample, self._positional_axis+'pos')(verbosity=0) - pos = sample.origin(verbosity=0)[self._positional_axis] - print( '%s: %s (%s = %.3f)' % (str(sample_number), sample.name, self._positional_axis, pos) ) - - def listSamplesDetails(self): - '''Print a list of the current samples associated with this holder/ - bar.''' - - for sample_number, sample in self._samples.items(): - #pos = getattr(sample, self._positional_axis+'pos')(verbosity=0) - pos = sample.origin(verbosity=0)[self._positional_axis] - print( '%s: %s (%s = %.3f) %s' % (str(sample_number), sample.name, self._positional_axis, pos, sample.detector) ) - - def addGaragePosition(self, shelf_num, spot_num): - '''the position in garage''' - if shelf_num not in range(1, 5) or spot_num not in range(1, 4): - print('Out of the range in Garage (4 x 3)') - - self.GaragePosition=[shelf_num, spot_num] - - -class GIBar(PositionalHolder): - '''This class is a sample bar for grazing-incidence (GI) experiments.''' - - # Core methods - ######################################## - - def __init__(self, name='GIBar', base=None, **kwargs): - - super().__init__(name=name, base=base, **kwargs) - - self._positional_axis = 'x' - - # Set the x and y origin to be the center of slot 8 - self.xsetOrigin(-71.89405) - self.ysetOrigin(10.37925) - - self.mark('right edge', x=+108.2) - self.mark('left edge', x=0) - self.mark('center', x=54.1, y=0) - - - def addSampleSlotPosition(self, sample, slot, position, detector_opt='SAXS', account_substrate=True): - '''Adds a sample to the specified "slot" (defined/numbered sample - holding spot on this holder).''' - - super().addSampleSlotPosition(sample, slot, position) - - # Adjust y-origin to account for substrate thickness - if account_substrate and 'substrate_thickness' in sample.md: - sample.ysetOrigin( -1.0*sample.md['substrate_thickness'] ) - - sample.detector=detector_opt - - - -class CapillaryHolder(PositionalHolder): - '''This class is a sample holder that has 15 slots for capillaries.''' - - # Core methods - ######################################## - - def __init__(self, name='CapillaryHolder', base=None, **kwargs): - - super().__init__(name=name, base=base, **kwargs) - - self._positional_axis = 'x' - - self.x_spacing = 6.342 # 3.5 inches / 14 spaces - - # slot 1; smx = +26.60 - # slot 8; smx = -17.80 - # slot 15; smx = -61.94 - - # Set the x and y origin to be the center of slot 8 - self.xsetOrigin(-16.7) - self.ysetOrigin(-2.36985) - - self.mark('right edge', x=+54.4) - self.mark('left edge', x=-54.4) - self.mark('bottom edge', y=-12.71) - self.mark('center', x=0, y=0) - - - def get_slot_position(self, slot): - '''Return the motor position for the requested slot number.''' - - return +1*self.x_spacing*(slot-8) - - -class CapillaryHolderHeated(CapillaryHolder): - - def update_sample_names(self): - - for sample in self.getSamples(): - if 'temperature' not in sample.naming_scheme: - sample.naming_scheme.insert(-1, 'temperature') - - def doHeatCool(self, heat_temps, cool_temps, exposure_time=None, stabilization_time=120, temp_tolerance=0.5, step=1): - - if step<=1: - - for temperature in heat_temps: - try: - self.setTemperature(temperature) - - while self.temperature(verbosity=0) < temperature-temp_tolerance: - time.sleep(5) - time.sleep(stabilization_time) - - for sample in self.getSamples(): - sample.gotoOrigin() - sample.xr(-0.05) - sample.measure(exposure_time) - - except HTTPError: - pass - - - if step<=5: - - for temperature in heat_temps: - try: - self.setTemperature(temperature) - - self.setTemperature(temperature) - - while self.temperature(verbosity=0) > temperature+temp_tolerance: - time.sleep(5) - time.sleep(stabilization_time) - - for sample in self.getSamples(): - sample.gotoOrigin() - sample.xr(0.1) - sample.measure(exposure_time) - - except HTTPError: - pass - - - - -stg = SampleStage() -def get_default_stage(): - return stg - - - - -if False: - # For testing: - # %run -i /opt/ipython_profiles/profile_collection/startup/94-sample.py - sam = SampleGISAXS_Generic('testing_of_code') - sam.mark('here') - #sam.mark('XY_field', 'x', 'y') - #sam.mark('specified', x=1, th=0.1) - #sam.naming(['name', 'extra', 'clock', 'th', 'exposure_time', 'id']) - #sam.thsetOrigin(0.5) - #sam.marks() - - - hol = CapillaryHolder(base=stg) - hol.addSampleSlot( SampleGISAXS_Generic('test_sample_01'), 1.0 ) - hol.addSampleSlot( SampleGISAXS_Generic('test_sample_02'), 3.0 ) - hol.addSampleSlot( SampleGISAXS_Generic('test_sample_03'), 5.0 ) - - sam = hol.getSample(1) - - - diff --git a/startup/95-sample-custom.py b/startup/95-sample-custom.py index 6d364e9..43dd1b8 100644 --- a/startup/95-sample-custom.py +++ b/startup/95-sample-custom.py @@ -1,3 +1,5 @@ +print(f"Loading {__file__!r} ...") + ################################################################################ # Code for customer-made holders and sample stages, # Samples include : @@ -63,8 +65,7 @@ def intMeasure(self, output_file, exposure_time): if os.path.isfile(INT_FILENAME): output_data = pds.read_csv(INT_FILENAME, index_col=0) - # output_data = output_data.append(temp_data, ignore_index=True) - output_data = pds.concat([output_data, temp_data], ignore_index=True) + output_data = output_data.append(temp_data, ignore_index=True) output_data.to_csv(INT_FILENAME) else: temp_data.to_csv(INT_FILENAME) @@ -309,8 +310,7 @@ def intMeasure(self, output_file, exposure_time): if os.path.isfile(INT_FILENAME): output_data = pds.read_csv(INT_FILENAME, index_col=0) - # output_data = output_data.append(temp_data, ignore_index=True) - output_data = pds.concat([output_data, temp_data], ignore_index=True) + output_data = output_data.append(temp_data, ignore_index=True) output_data.to_csv(INT_FILENAME) else: temp_data.to_csv(INT_FILENAME) @@ -439,12 +439,7 @@ def align(self, step=0, reflection_angle=0.12, verbosity=3): # Find the step-edge self.ysearch( - step_size=0.5, - min_step=0.005, - intensity=value, - target=0.5, - verbosity=verbosity, - polarity=-1, + step_size=0.5, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1 ) # Find the peak @@ -956,7 +951,7 @@ def XR_scan( # default_WAXSy = WAXSy.position # move in absorber and move out the beamstop - slot_pos = 5 + slot_pos = 4 beam.setAbsorber(slot_pos) if beam.absorber()[0] >= 4: bsx.move(bsx.position + 6) @@ -975,7 +970,7 @@ def XR_scan( # Energy = 17kev if abs(beam.energy(verbosity=1) - 10) < 0.1: - direct_beam_slot = 5 + direct_beam_slot = 3 beam.setAbsorber(direct_beam_slot) # TODO:move detector to the 1st position and setROI @@ -1109,8 +1104,7 @@ def XR_scan( self.measure(exposure_time, extra=extra) temp_data = self.XR_data_output(slot_pos, exposure_time) - # output_data = output_data.append(temp_data, ignore_index=True) - output_data = pds.concat([output_data, temp_data], ignore_index=True) + output_data = output_data.append(temp_data, ignore_index=True) # save to file output_data.to_csv(XR_FILENAME) @@ -1165,7 +1159,7 @@ def XR_data_output(self, slot_pos, exposure_time): beam.absorber_transmission_list = beam.absorber_transmission_list_17kev elif abs(beam.energy(verbosity=1) - 10) < 0.1: - beam.absorber_transmission_list = beam.absorber_transmission_list + beam.absorber_transmission_list = beam.absorber_transmission_list_10kev else: print("The absorber has not been calibrated under current Energy!!!") @@ -1253,12 +1247,7 @@ def XR_align(self, step=0, reflection_angle=0.15, verbosity=3): # Find the step-edge self.ysearch( - step_size=0.5, - min_step=0.005, - intensity=value, - target=0.5, - verbosity=verbosity, - polarity=-1, + step_size=0.5, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1 ) # Find the peak @@ -1502,8 +1491,7 @@ def th2thscan( self.measure(exposure_time, extra=extra) temp_data = self.XR_data_output(slot_pos, exposure_time) - # output_data = output_data.append(temp_data, ignore_index=True) - output_data = pds.concat([output_data, temp_data], ignore_index=True) + output_data = output_data.append(temp_data, ignore_index=True) # save to file output_data.to_csv(th2th_FILENAME) @@ -1615,11 +1603,7 @@ def _backup_addSampleSlotPosition( holding spot on this holder).""" super().addSampleSlotPosition( - sample=sample, - slot=slot, - position=position, - detector_opt=detector_opt, - incident_angles=incident_angles, + sample=sample, slot=slot, position=position, detector_opt=detector_opt, incident_angles=incident_angles ) # Adjust y-origin to account for substrate thickness @@ -1649,11 +1633,7 @@ def addSampleSlotPosition( holding spot on this holder).""" super().addSampleSlotPosition( - sample=sample, - slot=slot, - position=position, - detector_opt=detector_opt, - incident_angles=incident_angles, + sample=sample, slot=slot, position=position, detector_opt=detector_opt, incident_angles=incident_angles ) # Adjust y-origin to account for substrate thickness if thickness != 0: @@ -2296,13 +2276,7 @@ def update_sample_names(self): sample.naming_scheme.insert(-1, "temperature") def doHeatCool( - self, - heat_temps, - cool_temps, - exposure_time=None, - stabilization_time=120, - temp_tolerance=0.5, - step=1, + self, heat_temps, cool_temps, exposure_time=None, stabilization_time=120, temp_tolerance=0.5, step=1 ): if step <= 1: for temperature in heat_temps: @@ -2991,13 +2965,7 @@ def get_slot_position(self, slot): return position_x * self.x_spacing def tscan( - self, - temperature_start, - temperature_final, - num_intervals, - wait_time, - temp_update_time=5, - exposure_time=0, + self, temperature_start, temperature_final, num_intervals, wait_time, temp_update_time=5, exposure_time=0 ): if temperature_start == None or temperature_start < 0.0 or temperature_start >= 250: print("temperature_start must be set between 0 and 250 degC.\n") @@ -3040,11 +3008,7 @@ def tscan( print("{:.3f} {:.3f}".format(current_time, current_temperature)) # f.write('{:d} {:.3f} {:.3f}\n'.format(RE.md['scan_id'], current_time, current_temperature)) self.tscan_data = self.tscan_data.append( - { - "scan_id": RE.md["scan_id"], - "degC": current_temperature, - "seconds": current_time, - }, + {"scan_id": RE.md["scan_id"], "degC": current_temperature, "seconds": current_time}, ignore_index=True, ) diff --git a/startup/96-automation.py b/startup/96-automation.py index f094443..94cf56b 100644 --- a/startup/96-automation.py +++ b/startup/96-automation.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- # vi: ts=4 sw=4 +print(f"Loading {__file__!r} ...") ################################################################################ # Classes for controlling the robotics and automation on the beamline. @@ -79,10 +80,7 @@ def __init__(self, name="SampleExchangeRobot", base=None, use_gs=True, **kwargs) # default position for stage without SmarAct motor # self._position_stg_exchange = [+50.0, -2.37] # smx, smy - self._position_stg_exchange = [ - +51.5, - -1.87, - ] # smx, smy # Manual tweak KY (2017-11-28) + self._position_stg_exchange = [+51.5, -1.87] # smx, smy # Manual tweak KY (2017-11-28) self._position_stg_safe = [-30.0, -2.37] # smx, smy self._position_stg_measure = [] # smx, smy @@ -174,12 +172,7 @@ def home_y(self, verbosity=3, delays=0.5, retries=5, max_wait=2.0): if time.time() - start_time > max_wait: # Retry - self.home_y( - verbosity=verbosity, - delays=delays, - retries=retries - 1, - max_wait=max_wait, - ) + self.home_y(verbosity=verbosity, delays=delays, retries=retries - 1, max_wait=max_wait) # Wait for motion to be complete time.sleep(delays) @@ -281,7 +274,7 @@ def checkMove(self, verbosity=3): return self.moving == False def checkSafe(self, check_stage=True): - if self._region is not "safe": + if self._region != "safe": print( "ERROR: Robot arm must start in the 'safe' region of the chamber (current region is '{}'). Move the robot to the safe region (and/or set _region to 'safe').".format( self._region @@ -1325,25 +1318,6 @@ def listSamples(self): for sample_number, sample in sorted(holder._samples.items()): print("{}: {:s}".format(sample_number, sample.name)) - def checkSamples(self, verbosity=3): - if verbosity > 0: - self.listSamples() - # check positions to make sure the samples are in the range of smx - if verbosity > 3: - error_signal = False - for holder_number, holder in sorted(self._holders.items()): - for sample_number, sample in sorted(holder._samples.items()): - sample_xpos = holder.position["x"] + sample.position - if sample_xpos < smx.limits[0] or sample_xpos > smx.limits[-1]: - print( - "ERROR: out of limit of smx motor: holder--{}: sample--{}".format( - holder_number, sample_number - ) - ) - error_signal = True - if error_signal == True: - input(" Please ctrl+c and correct the errors.") - def returnHolder(self, holder="current", gotoSafe=True, force=False): """return the holder from stage back to garage. holder = None: retrun to default position @@ -1392,8 +1366,7 @@ def pickupHolder(self, holder, force=False, gotoSafe=True, slack=False): self._current = holder self.status = "onStage" post_to_slack( - text="holder <<<{}>>> is onStage for measurements".format(self._current.name), - slack=slack, + text="holder <<<{}>>> is onStage for measurements".format(self._current.name), slack=slack ) return self._current elif self.status == "onStage": @@ -1403,8 +1376,7 @@ def pickupHolder(self, holder, force=False, gotoSafe=True, slack=False): self._current = holder self.status = "onStage" post_to_slack( - text="holder <<<{}>>> is onStage for measurements".format(self._current.name), - slack=slack, + text="holder <<<{}>>> is onStage for measurements".format(self._current.name), slack=slack ) return self._current if force == True: @@ -1414,8 +1386,7 @@ def pickupHolder(self, holder, force=False, gotoSafe=True, slack=False): self._current = holder self.status = "onStage" post_to_slack( - text="holder <<<{}>>> is onStage for measurements".format(self._current.name), - slack=slack, + text="holder <<<{}>>> is onStage for measurements".format(self._current.name), slack=slack ) return self._current else: @@ -1588,12 +1559,7 @@ def runHolders(self, startHolder=None, endHolder=None, gotoSafeForce=False, slac # This setting is for individual holder. Each sample could set its own setting when adding into holder def exposure_setting( - self, - exposure_time=None, - incident_angles=None, - detectors=None, - detector_positions=None, - tiling=None, + self, exposure_time=None, incident_angles=None, detectors=None, detector_positions=None, tiling=None ): """define the setting for exposures, including incident angles, exposure time, detector selection, detector positions. incident_angles: [0.05, 0.08, 0,1] @@ -1669,9 +1635,7 @@ def post_to_slack(text, slack=True): # data=json_data.encode('ascii'), # headers={'Content-Type': 'application/json'}) r = requests.post( - channel, - json=post, - headers={"Content-Type": "application/json", "Accept": "text/plain"}, + channel, json=post, headers={"Content-Type": "application/json", "Accept": "text/plain"} ) except Exception as em: diff --git a/startup/97-user.py b/startup/97-user.py index bac2814..feeffe2 100644 --- a/startup/97-user.py +++ b/startup/97-user.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- # vi: ts=4 sw=4 +print(f"Loading {__file__!r} ...") ################################################################################ # Short-term settings (specific to a particular user/experiment) can diff --git a/startup/98-databroker-browser-config.py b/startup/98-databroker-browser-config.py index e93dad7..2ac508b 100644 --- a/startup/98-databroker-browser-config.py +++ b/startup/98-databroker-browser-config.py @@ -1,3 +1,5 @@ +print(f"Loading {__file__!r} ...") + ## We assume this is being run in a namespace (e.g. an IPython profile startup ## script) where an instance of databroker.Broker named `db` is already defined. diff --git a/startup/99-caproto-test.py b/startup/99-caproto-test.py index be47f20..0e11d5a 100644 --- a/startup/99-caproto-test.py +++ b/startup/99-caproto-test.py @@ -1,3 +1,5 @@ +print(f"Loading {__file__!r} ...") + import logging import caproto diff --git a/startup/998-fitting.py b/startup/998-fitting.py new file mode 100644 index 0000000..e699127 --- /dev/null +++ b/startup/998-fitting.py @@ -0,0 +1,111 @@ +import numpy as np +from scipy.special import erf +from lmfit import Model + + +def do_fitting(x, y, *, model_type=None, shift=0.5): + """ + Do fitting for a peak or an edge. The peak is expected to symmetical. The type + (peak or edge) is determined automatically based on data or could be explicitly + set by specifying ``model_type``. + + Parameters + ---------- + x: iterable + An array or a list of positions + y: iterable + An array or a list of measurements + model_type: str or None + None - determine model type based on the number of 'roots', + 'step' - step function, 'peak' - peak. + shift: float + Shift applied to the normalized values before finding roots, typically 0.5. + + Returns + ------- + CEN: float + Position of the center of the peak or the edge + FWHM: float + FWHM of the peak (or similar parameter for the edge). If FWHM is 0 for a peak, + it means that the scanned range does not contain the full peak. In this case + the estimate of the center position is selected as 'x' with the largest 'y', + which is not accurate. In this case, the wider range should be scanned. + (XMIN, XMAX): type(float) + The range for positions, which define FWHM of the peak. The range is (None, None) + for the edge (this could be changed if needed). + """ + + if model_type not in (None, "step", "peak"): + raise ValueError(f"Unrecognized model type: {model_type!r}") + + x, y = np.array(x), np.array(y) + + if x.ndim != 1: + raise ValueError(f"Array 'x' must have one dimension: x.ndim={x.ndim}") + if y.ndim != 1: + raise ValueError(f"Array 'y' must have one dimension: y.ndim={y.ndim}") + if x.shape != y.shape: + raise ValueError( + f"Arrays 'x' and 'y' have unequal number of elements (x.shape={x.shape}, y.shape={y.shape})" + ) + + # Normalize values first: + ym = (y - np.min(y)) / (np.max(y) - np.min(y)) - shift # roots are at Y=0 + + CEN, FWHM, XMIN, XMAX = None, None, None, None + + def is_positive(num): + return True if num > 0 else False + + positive = is_positive(ym[0]) + list_of_roots = [] + for i in range(len(y)): + current_positive = is_positive(ym[i]) + if current_positive != positive: + rt = x[i - 1] + (x[i] - x[i - 1]) / (abs(ym[i]) + abs(ym[i - 1])) * abs(ym[i - 1]) + list_of_roots.append(rt) + positive = not positive + + n_roots = len(list_of_roots) + + if (n_roots >= 2) or (model_type == "peak"): # Peak + print(f"Fitting a peak ...") + + nmax = y.argmax() + xmax = x[nmax] + + root1, root2 = None, None + for r in list_of_roots: + if r <= xmax: + if (root1 is None) or (xmax - r < xmax - root1): + root1 = r + if r > xmax: + if (root2 is None) or (r - xmax < root2 - xmax): + root2 = r + + XMIN = root1 if root1 is not None else x[0] + XMAX = root2 if root2 is not None else x[-1] + + # Can not find the precise center if the scanned range does not contain the full peak. + if root1 is None or root2 is None: + root1, root2 = xmax, xmax + + FWHM = abs(root2 - root1) + CEN = root1 + 0.5 * (root2 - root1) + + if (n_roots == 1) or (model_type == "step"): # Step function + print(f"Fitting a step function ...") + ym = ym + shift + + def err_func(x, x0, k=2, A=1, base=0): #### erf fit from Yugang + return base - A * erf(k * (x - x0)) + + mod = Model(err_func) + x0 = np.mean(x) + k = 0.1 * (np.max(x) - np.min(x)) + pars = mod.make_params(x0=x0, k=k, A=1.0, base=0.0) + result = mod.fit(ym, pars, x=x) + CEN = result.best_values["x0"] + FWHM = result.best_values["k"] + + return CEN, FWHM, (XMIN, XMAX) diff --git a/startup/9999-plans.py b/startup/9999-plans.py new file mode 100644 index 0000000..aefa324 --- /dev/null +++ b/startup/9999-plans.py @@ -0,0 +1,378 @@ +print(f"Loading {__file__!r} ...") + +import time +import bluesky.preprocessors as bpp +from bluesky.utils import short_uid +from functools import partial + +try: + DETS = get_beamline().detector + [core_laser, laserx, lasery, smy, smx, sth, schi] +except Exception: + DETS = get_beamline().detector + [smy, smx, sth, schi] + +sample_pta = Sample("test") + + +@bpp.finalize_decorator(final_plan=shutter_off) +def expose(detectors, exposure_time=None, extra=None, verbosity=3, md=None): + md = dict(md or {}) + md.setdefault("measure_type", "expose") + + # Set exposure time + if exposure_time is not None: + exposure_time = abs(exposure_time) + + for detector in detectors: + if ( + hasattr(detector, "cam") + and hasattr(detector, "setExposureTime") + and exposure_time != detector.cam.acquire_time.get() + ): + yield from detector.setExposureTime(exposure_time, verbosity=verbosity) + + yield from shutter_on() + + md["plan_header_override"] = md["measure_type"] + start_time = time.time() + + # md_current = yield from self.get_md() + md["beam_int_bim3"] = yield from beam.bim3.flux(verbosity=0) + md["beam_int_bim4"] = yield from beam.bim4.flux(verbosity=0) + md["beam_int_bim5"] = yield from beam.bim5.flux(verbosity=0) + # md['trigger_time'] = self.clock() + # md.update(md_current) + + uids = yield from count(detectors, md=md) + + +def measure_single( + sample, + detectors=None, + exposure_time=None, + measure_type="measure", + verbosity=3, + handlefile=True, + md=None, +): + """Measure data by triggering the area detectors. + + Parameters + ---------- + exposure_time : float + How long to collect data + extra : string, optional + Extra information about this particular measurement (which is typically + included in the savename/filename). + """ + detectors = detectors if detectors is not None else DETS + md = dict(md or {}) + if exposure_time is not None: + sample.set_attribute("exposure_time", exposure_time) + # else: + # exposure_time = sample.get_attribute('exposure_time') + extra = md.get("extra", None) + savename = sample.get_savename(savename_extra=extra) + + if verbosity >= 2 and (get_beamline().current_mode != "measurement"): + print("WARNING: Beamline is not in measurement mode (mode is '{}')".format(get_beamline().current_mode)) + + if verbosity >= 1 and len(get_beamline().detector) < 1: + raise ValueError("ERROR: No detectors defined in detectors") + + md_current = yield from sample.get_md() + new_md = yield from sample.get_measurement_md() + md_current.update(new_md) + md_current["sample_savename"] = savename + md_current["measure_type"] = measure_type + # md_current['filename'] = '{:s}_{:04d}.tiff'.format(savename, md_current['detector_sequence_ID']) + # md_current['filename'] = '{:s}_{:04d}.tiff'.format(savename, RE.md['scan_id']) + md_current["filename"] = "{:s}_{:06d}".format(savename, RE.md.get("scan_id", -1)) + md_current.update(md) + + yield from expose(detectors, exposure_time, extra=extra, verbosity=verbosity, md=md_current) + # sample.expose(exposure_time, extra=extra, verbosity=verbosity, **md) + + # This is the symlinking code. + # We plan to remove this once kafka based linking is finished. + if handlefile: + for detector in detectors: + sample.handle_file(detector, verbosity=verbosity, **md_current) + + sample.md["measurement_ID"] += 1 + + +def tiling(detectors, inner_plan, tiling_type=None, md=None): + """ + A helper function that applies tiling to a plan. + Tiling is used to fill gaps between the detector chips. + + There are 3 different tiling modes: None, xgaps, and xygaps. + + xgaps mode sets the detector positions to the upper position, calls the plan, + and then sets the detector position to the lower position and calls the plan again. + + xygaps mode executes the plan for four different detector postions. + + The motors that are used to tiling will be added on to the list of detectors + when passed to the inner plan. + + Parameters + ---------- + detectors: list + The list of detectors used in the plan. + Detectors in this list that we know how to tiled, will get tiled. + inner_plan: callable + expected signature: + + def plan(detectors, md): + ''' + Parameters + ---------- + detectors: list + The list of detectors to use in the plan. + md: dict + Plan metadata. + ''' + ... + tiling_type: str, None + has one of the following values: None, 'xgaps', 'xygaps' + md: dict + Plan metadata. + + Returns + ------- + list + accumulated results of inner_plan + + """ + md = dict(md or {}) + md.setdefault("tile_id", short_uid("tile_id")) + GAP_SIZE = 5.16 + + # note: the incident angle plan does not set the maxs_y position for lower_right, and upper_right. + offsets = { + "lower": {"saxs_x": 0, "saxs_y": 0, "waxs_x": 0, "waxs_y": 0, "maxs_y": 0}, + "upper": { + "saxs_x": 0, + "saxs_y": GAP_SIZE, + "waxs_x": 0, + "waxs_y": GAP_SIZE, + "maxs_y": GAP_SIZE, + }, + "lower_left": {"saxs_x": 0, "saxs_y": 0, "waxs_x": 0, "waxs_y": 0, "maxs_y": 0}, + "upper_left": { + "saxs_x": 0, + "saxs_y": GAP_SIZE, + "waxs_x": 0, + "waxs_y": GAP_SIZE, + "maxs_y": GAP_SIZE, + }, + "lower_right": { + "saxs_x": GAP_SIZE, + "saxs_y": 0, + "waxs_x": -GAP_SIZE, + "waxs_y": 0, + "maxs_y": 0, + }, + "upper_right": { + "saxs_x": GAP_SIZE, + "saxs_y": GAP_SIZE, + "waxs_x": -GAP_SIZE, + "waxs_y": GAP_SIZE, + "maxs_y": 0, + }, + "default": {"saxs_x": 0, "saxs_y": 0, "waxs_x": 0, "waxs_y": 0}, + } + + tile_types = { + "xygaps": ["lower_left", "upper_left", "lower_right", "upper_right"], + "ygaps": ["upper", "lower"], + None: ["default"], + } + + extra = md.get("extra", None) + extras = { + "lower": "pos1" if extra is None else f"{extra}_pos1", + "upper": "pos2" if extra is None else f"{extra}_pos2", + "lower_left": "pos1" if extra is None else f"{extra}_pos1", + "upper_left": "pos2" if extra is None else f"{extra}_pos2", + "lower_right": "pos3" if extra is None else f"{extra}_pos3", + "upper_right": "pos4" if extra is None else f"{extra}_pos4", + "default": extra, + } + + motors = [] + if pilatus2M in detectors: + motors.extend([SAXSx, SAXSy]) + if pilatus800 in detectors: + motors.extend([WAXSx, WAXSy]) + if pilatus8002 in detectors: + motors.extend([MAXSy]) + + @bpp.reset_positions_decorator(motors) + def tiling_wrapper(): + ret = [] + if pilatus2M in detectors: + SAXSy_original = yield from bps.rd(SAXSy) + SAXSx_original = yield from bps.rd(SAXSx) + if pilatus800 in detectors: + WAXSy_original = yield from bps.rd(WAXSy) + WAXSx_original = yield from bps.rd(WAXSx) + if pilatus8002 in detectors: + MAXSy_original = yield from bps.rd(MAXSy) + + for tile in tile_types[tiling_type]: + if pilatus2M in detectors: + yield from bps.mv(SAXSx, SAXSx_original + offsets[tile]["saxs_x"]) + yield from bps.mv(SAXSy, SAXSy_original + offsets[tile]["saxs_y"]) + if pilatus800 in detectors: + yield from bps.mv(WAXSx, WAXSx_original + offsets[tile]["waxs_x"]) + yield from bps.mv(WAXSy, WAXSy_original + offsets[tile]["waxs_y"]) + if pilatus8002 in detectors: + yield from bps.mv(MAXSy, MAXSy_original + offsets[tile]["maxs_y"]) + + val = yield from inner_plan(detectors + motors, md={**md, "extra": extra, "detector_position": tile}) + ret.append(val) + return ret + + return (yield from tiling_wrapper()) + + +def measure( + sample, + detectors=None, + exposure_time=None, + extra=None, + measure_type="measure", + verbosity=3, + tiling_type=None, + md=None, +): + """Measure data by triggering the area detectors. + + Parameters + ---------- + sample: Sample + The sample object to measure. + detectors: interable + The list of detectors. + exposure_time : float + How long to collect data + extra : string, optional + Extra information about this particular measurement (which is typically + included in the savename/filename). + tiling : string + Controls the detector tiling mode. + None : regular measurement (single detector position) + 'ygaps' : try to cover the vertical gaps in the Pilatus detector + """ + detectors = detectors if detectors is not None else DETS + md = dict(md or {}) + + # The helper function `tiling` applies tiling to a plan. See the doc string. + # It takes the list of detectors, which should includes any device you want to measure at each iteration. + # So this should include motors or sensors that you would like to track to state of. + # It also takes a plan that has parameters: detectors, and md. + # Partial is used here to pre-set all of the parameters of measure single, except for detectors, and md. + yield from tiling( + detectors, + partial( + measure_single, + sample, + exposure_time=exposure_time, + measure_type=measure_type, + verbosity=verbosity, + ), + tiling_type=tiling_type, + md={**md, "extra": extra}, + ) + + +def sam_measure( + sample=None, + detectors=None, + exposure_time=None, + extra=None, + measure_type="measure", + verbosity=3, + tiling=None, + md=None, +): + sample = sample or sample_pta + detectors = detectors if detectors is not None else DETS + md = dict(md or {}) + if tiling is not None: + raise ValueError("Parameter 'tiling' must be None. Other values are not supported yet.") + + yield from measure( + sample, + detectors=detectors, + exposure_time=exposure_time, + extra=extra, + measure_type=measure_type, + verbosity=verbosity, + tiling=tiling, + md=md, + ) + + +def measure_incidents( + sample, + detectors=DETS, + angles=None, + exposure_time=None, + extra=None, + measure_type="measure", + verbosity=3, + tiling_type=None, + md=None, +): + """Measure data at various incident angles. + + Parameters + ---------- + sample: Sample + The sample object to measure. + detectors: interable + The list of detectors. + angles: list, optional + The list of angles to measure at. + defaults to sample.incident_angle_defaults + exposure_time : float + How long to collect data + extra : string, optional + Extra information about this particular measurement (which is typically + included in the savename/filename). + tiling : string + Controls the detector tiling mode. + None : regular measurement (single detector position) + 'ygaps' : try to cover the vertical gaps in the Pilatus detector + """ + + md = dict(md or {}) + + def measure_angles(detectors, md=None): + """ + Take a measurement for each angle in angles. + This function has the signature that is needed by `tiling` + """ + + nonlocal angles, sample, exposure_time, measure_type, verbosity + incident_angles = angles or sample.incident_angles_default + for angle in incident_angles: + yield from bps.mv(sample.thabs, angle) + yield from measure_single( + sample, + detectors=detectors, + exposure_time=exposure_time, + measure_type=measure_type, + verbosity=verbosity, + md=md, + ) + + yield from tiling( + detectors, + measure_angles, + tiling_type=tiling_type, + md=dict(**md, extra=extra), + ) diff --git a/startup/999999-user-PTA-KChen-Wiegart.py b/startup/999999-user-PTA-KChen-Wiegart.py new file mode 100644 index 0000000..ef5c2a3 --- /dev/null +++ b/startup/999999-user-PTA-KChen-Wiegart.py @@ -0,0 +1,4696 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# vi: ts=4 sw=4 + + +####### +# v3 --> v4: coord based on KY_coord_form.py + +# applied on sample : 16(7th) , 7(8th), 6(9th), 11(10th), 12(11th), 1(12th, LonC), 5(13th), 3(14th, LonC) + +####### + + +################################################################################ +# Short-term settings (specific to a particular user/experiment) can +# be placed in this file. You may instead wish to make a copy of this file in +# the user's data directory, and use that as a working copy. +################################################################################ + +from ophyd import Device, Component as Cpt, EpicsSignal, EpicsSignalRO +from bluesky.suspenders import SuspendFloor +import bluesky.plan_stubs as bps +import bluesky.preprocessors as bpp + +import sympy as sym + +print(f"Loading {__file__!r} ...") + +smz = EpicsMotor("XF:11BMB-ES{Chm:Smpl2-Ax:Z}Mtr", name="smz") + +MAXSbsx = smz +MAXSbsy = smy2 +# def saxs_on(): +# detselect(pilatus2M) +# WAXSx.move(-225) +# WAXSy.move(28) + + +def bsin(): + MAXSbsx.move(-7) + MAXSbsy.move(11) + + +def bsout(): + MAXSbsx.move(-7) + MAXSbsy.move(0) + + +def smaxs_on(): + MAXSx.move(-85) + MAXSy.move(-15) + + +def saxs_on(): + MAXSx.move(-85) + MAXSy.move(-15) + + +if True: + # Define suspenders to hold data collection if x-ray + # beam is not available. + + ring_current = EpicsSignal("SR:OPS-BI{DCCT:1}I:Real-I") + sus = SuspendFloor(ring_current, 100, resume_thresh=400, sleep=600) + RE.install_suspender(sus) + +# absorber_pos = EpicsSignal( 'XF:11BMB-ES{SM:1-Ax:ArmR}Mtr.RBV') +# sus_abs_low = SuspendFloor(absorber_pos, -56, resume_thresh=-55) +# sus_abs_hi = SuspendCeil(absorber_pos, -54, resume_thresh=-55) +# RE.install_suspender(sus_abs_low) +# RE.install_suspender(sus_abs_hi) + +# RE.clear_suspenders() + + +if False: + # The following shortcuts can be used for unit conversions. For instance, + # for a motor operating in 'mm' units, one could instead do: + # sam.xr( 10*um ) + # To move it by 10 micrometers. HOWEVER, one must be careful if using + # these conversion parameters, since they make implicit assumptions. + # For instance, they assume linear axes are all using 'mm' units. Conversely, + # you will not receive an error if you try to use 'um' for a rotation axis! + m = 1e3 + cm = 10.0 + mm = 1.0 + um = 1e-3 + nm = 1e-6 + + inch = 25.4 + pixel = 0.172 # Pilatus + + deg = 1.0 + rad = np.degrees(1.0) + mrad = np.degrees(1e-3) + urad = np.degrees(1e-6) + + +INTENSITY_EXPECTED_050 = 18800.0 +INTENSITY_EXPECTED_025 = INTENSITY_EXPECTED_050 * 0.5 + + +def get_default_stage(): + return stg + + +# TODO consider if this is better than using EpicsSignal with different read / +# write PVs +class PairSP(Device): + """ + Hold a pair of PVs as a set-point / readback pair + + set forwards to the set point. + """ + + sp = Cpt(EpicsSignal, "-SP", kind="normal") + rb = Cpt(EpicsSignalRO, "-RB", kind="hinted") + + def set(self, value, **kwargs): + return self.sp.set(value, **kwargs) + + +class PairSEL(Device): + """ + Hold a pair of PVs as bool / readback pair + + set forwards to the Select + """ + + sel = Cpt(EpicsSignal, "-Sel", kind="normal") + rb = Cpt(EpicsSignalRO, "-RB", kind="hinted", string=True, auto_monitor=True) + + def set(self, value, **kwargs): + return self.sel.set(value, **kwargs) + + +class PairCMD(Device): + """ + Hold a pair of PVs as CMD / readback pair + + set forwards to the CMD + """ + + cmd = Cpt(EpicsSignal, "-CMD", kind="omitted") + rb = Cpt(EpicsSignalRO, "-RB", kind="hinted") + + def set(self, value, **kwargs): + return self.cmd.set(value, **kwargs) + + +class Laser(Device): + """ + Class to represent the PTA laser as controlled by the beckoff I/O + """ + + # Set pulse width for output + # Milliseconds units + width = Cpt(PairSP, "OutWidthSet:1") + # Set delay between input trigger and output trigger + # Milliseconds units + delay = Cpt(PairSP, "OutDelaySet:1") + # Set number of discrete pulses per trigger event + pulses = Cpt(PairSP, "OutPulsesSet:1") + + # Read inputs + # 1 = PV trigger, 2 = physical trigger + input1 = Cpt(EpicsSignalRO, "Input:1-RB") + input2 = Cpt(EpicsSignalRO, "Input:2-RB") + + # Enable/disable trigger inputs + # 1 = PV trigger, 2 = physical trigger + pv_bitmask = Cpt(PairSEL, "InMaskBit:1") + physical_bitmank = Cpt(PairSEL, "InMaskBit:2") + + # PV Trigger + pv_trigger = Cpt(PairCMD, "Trigger:PV") + + # Enable/disable output trigger mode + trigger_mode = Cpt(PairSEL, "OutMaskBit:1") + + # Output override and output readback + # Override only works when trigger disabled + # manual_button = Cpt(PairSEL, 'Output:1') + manual_button = Cpt(PairSEL, "Output:1-Sel") + + def manual_mode(self): + yield from bps.mv(self.trigger, 0) + + def turn_on(self): + # TODO check if we are in manual mode + yield from bps.mv(self.manual_button, 1) + + def turn_off(self): + # TODO check if we are in manual mode + yield from bps.mv(self.manual_button, 0) + + +laser = Laser("XF:11BM-CT{BIOME-MTO:1}", name="laser") + +# self.powerV_PV = "XF:11BM-CT{BIOME-MTO:1}LaserVoltsSet:1-SP" #changed at 080323 by RL for the new laser control box +# self.controlTTL_PV = "XF:11BM-CT{BIOME-MTO:1}Output:1-Sel" + + +class SampleTSAXS(SampleTSAXS_Generic): + def __init__(self, name, base=None, **md): + super().__init__(name=name, base=base, **md) + self.naming_scheme = ["name", "extra", "temperature", "exposure_time"] + + self.md["exposure_time"] = 30.0 + + +class SampleGISAXS(SampleGISAXS_Generic): + def __init__(self, name, base=None, **md): + super().__init__(name=name, base=base, **md) + self.naming_scheme = ["name", "extra", "th", "exposure_time"] + + +# class Sample(SampleTSAXS): +class Sample(SampleGISAXS): + def __init__(self, name, base=None, **md): + super().__init__(name=name, base=base, **md) + + # self.naming_scheme = ['name', 'extra', 'clock', 'temperature', 'th', 'exposure_time'] + # self.naming_scheme = ['name', 'extra', 'temperature', 'th', 'exposure_time'] + # self.naming_scheme = ['name', 'extra', 'th', 'exposure_time'] + # self.naming_scheme = ['name', 'extra', 'y', 'th', 'clock', 'exposure_time'] + # self.naming_scheme = ['name', 'extra', 'opos', 'lpos', 'x', 'th', 'exposure_time'] + # self.naming_scheme = ['name', 'extra', 'clock', 'localT', 'exposure_time'] + # self.naming_scheme = ['name', 'extra', 'x', 'yy', 'exposure_time'] + # self.naming_scheme = ['name', 'extra', 'SamX', 'SamY', 'exposure_time'] + # self.naming_scheme = ['name', 'extra', 'x', 'yy', 'SamX', 'SamY', 'exposure_time'] + # self.naming_scheme = ['name', 'extra', 'x', 'yy', 'h1', 'h2', 'exposure_time'] + self.naming_scheme = ["name", "extra", "Tc", "clock", "x", "th", "exposure_time"] + self.name_o = self.name + self.md["exposure_time"] = 5.0 + # self.incident_angles_default = [0.08, 0.10, 0.12, 0.15, 0.20] + + # self.anneal_time = int(self.name.split('_')[-2].split('anneal')[-1]) + # self.anneal_time = int(self.name.split('anneal')[-1].split('_')[0]) + # self.preanneal_time = int(self.name.split('pre')[-1].split('_')[0]) + + self._positional_axis = ["x", "y"] + + self.smxPos = [121.5, 142.5, 162.5] + + # self._axes["x"].origin = 130 + # self._axes["y"].origin = 16.8 # smy stage should be set with the limit [-5.5, -5] + # self._axes["th"].origin = 0 + + self._axes["x"].origin = 0 + self._axes["y"].origin = 39.26 # smy stage should be set with the limit [-5.5, -5] + self._axes["th"].origin = 0.93 + + # default position for laser position on the edge of the sample (5mm offset) + # smx = -1.5, laserx = 0 + # smx and laserx should move simultaneously. + + # def get_attribute(self, attribute): + # '''Return the value of the requested md.''' + # #return the value of temperature by IR laser where the + # if attribute == 'localT': + # return 'localT{:.1f}'.format(self.x2localT()) + # elif attribute == 'clockT': + # return 'clock{:.2f}'.format(self.clock()) + # else: + # return super().get_attribute(attribute) + + # #convert temperature to x position to tempreature in the gradient created by laser + # def localT2x(self, temperature, t_range=[25, 500], xo=0, length=10): + # #xo is located at the HOT temperature (laser spot) + # #(x_pos-xo)/(-length) = (temperature-t_range[1])/(t_range[0]-t_range[1]) + # #x_pos = (temperature-t_range[1])/(t_range[0]-t_range[1])*(-length) + xo + + # x_pos = (492 - temperature)/24.7 # P_frac = 0.45 + # return -x_pos + + # #convert x position to tempreature in the gradient created by laser + # def x2localT(self, t_range=[25, 500], xo=0, length=10): + # #(x_pos-xo)/(-length) = (temperature-t_range[1])/(t_range[0]-t_range[1]) + # x_pos = self.xpos(verbosity=0) + # #temperature = (x_pos-xo)/(-length)*(t_range[0]-t_range[1]) + t_range[1] + + # T_est = 492 - abs(x_pos)*24.7 # P_frac = 0.45 + + # return T_est + + def setFlow(self, channel, voltage=0): + # device = 'A1' + ioL.set(AO[channel], 0) + time.sleep(1) + ioL.set(AO[channel], voltage) + + def setDryFlow(self, voltage=None): + if voltage == None or voltage > 5 or voltage < 0: + print("Input voltage betwee 0 and 5V") + self.setFlow(1, voltage=voltage) + + def _set_axes_definitions(self): + """Internal function which defines the axes for this stage. This is kept + as a separate function so that it can be over-ridden easily.""" + + # The _axes_definitions array holds a list of dicts, each defining an axis + super()._set_axes_definitions() + + # self._axes_definitions.append ( {'name': 'y', + # 'motor': smy2, + # 'enabled': True, + # 'scaling': +1.0, + # 'units': 'mm', + # 'hint': 'positive moves stage up', + # }, + # {'name': 'x', + # 'motor': , + # 'enabled': True, + # 'scaling': +1.0, + # 'units': 'mm', + # 'hint': 'positive moves stage up', + # } ) + + def get_attribute(self, attribute): + """Return the value of the requested md.""" + if attribute == "Tc": + # return 'SamX{:.2f}'.format(-1*self.yypos(verbosity=0)) # Nov 2020 + return "Tc{:.2f}".format(pta.getTemperature(verbosity=0)) # Feb 2021 + else: + return super().get_attribute(attribute) + + def get_md(self, prefix="sample_", include_marks=True, **md): + """Returns a dictionary of the current metadata. + The 'prefix' argument is prepended to all the md keys, which allows the + metadata to be grouped with other metadata in a clear way. (Especially, + to make it explicit that this metadata came from the sample.)""" + + # Update internal md + # self.md['key'] = value + + yield from bps.null() ##!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + md_return = self.md.copy() + md_return["name"] = self.name + + if include_marks: + for label, positions in self._marks.items(): + md_return["mark_" + label] = positions + + # Add md that varies over time + md_return["clock"] = self.clock() + + for axis_name, axis in self._axes.items(): + md_return[axis_name] = axis.get_position(verbosity=0) + md_return["motor_" + axis_name] = axis.get_motor_position(verbosity=0) + + md_return["savename"] = self.get_savename() # This should be over-ridden by 'measure' + + # Include the user-specified metadata + md_return.update(md) + + # Add an optional prefix + if prefix is not None: + md_return = {"{:s}{:s}".format(prefix, key): value for key, value in md_return.items()} + + return md_return + + def align(self, step=0, reflection_angle=0.15, verbosity=3): + """Align the sample with respect to the beam. GISAXS alignment involves + vertical translation to the beam center, and rocking theta to get the + sample plane parralel to the beam. Finally, the angle is re-optimized + in reflection mode. + + The 'step' argument can optionally be given to jump to a particular + step in the sequence.""" + start_time = time.time() + alignment = "Success" + initial_y = smy.position + initial_th = sth.position + + align_crazy = self.swing(reflection_angle=reflection_angle) + crazy_y = smy.position + crazy_th = sth.position + + if align_crazy[0] == False: + alignment = "Failed" + if step <= 4: + if verbosity >= 4: + print(" align: fitting") + + fit_scan(smy, 1.2, 21, fit="HMi") + ##time.sleep(2) + fit_scan(sth, 1.5, 21, fit="max") + # time.sleep(2) + + if step <= 8: + # fit_scan(smy, 0.3, 21, fit='sigmoid_r') + + fit_edge(smy, 0.6, 21) + # time.sleep(2) + # fit_edge(smy, 0.4, 21) + fit_scan(sth, 0.8, 21, fit="COM") + # time.sleep(2) + self.setOrigin(["y", "th"]) + + if step <= 9 and reflection_angle is not None: + # Final alignment using reflected beam + if verbosity >= 4: + print(" align: reflected beam") + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2.0) + # get_beamline().setReflectedBeamROI(total_angle=reflection_angle*2.0, size=[12,2]) + + self.thabs(reflection_angle) + + result = fit_scan(sth, 0.4, 41, fit="max") + # result = fit_scan(sth, 0.2, 81, fit='max') #it's useful for alignment of SmarAct stage + sth_target = result.values["x_max"] - reflection_angle + + if result.values["y_max"] > 50: + th_target = self._axes["th"].motor_to_cur(sth_target) + self.thsetOrigin(th_target) + + # fit_scan(smy, 0.2, 21, fit='max') + # self.setOrigin(['y']) + + if step <= 10: + self.thabs(0.0) + beam.off() + + ### save the alignment information + align_time = time.time() - start_time + + # current_data = { + # "a_sample": self.name, + # "i_smx": smx.position, + # "j_smy": smy.position, + # "k_sth": sth.position, + # "l_laserx": laserx.position, + # "m_power": caget(pta.powerV_PV), + # "b_quick_alignment": alignment, + # "c_align_time": align_time, + # "d_offset_y": smy.position - initial_y, + # "e_offset_th": sth.position - initial_th, + # "f_crazy_offset_y": smy.position - crazy_y, + # "g_crazy_offset_th": sth.position - crazy_th, + # "h_search_no": align_crazy[1], + # } + + # temp_data = pds.DataFrame([current_data]) + + # INT_FILENAME = "{}/data/{}.csv".format(os.path.dirname(__file__), "alignment_results.csv") + + # if os.path.isfile(INT_FILENAME): + # output_data = pds.read_csv(INT_FILENAME, index_col=0) + # output_data = output_data.append(temp_data, ignore_index=True) + # output_data.to_csv(INT_FILENAME) + # else: + # temp_data.to_csv(INT_FILENAME) + + def align_old(self, step=0, reflection_angle=0.12, verbosity=3): + """Align the sample with respect to the beam. GISAXS alignment involves + vertical translation to the beam center, and rocking theta to get the + sample plane parralel to the beam. Finally, the angle is re-optimized + in reflection mode. + + The 'step' argument can optionally be given to jump to a particular + step in the sequence.""" + # if step<=4: + # if verbosity>=4: + # print(' align: fitting') + + # fit_scan(smy, 1.2, 21, fit='HMi') + # ##time.sleep(2) + # fit_scan(sth, 1.5, 21, fit='max') + ##time.sleep(2) + cms.modeAlignment() + self.yo() + self.tho() + if step <= 8: + # fit_scan(smy, 0.3, 21, fit='sigmoid_r') + + fit_edge(smy, 0.6, 21) + # time.sleep(2) + # fit_edge(smy, 0.4, 21) + fit_scan(sth, 0.8, 21, fit="COM") + # time.sleep(2) + self.setOrigin(["y", "th"]) + + if step <= 9 and reflection_angle is not None: + # Final alignment using reflected beam + if verbosity >= 4: + print(" align: reflected beam") + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2.0) + # get_beamline().setReflectedBeamROI(total_angle=reflection_angle*2.0, size=[12,2]) + + self.thabs(reflection_angle) + + result = fit_scan(sth, 0.4, 41, fit="max") + # result = fit_scan(sth, 0.2, 81, fit='max') #it's useful for alignment of SmarAct stage + sth_target = result.values["x_max"] - reflection_angle + + if result.values["y_max"] > 50: + th_target = self._axes["th"].motor_to_cur(sth_target) + self.thsetOrigin(th_target) + + # fit_scan(smy, 0.2, 21, fit='max') + # self.setOrigin(['y']) + + if step <= 10: + self.thabs(0.0) + beam.off() + + def align_th(self, step=0, reflection_angle=0.12, verbosity=3): + """Align the sample with respect to the beam. GISAXS alignment involves + vertical translation to the beam center, and rocking theta to get the + sample plane parralel to the beam. Finally, the angle is re-optimized + in reflection mode. + + The 'step' argument can optionally be given to jump to a particular + step in the sequence.""" + # if step<=4: + # if verbosity>=4: + # print(' align: fitting') + + # fit_scan(smy, 1.2, 21, fit='HMi') + # ##time.sleep(2) + # fit_scan(sth, 1.5, 21, fit='max') + ##time.sleep(2) + cms.modeAlignment() + self.yo() + self.tho() + + if step <= 9 and reflection_angle is not None: + # Final alignment using reflected beam + if verbosity >= 4: + print(" align: reflected beam") + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2.0) + # get_beamline().setReflectedBeamROI(total_angle=reflection_angle*2.0, size=[12,2]) + + self.thabs(reflection_angle) + + result = fit_scan(sth, 0.2, 21, fit="max") + # result = fit_scan(sth, 0.2, 81, fit='max') #it's useful for alignment of SmarAct stage + sth_target = result.values["x_max"] - reflection_angle + + if result.values["y_max"] > 50: + th_target = self._axes["th"].motor_to_cur(sth_target) + self.thsetOrigin(th_target) + + # fit_scan(smy, 0.2, 21, fit='max') + # self.setOrigin(['y']) + + if step <= 10: + self.thabs(0.0) + beam.off() + + def align_crazy_v2( + self, step=0, reflection_angle=0.12, ROI_size=[10, 180], th_range=0.3, int_threshold=10, verbosity=3 + ): + # setting parameters + rel_th = 1 + ct = 0 + cycle = 0 + intenisty_threshold = 10 + + # re-assure the 3 ROI positon + get_beamline().setDirectBeamROI() + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2) + + # set ROI2 as a fixed area + get_beamline().setROI2ReflectBeamROI(total_angle=reflection_angle * 2, size=ROI_size) + pilatus2M.roi2.size.y.set(200) + pilatus2M.roi2.min_xyz.min_y.set(852) + + # def ROI3 in 160pixels with the center located at reflection beam + # get_beamline().setReflectedBeamROI(total_angle = reflection_angle*2, size=ROI_size) #set ROI3 + + # self.thabs(reflection_angle) + if verbosity >= 4: + print(" Aligning {}".format(self.name)) + + if step <= 0: + # Prepare for alignment + + if RE.state != "idle": + RE.abort() + + if get_beamline().current_mode != "alignment": + # if verbosity>=2: + # print("WARNING: Beamline is not in alignment mode (mode is '{}')".format(get_beamline().current_mode)) + print("Switching to alignment mode (current mode is '{}')".format(get_beamline().current_mode)) + get_beamline().modeAlignment() + + get_beamline().setDirectBeamROI() + + beam.on() + + if step <= 2: + if verbosity >= 4: + print(" align: searching") + + # Estimate full-beam intensity + value = None + if True: + # You can eliminate this, in which case RE.md['beam_intensity_expected'] is used by default + self.yr(-0.5) + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + value_name = get_beamline().TABLE_COLS[0] + RE(count([detector])) + value = detector.read()[value_name]["value"] + self.yr(0.5) + + if "beam_intensity_expected" in RE.md: + if value < RE.md["beam_intensity_expected"] * 0.75: + print( + "WARNING: Direct beam intensity ({}) lower than it should be ({})".format( + value, RE.md["beam_intensity_expected"] + ) + ) + + # check the last value: + ii = 0 + while abs(pilatus2M.stats4.total.get() - value) / value < 0.1 and ii < 3: + ii += 1 + # Find the step-edge + self.ysearch( + step_size=0.2, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1 + ) + + # Find the peak + self.thsearch(step_size=0.2, min_step=0.01, target="max", verbosity=verbosity) + + # last check for height + self.ysearch( + step_size=0.05, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1 + ) + + # check reflection beam + self.thr(reflection_angle) + RE(count([detector])) + + if ( + abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) < 20 + and detector.stats2.max_value.get() > intenisty_threshold + ): + # continue the fast alignment + print("The reflective beam is found! Continue the fast alignment") + + while abs(rel_th) > 0.005 and ct < 5: + # while detector.roi3.max_value.get() > 50 and ct < 5: + + # absolute beam position + refl_beam = detector.roi2.min_xyz.min_y.get() + detector.stats2.max_xy.y.get() + + # roi3 position + roi3_beam = detector.roi3.min_xyz.min_y.get() + detector.roi3.size.y.get() / 2 + + # distance from current postion to the center of roi2 (the disired rel beam position) + # rel_ypos = detector.stats2.max_xy.get().y - detector.stats2.size.get().y + rel_ypos = refl_beam - roi3_beam + + rel_th = rel_ypos / get_beamline().SAXS.distance / 1000 * 0.172 / np.pi * 180 / 2 + + print("The th offset is {}".format(rel_th)) + self.thr(rel_th) + + ct += 1 + RE(count([detector])) + + if detector.stats3.total.get() > 50: + print("The fast alignment works!") + self.thr(-reflection_angle) + self.setOrigin(["y", "th"]) + + beam.off() + + return True, ii + + else: + print("Alignment Error: Cannot Locate the reflection beam") + self.thr(-reflection_angle) + beam.off() + + return False, ii + + elif abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) > 5: + print("Max and Centroid dont Match!") + + # perform the full alignment + print("Alignment Error: No reflection beam is found!") + self.thr(-reflection_angle) + beam.off() + return False, ii + + else: + print("Intensiy < threshold!") + + # perform the full alignment + print("Alignment Error: No reflection beam is found!") + self.thr(-reflection_angle) + beam.off() + return False, ii + + def align_crazy_v3( + self, step=0, reflection_angle=0.12, ROI_size=[10, 180], th_range=0.3, int_threshold=10, verbosity=3 + ): + # setting parameters + rel_th = 1 + ct = 0 + cycle = 0 + intenisty_threshold = 10 + + # re-assure the 3 ROI positon + get_beamline().setDirectBeamROI() + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2) + detector = get_beamline().detector[0] + + # set ROI2 as a fixed area + get_beamline().setROI2ReflectBeamROI(total_angle=reflection_angle * 2, size=ROI_size) + pilatus2M.roi2.size.y.set(200) + pilatus2M.roi2.min_xyz.min_y.set(842) + + # def ROI3 in 160pixels with the center located at reflection beam + # get_beamline().setReflectedBeamROI(total_angle = reflection_angle*2, size=ROI_size) #set ROI3 + + # self.thabs(reflection_angle) + if verbosity >= 4: + print(" Aligning {}".format(self.name)) + + if step <= 0: + # Prepare for alignment + + if RE.state != "idle": + RE.abort() + + if get_beamline().current_mode != "alignment": + # if verbosity>=2: + # print("WARNING: Beamline is not in alignment mode (mode is '{}')".format(get_beamline().current_mode)) + print("Switching to alignment mode (current mode is '{}')".format(get_beamline().current_mode)) + get_beamline().modeAlignment() + + get_beamline().setDirectBeamROI() + + beam.on() + + if step <= 2: + ######################### fast alignment in the case2 and 3 -- NO refl beam + self.thabs(0.12) + self.snap(0.5) + roi2_int = pilatus2M.stats2.total.get() + roi4_int = pilatus2M.stats4.total.get() + threshold = 100 + beam_int = 20000 + target_ratio = 0.5 + beam.on() + if roi2_int < threshold: + print("CASE 2 or 3") + + roi4_int = pilatus2M.stats4.total.get() + roi2_int = pilatus2M.stats2.total.get() + + roi4_beam = roi4_int / beam_int + + min_step = 0.005 + # if roi4_beam 0.005 and ct < 5: + # while detector.roi3.max_value.get() > 50 and ct < 5: + + print("CASE 2 ") + + # absolute beam position + refl_beam = detector.roi2.min_xyz.min_y.get() + detector.stats2.max_xy.y.get() + + # roi3 position + roi3_beam = detector.roi3.min_xyz.min_y.get() + detector.roi3.size.y.get() / 2 + + # distance from current postion to the center of roi2 (the disired rel beam position) + # rel_ypos = detector.stats2.max_xy.get().y - detector.stats2.size.get().y + rel_ypos = refl_beam - roi3_beam + + rel_th = rel_ypos / get_beamline().SAXS.distance / 1000 * 0.172 / np.pi * 180 / 2 + + print("The th offset is {}".format(rel_th)) + self.thr(rel_th) + + ct += 1 + RE(count([pilatus2M])) + # self.ysearch(step_size=0.01, min_step=0.005, intensity=beam_int, target=0.5, verbosity=verbosity, polarity=-1) + + ######################### fast alignment in the case1 -- both refl and direct beam + target_ratio = 1 + # self.snap() + print("CASE 1") + + def get_roi2_4(): + roi2_int = pilatus2M.stats2.total.get() + roi2_int = roi2_int if roi2_int > 0 else 0 + roi4_int = pilatus2M.stats4.total.get() + roi4_int = roi4_int if roi4_int > 0 else 0 + return roi2_int / (roi4_int + 10) + + roi2_4 = get_roi2_4() + + min_step = 0.005 + while abs(roi2_4 - target_ratio) > 0.2: + print(roi2_4) + if roi2_4 < target_ratio: + # print(" +Y") + step = min_step + else: + # print(" -Y") + step = -min_step + + self.yr(step) + self.snap() + roi2_4 = get_roi2_4() + + if step > 5: + if verbosity >= 4: + print(" align: searching") + + # Estimate full-beam intensity + value = None + if True: + # You can eliminate this, in which case RE.md['beam_intensity_expected'] is used by default + self.yr(-0.5) + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + value_name = get_beamline().TABLE_COLS[0] + RE(count([detector])) + value = detector.read()[value_name]["value"] + self.yr(0.5) + + if "beam_intensity_expected" in RE.md: + if value < RE.md["beam_intensity_expected"] * 0.75: + print( + "WARNING: Direct beam intensity ({}) lower than it should be ({})".format( + value, RE.md["beam_intensity_expected"] + ) + ) + + # check the last value: + ii = 0 + while abs(pilatus2M.stats4.total.get() - value) / value < 0.1 and ii < 3: + ii += 1 + # Find the step-edge + self.ysearch( + step_size=0.2, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1 + ) + + # Find the peak + self.thsearch(step_size=0.2, min_step=0.01, target="max", verbosity=verbosity) + + # last check for height + self.ysearch( + step_size=0.05, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1 + ) + + if step > 5: + # check reflection beam + self.thr(reflection_angle) + RE(count([detector])) + + if ( + abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) < 20 + and detector.stats2.max_value.get() > intenisty_threshold + ): + # continue the fast alignment + print("The reflective beam is found! Continue the fast alignment") + + while abs(rel_th) > 0.005 and ct < 5: + # while detector.roi3.max_value.get() > 50 and ct < 5: + + # absolute beam position + refl_beam = detector.roi2.min_xyz.min_y.get() + detector.stats2.max_xy.y.get() + + # roi3 position + roi3_beam = detector.roi3.min_xyz.min_y.get() + detector.roi3.size.y.get() / 2 + + # distance from current postion to the center of roi2 (the disired rel beam position) + # rel_ypos = detector.stats2.max_xy.get().y - detector.stats2.size.get().y + rel_ypos = refl_beam - roi3_beam + + rel_th = rel_ypos / get_beamline().SAXS.distance / 1000 * 0.172 / np.pi * 180 / 2 + + print("The th offset is {}".format(rel_th)) + self.thr(rel_th) + + ct += 1 + RE(count([detector])) + + # if detector.stats3.total.get()>50: + + # print('The fast alignment works!') + # self.thr(-reflection_angle) + # self.setOrigin(['y', 'th']) + + # beam.off() + + # return True, ii + + # else: + # print('Alignment Error: Cannot Locate the reflection beam') + # self.thr(-reflection_angle) + # beam.off() + + # return False, ii + + # elif abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) > 5: + # print('Max and Centroid dont Match!') + + # #perform the full alignment + # print('Alignment Error: No reflection beam is found!') + # self.thr(-reflection_angle) + # beam.off() + # return False, ii + + # else: + # print('Intensiy < threshold!') + + # #perform the full alignment + # print('Alignment Error: No reflection beam is found!') + # self.thr(-reflection_angle) + # beam.off() + # return False, ii + + def align_crazy_v3_plan( + self, + step=0, + reflection_angle=0.12, + ROI_size=[10, 180], + th_range=0.3, + int_threshold=10, + direct_beam_int=None, + verbosity=3, + detector=None, + detector_suffix=None, + ): + if detector is None: + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + + # if detector_suffix is None: + # #value_name = gs.TABLE_COLS[0] + # value_name = get_beamline().TABLE_COLS[0] + # else: + # value_name = detector.name + detector_suffix + + motors_for_table = [smx, smy, sth] + + @bpp.stage_decorator([detector]) + @bpp.run_decorator(md={}) + @bpp.finalize_decorator(final_plan=shutter_off) + def inner_align(group=None): + nonlocal step, reflection_angle + + if group: + yield from bps.wait(group) + + # setting parameters + rel_th = 1 + ct = 0 + cycle = 0 + intenisty_threshold = 50 + + # re-assure the 3 ROI positon + get_beamline().setDirectBeamROI() + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2) + detector = get_beamline().detector[0] + + # set ROI2 as a fixed area + get_beamline().setROI2ReflectBeamROI(total_angle=reflection_angle * 2, size=ROI_size) + pilatus2M.roi2.size.y.set(200) + pilatus2M.roi2.min_xyz.min_y.set(842) + + # def ROI3 in 160pixels with the center located at reflection beam + # get_beamline().setReflectedBeamROI(total_angle = reflection_angle*2, size=ROI_size) #set ROI3 + + # self.thabs(reflection_angle) + if verbosity >= 4: + print(" Aligning {}".format(self.name)) + + if step <= 0: + print(f"Step <= 0") + # Prepare for alignment + if get_beamline().current_mode != "alignment": + # if verbosity>=2: + # print("WARNING: Beamline is not in alignment mode (mode is '{}')".format(get_beamline().current_mode)) + print("Switching to alignment mode (current mode is '{}')".format(get_beamline().current_mode)) + yield from get_beamline().modeAlignment() + + get_beamline().setDirectBeamROI() + + yield from shutter_on() + + if direct_beam_int is not None: + value = direct_beam_int + elif hasattr(cms, "direct_beam_int") and cms.direct_beam_int is not None: + value = cms.direct_beam_int + else: + value = 0 + # You can eliminate this, in which case RE.md['beam_intensity_expected'] is used by default + for n in range(1, 4): + self.yr(-0.5) + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + value_name = get_beamline().TABLE_COLS[0] + yield from bps.trigger_and_read([detector, *motors_for_table]) + value = detector.read()[value_name]["value"] + if value > 100: + cms.direct_beam_int = value + self.yr(0.5) + break + + if "beam_intensity_expected" in RE.md: + if value < RE.md["beam_intensity_expected"] * 0.75: + print( + "WARNING: Direct beam intensity ({}) lower than it should be ({})".format( + value, RE.md["beam_intensity_expected"] + ) + ) + + if step <= 2: + print("Step <= 2") + + ######################### fast alignment in the case2 and 3 -- NO refl beam + self.thabs(0.12) + # self.snap(0.5) + yield from bps.trigger_and_read([detector, *motors_for_table]) + roi2_int = pilatus2M.stats2.total.get() + roi4_int = pilatus2M.stats4.total.get() + threshold = 500 + beam_int = value + target_ratio = 0.5 + # yield from shutter_on() + print(f"roi2_int={roi2_int} threshold={threshold}") + + if roi2_int < threshold: + print("CASE 2 or 3") + + roi4_int = pilatus2M.stats4.total.get() + roi2_int = pilatus2M.stats2.total.get() + + roi4_beam = roi4_int / beam_int + + min_step = 0.005 + # if roi4_beam 0 and norm_stats4 > 0.2: + break + + # Find the step-edge + yield from self.search_stub2( + motor=smy, + step_size=0.2, + min_step=0.005, + target=0.5, + intensity=beam_int, + polarity=-1, + detector=detector, + detector_suffix="_stats4_total", + ) + + yield from self.search_stub2( + motor=sth, + step_size=0.2, + min_step=0.01, + target="max", + polarity=-1, + detector=detector, + detector_suffix="_stats4_total", + ) + + # self.ysearch(step_size=0.2, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1) + + # # Find the peak + # self.thsearch(step_size=0.2, min_step=0.01, target='max', verbosity=verbosity) + + # last check for height + # self.ysearch(step_size=0.05, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1) + yield from self.search_stub2( + motor=smy, + step_size=0.05, + min_step=0.005, + target=0.5, + intensity=beam_int, + polarity=-1, + detector=detector, + detector_suffix="_stats4_total", + ) + + # self.ysearch(step_size=0.01, min_step=0.005, intensity=beam_int, target=0.5, verbosity=verbosity, polarity=-1) + # else: + # print(' -Y') + # self.ysearch(step_size=0.01, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1) + + roi4_beam = roi4_int / beam_int + roi2_int = pilatus2M.stats2.total.get() + + else: + # very close to aligned position + reflection_angle = 0 + # #use the beam heigh to find the correct refl beam + # print('Search the refl beam') + # yield from bps.trigger_and_read([detector, *motors_for_table]) + # # RE(count([pilatus2M])) + + # roi4_beam = roi4_int/beam_int + # roi2_int = pilatus2M.stats2.total.get() + # # roi2_int = roi2_i + # th_step = 0.1 + + # while roi2_int 0.005 and ct < 5: + # # while detector.roi3.max_value.get() > 50 and ct < 5: + + # print("CASE 2 ") + + # #absolute beam position + # refl_beam = detector.roi2.min_xyz.min_y.get() + detector.stats2.max_xy.y.get() + + # #roi3 position + # roi3_beam = detector.roi3.min_xyz.min_y.get() + detector.roi3.size.y.get()/2 + + # #distance from current postion to the center of roi2 (the disired rel beam position) + # # rel_ypos = detector.stats2.max_xy.get().y - detector.stats2.size.get().y + # rel_ypos = refl_beam - roi3_beam + + # rel_th = rel_ypos/get_beamline().SAXS.distance/1000*0.172/np.pi*180/2 + + # print('The th offset is {}'.format(rel_th)) + # self.thr(rel_th) + + # ct += 1 + # yield from bps.trigger_and_read([detector, *motors_for_table]) + # # RE(count([pilatus2M])) + # # self.ysearch(step_size=0.01, min_step=0.005, intensity=beam_int, target=0.5, verbosity=verbosity, polarity=-1) + + ######################### fast alignment in the case1 -- both refl and direct beam + + # self.thr(reflection_angle) + # yield from bps.trigger_and_read([detector, *motors_for_table]) + # RE(count([detector])) + + # # if abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) < 20 and detector.stats2.max_value.get() > intenisty_threshold: + + # target_ratio = 1 + # # self.snap() + # print("CASE 1") + + # def get_roi2_4(): + # roi2_int = pilatus2M.stats2.total.get() + # roi2_int = roi2_int if roi2_int > 0 else 0 + # roi4_int = pilatus2M.stats4.total.get() + # roi4_int = roi4_int if roi4_int > 0 else 0 + # return roi2_int/(roi4_int + 10) + + # roi2_4 = get_roi2_4() + + # min_step=0.005 + # while abs(roi2_4 - target_ratio)>0.2: + # print(roi2_4) + # if roi2_45: + + # if verbosity>=4: + # print(' align: searching') + + # # Estimate full-beam intensity + # value = None + # if True: + # # You can eliminate this, in which case RE.md['beam_intensity_expected'] is used by default + # self.yr(-0.5) + # #detector = gs.DETS[0] + # detector = get_beamline().detector[0] + # value_name = get_beamline().TABLE_COLS[0] + # yield from bps.trigger_and_read([detector, *motors_for_table]) + # # RE(count([detector])) + # value = detector.read()[value_name]['value'] + # self.yr(0.5) + + # if 'beam_intensity_expected' in RE.md: + # if value intenisty_threshold: + # continue the fast alignment + print("The reflective beam is found! Continue the fast alignment") + + while abs(rel_th) > 0.005 and ct < 5: + # while detector.roi3.max_value.get() > 50 and ct < 5: + + # absolute beam position + refl_beam = detector.roi2.min_xyz.min_y.get() + detector.stats2.max_xy.y.get() + + # roi3 position + roi3_beam = detector.roi3.min_xyz.min_y.get() + detector.roi3.size.y.get() / 2 + + # distance from current postion to the center of roi2 (the disired rel beam position) + # rel_ypos = detector.stats2.max_xy.get().y - detector.stats2.size.get().y + rel_ypos = refl_beam - roi3_beam + + rel_th = rel_ypos / get_beamline().SAXS.distance / 1000 * 0.172 / np.pi * 180 / 2 + + print("The th offset is {}".format(rel_th)) + self.thr(rel_th) + + ct += 1 + yield from bps.trigger_and_read([detector, *motors_for_table]) + # RE(count([detector])) + + # if detector.stats3.total.get()>50: + + # print('The fast alignment works!') + # self.thr(-reflection_angle) + # self.setOrigin(['y', 'th']) + + # beam.off() + + # return True, ii + + # else: + # print('Alignment Error: Cannot Locate the reflection beam') + # self.thr(-reflection_angle) + # beam.off() + + # return False, ii + + # elif abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) > 5: + # print('Max and Centroid dont Match!') + + # #perform the full alignment + # print('Alignment Error: No reflection beam is found!') + # self.thr(-reflection_angle) + # beam.off() + # return False, ii + + # else: + # print('Intensiy < threshold!') + + # #perform the full alignment + # print('Alignment Error: No reflection beam is found!') + # self.thr(-reflection_angle) + # beam.off() + # return False, ii + + group_name = "setup_aligment" + + # alignment mode + yield from bps.abs_set(bsx, cms.bsx_pos + 3, group=group_name) + beam.setTransmission(1e-6) + + # align as abovve + yield from inner_align(group=group_name) + + # move bs back + yield from bps.abs_set(bsx, cms.bsx_pos, group=group_name) + yield from bps.wait(group_name) + + # set the position for sample + # self.thr(reflection_angle) + # self.setOrigin(['y', 'th']) + + def swing_v2( + self, step=0, reflection_angle=0.12, ROI_size=[10, 180], th_range=0.3, int_threshold=10, verbosity=3 + ): + # setting parameters + rel_th = 1 + ct = 0 + cycle = 0 + intenisty_threshold = 10 + + # re-assure the 3 ROI positon + get_beamline().setDirectBeamROI() + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2) + + # set ROI2 as a fixed area + get_beamline().setROI2ReflectBeamROI(total_angle=reflection_angle * 2, size=ROI_size) + pilatus2M.roi2.size.y.set(190) + pilatus2M.roi2.min_xyz.min_y.set(852) + + # def ROI3 in 160pixels with the center located at reflection beam + # get_beamline().setReflectedBeamROI(total_angle = reflection_angle*2, size=ROI_size) #set ROI3 + + # self.thabs(reflection_angle) + if verbosity >= 4: + print(" Aligning {}".format(self.name)) + + # if step<=0: + # # Prepare for alignment + + # if RE.state!='idle': + # RE.abort() + + # if get_beamline().current_mode!='alignment': + # #if verbosity>=2: + # #print("WARNING: Beamline is not in alignment mode (mode is '{}')".format(get_beamline().current_mode)) + # print("Switching to alignment mode (current mode is '{}')".format(get_beamline().current_mode)) + # get_beamline().modeAlignment() + + get_beamline().setDirectBeamROI() + + beam.on() + + if step <= 2: + # if verbosity>=4: + # print(' align: searching') + + # Estimate full-beam intensity + value = None + if True: + # You can eliminate this, in which case RE.md['beam_intensity_expected'] is used by default + self.yr(-0.5) + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + # value_name = get_beamline().TABLE_COLS[0] + beam.on() + RE(count([detector])) + value = detector.read()["pilatus2M_stats4_total"]["value"] + self.yr(0.5) + + # if 'beam_intensity_expected' in RE.md: + # if value intenisty_threshold + ): + # continue the fast alignment + print("The reflective beam is found! Continue the fast alignment") + + while abs(rel_th) > 0.005 and ct < 5: + # while detector.roi3.max_value.get() > 50 and ct < 5: + + # absolute beam position + refl_beam = detector.roi2.min_xyz.min_y.get() + detector.stats2.max_xy.y.get() + + # roi3 position + roi3_beam = detector.roi3.min_xyz.min_y.get() + detector.roi3.size.y.get() / 2 + + # distance from current postion to the center of roi2 (the disired rel beam position) + # rel_ypos = detector.stats2.max_xy.get().y - detector.stats2.size.get().y + rel_ypos = refl_beam - roi3_beam + + rel_th = rel_ypos / get_beamline().SAXS.distance / 1000 * 0.172 / np.pi * 180 / 2 + + print("The th offset is {}".format(rel_th)) + self.thr(rel_th) + + ct += 1 + RE(count([detector])) + + if detector.stats3.total.get() > 50: + print("The fast alignment works!") + self.thr(-reflection_angle) + + if fastsearch == False: + RE( + self.search_plan( + motor=smy, + step_size=0.05, + min_step=0.005, + target=0.5, + intensity=20000, + polarity=-1, + detector_suffix="_stats4_total", + ) + ) + + self.setOrigin(["y", "th"]) + + beam.off() + + return True, ii + + else: + print("Alignment Error: Cannot Locate the reflection beam") + self.thr(-reflection_angle) + beam.off() + + return False, ii + + elif abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) > 5: + print("Max and Centroid dont Match!") + + # perform the full alignment + print("Alignment Error: No reflection beam is found!") + self.thr(-reflection_angle) + beam.off() + return False, ii + + else: + print("Intensiy < threshold!") + + # perform the full alignment + print("Alignment Error: No reflection beam is found!") + self.thr(-reflection_angle) + beam.off() + return False, ii + + def swing_March( + self, + step=0, + reflection_angle=0.12, + ROI_size=[10, 180], + th_range=0.3, + intensity=20000, + int_threshold=10, + verbosity=3, + ): + # setting parameters + rel_th = 1 + ct = 0 + cycle = 0 + intenisty_threshold = 10 + + # re-assure the 3 ROI positon + get_beamline().setDirectBeamROI() + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2) + + # set ROI2 as a fixed area + get_beamline().setROI2ReflectBeamROI(total_angle=reflection_angle * 2, size=ROI_size) + pilatus2M.roi2.size.y.set(190) + pilatus2M.roi2.min_xyz.min_y.set(852) + + # def ROI3 in 160pixels with the center located at reflection beam + # get_beamline().setReflectedBeamROI(total_angle = reflection_angle*2, size=ROI_size) #set ROI3 + + # self.thabs(reflection_angle) + if verbosity >= 4: + print(" Aligning {}".format(self.name)) + + # if step<=0: + # # Prepare for alignment + + # if RE.state!='idle': + # RE.abort() + + # if get_beamline().current_mode!='alignment': + # #if verbosity>=2: + # #print("WARNING: Beamline is not in alignment mode (mode is '{}')".format(get_beamline().current_mode)) + # print("Switching to alignment mode (current mode is '{}')".format(get_beamline().current_mode)) + # get_beamline().modeAlignment() + + get_beamline().setDirectBeamROI() + + beam.on() + + if step <= 2: + # if verbosity>=4: + # print(' align: searching') + + # Estimate full-beam intensity + value = None + if True: + # You can eliminate this, in which case RE.md['beam_intensity_expected'] is used by default + # self.yr(-0.5) + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + # value_name = get_beamline().TABLE_COLS[0] + beam.on() + RE(count([detector])) + value = detector.read()["pilatus2M_stats4_total"]["value"] + # self.yr(0.5) + + # if 'beam_intensity_expected' in RE.md: + # if value intenisty_threshold + ): + # continue the fast alignment + print("The reflective beam is found! Continue the fast alignment") + + # for sth + while abs(rel_th) > 0.005 and ct < 5: + # while detector.roi3.max_value.get() > 50 and ct < 5: + + # absolute beam position + refl_beam = detector.roi2.min_xyz.min_y.get() + detector.stats2.max_xy.y.get() + + # roi3 position + roi3_beam = detector.roi3.min_xyz.min_y.get() + detector.roi3.size.y.get() / 2 + + # distance from current postion to the center of roi2 (the disired rel beam position) + # rel_ypos = detector.stats2.max_xy.get().y - detector.stats2.size.get().y + rel_ypos = refl_beam - roi3_beam + + rel_th = rel_ypos / get_beamline().SAXS.distance / 1000 * 0.172 / np.pi * 180 / 2 + + print("The th offset is {}".format(rel_th)) + self.thr(rel_th) + + ct += 1 + RE(count([detector])) + + # for smy + # Find the step-edge + fastsearch = RE( + self.search_plan( + motor=smy, + step_size=0.05, + min_step=0.01, + target="max", + # intensity=intensity, + polarity=-1, + # fastsearch=True, + detector_suffix="_stats3_total", + ) + ) + + # if detector.stats3.total.get() > 50: + + # print("The fast alignment works!") + # self.thr(-reflection_angle) + + # if fastsearch == False: + # RE( + # self.search_plan( + # motor=smy, + # step_size=0.05, + # min_step=0.005, + # target=0.5, + # intensity=20000, + # polarity=-1, + # detector_suffix="_stats4_total", + # ) + # ) + + self.setOrigin(["y", "th"]) + + beam.off() + + return True, ii + + # else: + # print("Alignment Error: Cannot Locate the reflection beam") + # self.thr(-reflection_angle) + # beam.off() + + # return False, ii + + # elif abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) > 5: + # print("Max and Centroid dont Match!") + + # # perform the full alignment + # print("Alignment Error: No reflection beam is found!") + # self.thr(-reflection_angle) + # beam.off() + # return False, ii + + # else: + # print("Intensiy < threshold!") + + # # perform the full alignment + # print("Alignment Error: No reflection beam is found!") + # self.thr(-reflection_angle) + # beam.off() + # return False, ii + + def swing( + self, step=0, reflection_angle=0.12, ROI_size=[10, 180], th_range=0.3, int_threshold=10, verbosity=3 + ): + # setting parameters + rel_th = 1 + ct = 0 + cycle = 0 + intenisty_threshold = 10 + + # re-assure the 3 ROI positon + get_beamline().setDirectBeamROI() + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2) + + # set ROI2 as a fixed area + get_beamline().setROI2ReflectBeamROI(total_angle=reflection_angle * 2, size=ROI_size) + pilatus2M.roi2.size.y.set(190) + pilatus2M.roi2.min_xyz.min_y.set(852) + + # def ROI3 in 160pixels with the center located at reflection beam + # get_beamline().setReflectedBeamROI(total_angle = reflection_angle*2, size=ROI_size) #set ROI3 + + # self.thabs(reflection_angle) + if verbosity >= 4: + print(" Aligning {}".format(self.name)) + + # if step<=0: + # # Prepare for alignment + + # if RE.state!='idle': + # RE.abort() + + # if get_beamline().current_mode!='alignment': + # #if verbosity>=2: + # #print("WARNING: Beamline is not in alignment mode (mode is '{}')".format(get_beamline().current_mode)) + # print("Switching to alignment mode (current mode is '{}')".format(get_beamline().current_mode)) + # get_beamline().modeAlignment() + + get_beamline().setDirectBeamROI() + + # RE(beam.on()) + RE(shutter_on()) + + if step <= 2: + # if verbosity>=4: + # print(' align: searching') + + # Estimate full-beam intensity + value = None + if True: + # You can eliminate this, in which case RE.md['beam_intensity_expected'] is used by default + self.yr(-1) + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + # value_name = get_beamline().TABLE_COLS[0] + RE(shutter_on()) + # RE(beam.on()) + RE(count([detector])) + value = detector.read()["pilatus2M_stats4_total"]["value"] + self.yr(1) + + # if 'beam_intensity_expected' in RE.md: + # if value intenisty_threshold + ): + # continue the fast alignment + print("The reflective beam is found! Continue the fast alignment") + + while abs(rel_th) > 0.005 and ct < 5: + # while detector.roi3.max_value.get() > 50 and ct < 5: + + # absolute beam position + refl_beam = detector.roi2.min_xyz.min_y.get() + detector.stats2.max_xy.y.get() + + # roi3 position + roi3_beam = detector.roi3.min_xyz.min_y.get() + detector.roi3.size.y.get() / 2 + + # distance from current postion to the center of roi2 (the disired rel beam position) + # rel_ypos = detector.stats2.max_xy.get().y - detector.stats2.size.get().y + rel_ypos = refl_beam - roi3_beam + + rel_th = rel_ypos / get_beamline().SAXS.distance / 1000 * 0.172 / np.pi * 180 / 2 + + print("The th offset is {}".format(rel_th)) + self.thr(rel_th) + + ct += 1 + RE(count([detector])) + + if detector.stats3.total.get() > 50: + print("The fast alignment works!") + self.thr(-reflection_angle) + + self.setOrigin(["y", "th"]) + + beam.off() + + return True, ii + + else: + print("Alignment Error: Cannot Locate the reflection beam") + self.thr(-reflection_angle) + beam.off() + + return False, ii + + elif abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) > 5: + print("Max and Centroid dont Match!") + + # perform the full alignment + print("Alignment Error: No reflection beam is found!") + self.thr(-reflection_angle) + beam.off() + return False, ii + + else: + print("Intensiy < threshold!") + + # perform the full alignment + print("Alignment Error: No reflection beam is found!") + self.thr(-reflection_angle) + beam.off() + return False, ii + + def crazy_th( + self, step=0, reflection_angle=0.12, ROI_size=[10, 180], th_range=0.3, int_threshold=10, verbosity=3 + ): + # setting parameters + rel_th = 1 + ct = 0 + cycle = 0 + intenisty_threshold = 10 + + # re-assure the 3 ROI positon + get_beamline().setDirectBeamROI() + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2) + + # set ROI2 as a fixed area + get_beamline().setROI2ReflectBeamROI(total_angle=reflection_angle * 2, size=ROI_size) + pilatus2M.roi2.size.y.set(200) + pilatus2M.roi2.min_xyz.min_y.set(852) + + # def ROI3 in 160pixels with the center located at reflection beam + # get_beamline().setReflectedBeamROI(total_angle = reflection_angle*2, size=ROI_size) #set ROI3 + + # self.thabs(reflection_angle) + if verbosity >= 4: + print(" Aligning {}".format(self.name)) + + if step <= 0: + # Prepare for alignment + + if RE.state != "idle": + RE.abort() + + if get_beamline().current_mode != "alignment": + # if verbosity>=2: + # print("WARNING: Beamline is not in alignment mode (mode is '{}')".format(get_beamline().current_mode)) + print("Switching to alignment mode (current mode is '{}')".format(get_beamline().current_mode)) + get_beamline().modeAlignment() + + get_beamline().setDirectBeamROI() + + beam.on() + + detector = pilatus2M + RE(pilatus2M.setExposureTime(0.5)) + self.thabs(reflection_angle) + RE(count([detector])) + + if ( + abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) < 20 + and detector.stats2.max_value.get() > intenisty_threshold + ): + # continue the fast alignment + print("The reflective beam is found! Continue the fast alignment") + + while abs(rel_th) > 0.005 and ct < 5: + # while detector.roi3.max_value.get() > 50 and ct < 5: + + # absolute beam position + refl_beam = detector.roi2.min_xyz.min_y.get() + detector.stats2.max_xy.y.get() + + # roi3 position + roi3_beam = detector.roi3.min_xyz.min_y.get() + detector.roi3.size.y.get() / 2 + + # distance from current postion to the center of roi2 (the disired rel beam position) + # rel_ypos = detector.stats2.max_xy.get().y - detector.stats2.size.get().y + rel_ypos = refl_beam - roi3_beam + + rel_th = rel_ypos / get_beamline().SAXS.distance / 1000 * 0.172 / np.pi * 180 / 2 + + print("The th offset is {}".format(rel_th)) + self.thr(rel_th) + + ct += 1 + RE(count([detector])) + + if detector.stats3.total.get() > 50: + print("The fast alignment works!") + self.thr(-reflection_angle) + self.setOrigin(["y", "th"]) + + beam.off() + + return True, ii + + else: + print("Alignment Error: Cannot Locate the reflection beam") + self.thr(-reflection_angle) + beam.off() + + return False, ii + + elif abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) > 5: + print("Max and Centroid dont Match!") + + # perform the full alignment + print("Alignment Error: No reflection beam is found!") + self.thr(-reflection_angle) + beam.off() + return False, ii + + else: + print("Intensiy < threshold!") + + # perform the full alignment + print("Alignment Error: No reflection beam is found!") + self.thr(-reflection_angle) + beam.off() + return False, ii + + def measureInitial(self, exposure_time=10, bounds=[0, 50]): + pos_list = np.meshgrid(bounds[0], bounds[1], 2) + # pos_list.append([np.average(bounds),np.average(bounds)]) + command["out_of_bound"] = False + + for x_pos, y_pos in pos_list: + start_time = time.time() + if verbosity >= 3: + print( + "{}Driving to point {}/{}; (x,yy) = ({:.3f}, {:.3f})".format( + prefix, imeasure, num_to_measure, x_pos, yy_pos + ) + ) + + self.xabs(x_pos) + # self.yabs(y_pos) + self.yyabs(yy_pos) + + while smx.moving == True or smy2.moving == True: + time.sleep(1) + while abs(self.xpos(verbosity=0) - x_pos) > 0.1 or abs(self.yypos(verbosity=0) - yy_pos) > 0.1: + time.sleep(1) + + self.measure(exposure_time=exposure_time, extra=extra, **md) + header = db[-1] # The most recent measurement + # command['filename'] = '{}'.format(header.start['filename'][:-1]) + command["filename"] = "{}".format(header.start["filename"]) + command["x_position"] = self.xpos(verbosity=0) + command["y_position"] = self.yypos(verbosity=0) + command["h1_position"] = self.xy2h(self.xpos(), self.yypos())[0] + command["h2_position"] = self.xy2h(self.xpos(), self.yypos())[1] + + cost_time = time.time() - start_time + + command["cost"] = cost_time + + command["h1_para"] = self.para1 + command["h2_para"] = self.para2 + + command["measured"] = True + command["analyzed"] = False + + measure_queue.publish(commands) # Send results for analysis + + def search_plan( + self, + motor=smy, + step_size=0.2, + min_step=0.05, + intensity=None, + target=0.5, + detector=None, + detector_suffix=None, + polarity=-1, + verbosity=3, + ): + """Moves this axis, searching for a target value. + + Parameters + ---------- + step_size : float + The initial step size when moving the axis + min_step : float + The final (minimum) step size to try + intensity : float + The expected full-beam intensity readout + target : 0.0 to 1.0 + The target ratio of full-beam intensity; 0.5 searches for half-max. + The target can also be 'max' to find a local maximum. + detector, detector_suffix + The beamline detector (and suffix, such as '_stats4_total') to trigger to measure intensity + polarity : +1 or -1 + Positive motion assumes, e.g. a step-height 'up' (as the axis goes more positive) + """ + print("HERE!!") + + if detector is None: + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + if detector_suffix is None: + # value_name = gs.TABLE_COLS[0] + value_name = get_beamline().TABLE_COLS[0] + else: + value_name = detector.name + detector_suffix + + print(f"detector={detector}") + + @bpp.stage_decorator([detector]) + @bpp.run_decorator(md={}) + def inner_search(): + nonlocal intensity, target, step_size + + if not get_beamline().beam.is_on(): + print("WARNING: Experimental shutter is not open.") + + if intensity is None: + intensity = RE.md["beam_intensity_expected"] + + # bec.disable_table() + + # Check current value + vv = yield from bps.trigger_and_read([detector, motor]) + value = vv[value_name]["value"] + # RE(count([detector])) + # value = detector.read()[value_name]['value'] + + if target == "max": + if verbosity >= 5: + print("Performing search on axis '{}' target is 'max'".format(self.name)) + + max_value = value + # max_position = self.get_position(verbosity=0) + + direction = +1 * polarity + + while step_size >= min_step: + if verbosity >= 4: + print(" move {} by {} × {}".format(self.name, direction, step_size)) + + # pos = yield from bps.rd(motor) + yield from bps.mvr(motor, direction * step_size) + # self.move_relative(move_amount=direction*step_size, verbosity=verbosity-2) + + prev_value = value + yield from bps.trigger_and_read([detector, motor]) + # RE(count([detector])) + + value = detector.read()[value_name]["value"] + # if verbosity>=3: + # print(" {} = {:.3f} {}; value : {}".format(self.name, self.get_position(verbosity=0), self.units, value)) + + if value > max_value: + max_value = value + # max_position = self.get_position(verbosity=0) + + if value > prev_value: + # Keep going in this direction... + pass + else: + # Switch directions! + direction *= -1 + step_size *= 0.5 + + elif target == "min": + if verbosity >= 5: + print("Performing search on axis '{}' target is 'min'".format(self.name)) + + direction = +1 * polarity + + while step_size >= min_step: + if verbosity >= 4: + print(" move {} by {} × {}".format(self.name, direction, step_size)) + + # pos = yield from bps.rd(motor) + yield from bps.mvr(motor, direction * step_size) + # self.move_relative(move_amount=direction*step_size, verbosity=verbosity-2) + + prev_value = value + yield from bps.trigger_and_read([detector, motor]) + # RE(count([detector])) + value = detector.read()[value_name]["value"] + if verbosity >= 3: + print( + " {} = {:.3f} {}; value : {}".format( + self.name, self.get_position(verbosity=0), self.units, value + ) + ) + + if value < prev_value: + # Keep going in this direction... + pass + else: + # Switch directions! + direction *= -1 + step_size *= 0.5 + + else: + target_rel = target + target = target_rel * intensity + + if verbosity >= 5: + print( + "Performing search on axis '{}' target {} × {} = {}".format( + self.name, target_rel, intensity, target + ) + ) + if verbosity >= 4: + print(" value : {} ({:.1f}%)".format(value, 100.0 * value / intensity)) + + # Determine initial motion direction + if value > target: + direction = -1 * polarity + else: + direction = +1 * polarity + + while step_size >= min_step: + if verbosity >= 4: + print(" move {} by {} × {}".format(self.name, direction, step_size)) + + # pos = yield from bps.rd(motor) + yield from bps.mvr(motor, direction * step_size) + # self.move_relative(move_amount=direction*step_size, verbosity=verbosity-2) + + yield from bps.trigger_and_read([detector, motor]) + # RE(count([detector])) + value = detector.read()[value_name]["value"] + # if verbosity>=3: + # print(" {} = {:.3f} {}; value : {} ({:.1f}%)".format(self.name, self.get_position(verbosity=0), self.units, value, 100.0*value/intensity)) + + # Determine direction + if value > target: + new_direction = -1.0 * polarity + else: + new_direction = +1.0 * polarity + + if abs(direction - new_direction) < 1e-4: + # Same direction as we've been going... + # ...keep moving this way + pass + else: + # Switch directions! + direction *= -1 + step_size *= 0.5 + + # bec.enable_table() + + yield from inner_search() + + def search_stub2( + self, + motor=smy, + step_size=1.0, + min_step=0.05, + intensity=None, + target=0.5, + detector=None, + detector_suffix=None, + polarity=1, + verbosity=3, + ): + if detector is None: + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + if detector_suffix is None: + # value_name = gs.TABLE_COLS[0] + value_name = get_beamline().TABLE_COLS[0] + else: + value_name = detector.name + detector_suffix + + if intensity is None: + intensity = RE.md["beam_intensity_expected"] + + motors_for_table = [smx, smy, sth] + + # Check current value + vv = yield from bps.trigger_and_read([detector, *motors_for_table]) + value = vv[value_name]["value"] + + if target == "max": + if verbosity >= 5: + print("Performing search on axis '{}' target is 'max'".format(self.name)) + + max_value = value + # max_position = self.get_position(verbosity=0) + + direction = polarity + + while step_size >= min_step: + if verbosity >= 4: + print(" move {} by {} × {}".format(self.name, direction, step_size)) + + yield from bps.mvr(motor, direction * step_size) + + prev_value = value + yield from bps.trigger_and_read([detector, *motors_for_table]) + + value = detector.read()[value_name]["value"] + # if verbosity>=3: + # print(" {} = {:.3f} {}; value : {}".format(self.name, self.get_position(verbosity=0), self.units, value)) + + if value > max_value: + max_value = value + # max_position = self.get_position(verbosity=0) + + if value > prev_value: + # Keep going in this direction... + pass + else: + # Switch directions! + direction *= -1 + step_size *= 0.5 + + elif target == "min": + if verbosity >= 5: + print("Performing search on axis '{}' target is 'min'".format(self.name)) + + direction = +1 * polarity + + while step_size >= min_step: + if verbosity >= 4: + print(" move {} by {} × {}".format(self.name, direction, step_size)) + + # pos = yield from bps.rd(motor) + yield from bps.mvr(motor, direction * step_size) + # self.move_relative(move_amount=direction*step_size, verbosity=verbosity-2) + + prev_value = value + yield from bps.trigger_and_read([detector, *motors_for_table]) + value = detector.read()[value_name]["value"] + if verbosity >= 3: + print( + " {} = {:.3f} {}; value : {}".format( + self.name, self.get_position(verbosity=0), self.units, value + ) + ) + + if value < prev_value: + # Keep going in this direction... + pass + else: + # Switch directions! + direction *= -1 + step_size *= 0.5 + + else: + target_rel = target + target = target_rel * intensity + + if verbosity >= 5: + print( + "Performing search on axis '{}' target {} × {} = {}".format( + self.name, target_rel, intensity, target + ) + ) + if verbosity >= 4: + print(" value : {} ({:.1f}%)".format(value, 100.0 * value / intensity)) + + # Determine initial motion direction + if value > target: + direction = -1 * polarity + else: + direction = +1 * polarity + + while step_size >= min_step: + if verbosity >= 4: + print(" move {} by {} × {}".format(self.name, direction, step_size)) + + yield from bps.mvr(motor, direction * step_size) + + yield from bps.trigger_and_read([detector, *motors_for_table]) + value = detector.read()[value_name]["value"] + # if verbosity>=3: + # print(" {} = {:.3f} {}; value : {} ({:.1f}%)".format(self.name, self.get_position(verbosity=0), self.units, value, 100.0*value/intensity)) + + # Determine direction + if value > target: + new_direction = -1.0 * polarity + else: + new_direction = +1.0 * polarity + + if abs(direction - new_direction) < 1e-4: + # Same direction as we've been going... + # ...keep moving this way + pass + else: + # Switch directions! + direction *= -1 + step_size *= 0.5 + + # bec.enable_table() + + # def calc_lookuptable(self,target_x): + # #make a look up table for + + # start_x = self.start_x + # start_y = self.start_y + # start_th = self.start_th + + # end_x = self.end_x + # end_y = self.end_y + # end_th = self.end_th + + # target_y = (target_x-end_x)/(start_x-end_x)*(start_y-end_y)+end_y + # target_th = (target_x-end_x)/(start_x-end_x)*(start_th-end_th)+end_th + + # return target_x, target_y, target_th + + def run_initial_alignment(self, start_x=127.2, end_x=127.2 + 30, direct_beam_int=None): + # make a look up table for + + yield from bps.mv(smx, 122.4) + yield from bps.mv(laserx, 0) + + # yield from bps.mv(smx, end_x) + yield from move_sample_with_laser(start_x) + yield from bps.mv(smy, 24.5) + yield from self.align_crazy_v3_plan(direct_beam_int=direct_beam_int) + # yield from self.align() + + start_x = smx.position + start_y = smy.position + start_th = sth.position + self.start_x = start_x + self.start_y = start_y + self.start_th = start_th + # start_x = self.start_x + # start_y = self.start_y + # start_th = self.start_th + + yield from move_sample_with_laser(end_x) + yield from bps.mv(smy, 24.6) + # yield from bps.mv(smx, start_x) + yield from self.align_crazy_v3_plan(direct_beam_int=direct_beam_int) + # yield from self.align() + + end_x = smx.position + end_y = smy.position + end_th = sth.position + + self.end_x = end_x + self.end_y = end_y + self.end_th = end_th + + # end_x = self.end_x + # end_y = self.end_y + # end_th = self.end_th + # return self.calc_lookuptable() + + def calc_lookuptable(self, target_x): + start_x = self.start_x + start_y = self.start_y + start_th = self.start_th + + end_x = self.end_x + end_y = self.end_y + end_th = self.end_th + + target_y = (target_x - end_x) / (start_x - end_x) * (start_y - end_y) + end_y + target_th = (target_x - end_x) / (start_x - end_x) * (start_th - end_th) + end_th + + return target_x, target_y, target_th + + def align_lookup(self, target_x, direct_beam_int=None): + xpos, ypos, thpos = self.calc_lookuptable(target_x) + + # move to the position in lookup table + yield from bps.mv(smx, xpos, smy, ypos, sth, thpos) + + yield from self.align_crazy_v3_plan(direct_beam_int=direct_beam_int) + + def search_plan2( + self, + motor=smy, + step_size=0.2, + min_step=0.05, + intensity=None, + target=0.5, + detector=None, + detector_suffix=None, + polarity=-1, + verbosity=3, + ): + """Moves this axis, searching for a target value. + + Parameters + ---------- + step_size : float + The initial step size when moving the axis + min_step : float + The final (minimum) step size to try + intensity : float + The expected full-beam intensity readout + target : 0.0 to 1.0 + The target ratio of full-beam intensity; 0.5 searches for half-max. + The target can also be 'max' to find a local maximum. + detector, detector_suffix + The beamline detector (and suffix, such as '_stats4_total') to trigger to measure intensity + polarity : +1 or -1 + Positive motion assumes, e.g. a step-height 'up' (as the axis goes more positive) + """ + + if detector is None: + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + + @bpp.stage_decorator([detector]) + @bpp.run_decorator(md={}) + @bpp.finalize_decorator(final_plan=shutter_off) + def inner_search(group=None): + nonlocal intensity, target, step_size + + if not get_beamline().beam.is_on(): + print("WARNING: Experimental shutter is not open.") + + if intensity is None: + intensity = RE.md["beam_intensity_expected"] + + if group: + yield from bps.wait(group) + + yield from shutter_on() + + yield from self.search_stub2( + motor=motor, + step_size=step_size, + min_step=min_step, + intensity=intensity, + target=target, + detector=detector, + detector_suffix=detector_suffix, + polarity=polarity, + verbosity=verbosity, + ) + + group_name = "setup_aligment" + yield from bps.abs_set(bsx, cms.bsx_pos + 3, group=group_name) + # beam.setTransmission(1e-6) + + yield from inner_search(group=group_name) + + yield from bps.abs_set(bsx, cms.bsx_pos, group=group_name) + yield from bps.wait(group_name) + + def measureAutonomous( + self, + runno=0, + exposure_time=10, + extra=None, + max_measurements=600000, + prefix="measureAutonomous > ", + verbosity=3, + **md, + ): + """Measure points in a loop, relying on an external queue to specify what + position to actually measure. If the 'position' is not (x,y) sample coordinates, + then you will have to add code to do the appropriate coordinate conversion, + or trigger the right beamline motors/components.""" + + for i in range(runno, max_measurements): + if verbosity >= 3: + print("{}Waiting for AE command on queue...".format(prefix)) + + # forceload_repeat = 0 + # if forceLoad == True: + # commands = measure_queue.get() + # forceload_repeat = 1 + # elif forceLoad == False or forceload_repeat == 1: + commands = measure_queue.get() # Get measurement command from queue + num_to_measure = sum([1.0 for command in commands if command["measured"] is False]) + + if verbosity >= 3: + # print('{}Received command to measure {} points'.format(num_to_measure)) + print("{}Received command to measure {} points".format(prefix, num_to_measure)) + + imeasure = 0 + for icommand, command in enumerate(commands): + if verbosity >= 5: + print("{}Considering point {}/{}".format(prefix, icommand, len(commands))) + + if not command["measured"]: + imeasure += 1 + if verbosity >= 3: + print("{}Measuring point {}/{}".format(prefix, imeasure, num_to_measure)) + + start_time = time.time() + + ######################################## + # Move to point + ######################################## + # Here you should define the beamline changes needed to go + # to the desired position. (You shouldn't in general need + # to change code outside of this block.) + ######################################## + + # convert x_pos, yy_pos of stage to x_position, y_position of sample + # yy_pos = -1*command['position']['x_position'] + # x_pos = command['position']['y_position'] + + # [x_pos, yy_pos] = command['position'] + Ti, Tm, Tf = command["position"] + # command['position_gpcam'] = command['position'] + + # align the sample + ss = input("Change the sample: (it has to be y or yes)") + while ss != "yes" and ss != "y": + ss = input("Change the sample: (it has to be y or yes)") + pta.laserOff() + smx.move(-20) + + ss = input("Is the sample ready? (it has to be y or yes)") + while ss != "yes" and ss != "y": + ss = input("Is the sample ready? (it has to be y or yes)") + + self.xo() + self.align() + cms.modeMeasurement() + self.xabs(0) + self.thabs(0.12) + + # offset the sample for high T + # self.yr(xxx) + # self.thabs(xxx) + + input("ready to go?") + # now use zmq to set PTA + # CustomQueue.push the message + BS.publish([Ti, Tm, Tf]) + # check it's working + # if verbosity>=3: + # print('{}Driving to point {}/{}; (x,yy) = ({:.3f}, {:.3f})'.format(prefix, imeasure, num_to_measure, x_pos, yy_pos)) + + self.name = ( + self.name_o + "_Ti{:.1f}".format(Ti) + "_Tm{:.1f}".format(Tm) + "_Tf{:.1f}".format(Tf) + ) + + # continuous measurement for 5 points + + wait_time_list = [5, 0, 0, 35, 85] + self.reset_clock() + # continuous measurement for 6 points + for ii in range(5): + self.xabs(ii * 0.2) + if ii >= 2: + self.crazy_th() + cms.modeMeasurement() + time.sleep(wait_time_list[ii]) + + self.measureIncidentAngle(0.12, exposure_time=exposure_time, **md) + + # wait until the T back to RT, move to the last fresh position + while self.clock() < 310: + time.sleep(5) + self.xabs(0.2 * 6) + self.crazy_th() + cms.modeMeasurement() + self.measureIncidentAngle(0.12, exposure_time=exposure_time, extra="FINAL", **md) + + header = db[-1] # The most recent measurement + # command['filename'] = '{}'.format(header.start['filename'][:-1]) + command["filename"] = "{}".format(header.start["filename"]) + + ######################################## + # md['anneal_time'] = self.anneal_time + # md['preanneal_time'] = self.preanneal_time + + cost_time = time.time() - start_time + + command["cost"] = cost_time + + command["measured"] = True + command["analyzed"] = False + + measure_queue.publish(commands) # Send results for analysis + + def measureAutonomous_3samples( + self, + runNo=0, + exposure_time=10, + extra=None, + max_measurements=600000, + samplePosNo=0, + prefix="measureAutonomous > ", + verbosity=3, + align=False, + **md, + ): + """Measure points in a loop, relying on an external queue to specify what + position to actually measure. If the 'position' is not (x,y) sample coordinates, + then you will have to add code to do the appropriate coordinate conversion, + or trigger the right beamline motors/components.""" + + samplePosNo_list = np.arange(0, 3) + samplePos = [123, 143.5, 163] + # samplePos = self.smxPos + # samplePosOffset = [pos1, pos2, pos3] + samplePosNo = samplePosNo + + for i in range(runNo, max_measurements): + if verbosity >= 3: + print("{}Waiting for AE command on queue...".format(prefix)) + + commands = measure_queue.get() # Get measurement command from queue + num_to_measure = sum([1.0 for command in commands if command["measured"] is False]) + + if verbosity >= 3: + # print('{}Received command to measure {} points'.format(num_to_measure)) + print("{}Received command to measure {} points".format(prefix, num_to_measure)) + + imeasure = 0 + for icommand, command in enumerate(commands): + if verbosity >= 5: + print("{}Considering point {}/{}".format(prefix, icommand, len(commands))) + + if not command["measured"]: + imeasure += 1 + if verbosity >= 3: + print("{}Measuring point {}/{}".format(prefix, imeasure, num_to_measure)) + + start_time = time.time() + + # [x_pos, yy_pos] = command['position'] + Ti, Tm, Tf = command["position"] + print("The next Temperatures are: Ti {:.1f}, Tm {:.1f}, Tf {:.1f}".format(Ti, Tm, Tf)) + # command['position_gpcam'] = command['position'] + self.name = ( + self.name_o + + "_Ti{:.1f}".format(Ti) + + "_Tm{:.1f}".format(Tm) + + "_Tf{:.1f}".format(Tf) + + "_run{}".format(i) + ) + + # align the sample + if samplePosNo == 0: + ss = input("Change the sample: (it has to be y or yes)") + while ss != "yes" and ss != "y": + ss = input("Change the sample: (it has to be y or yes)") + pta.laserOff() + smx.move(-20) + + ss = input("Are the samples ready? (it has to be y or yes)") + while ss != "yes" and ss != "y": + ss = input("Are the samples ready? (it has to be y or yes)") + print("Running Postion {}".format(samplePosNo)) + smx.move(samplePos[samplePosNo]) + sth.move(0) + self.setOrigin(["th"]) + + while smx.moving == True: + time.sleep(1) + beam.setSize(0.2, 0.05) + self.align() + beam.setSize(0.2, 0.2) + self.setOrigin(["x"]) + input("ready to go?") + # now use zmq to set PTA + # CustomQueue.push the message + BS.publish([Ti, Tm, Tf]) + # check it's working + + # continuous measurement for 5 points + + wait_time_list = [5, 0, 0, 50, 100] + + self.reset_clock() + for ii in range(5): + self.xabs(ii * 0.2) + if ii >= 2 and align: + self.crazy_th() + time.sleep(wait_time_list[ii]) + cms.modeMeasurement() + self.measureIncidentAngle(0.12, exposure_time=exposure_time) + + # wait until the T back to RT, move to the last fresh position + while self.clock() < 310: + time.sleep(5) + self.xabs(0.2 * 5) + if align: + self.crazy_th() + else: + beam.setSize(0.2, 0.05) + self.align() + beam.setSize(0.2, 0.2) + cms.modeMeasurement() + self.measureIncidentAngles( + [0.08, 0.1, 0.12, 0.15, 0.18, 0.2, 0.25], exposure_time=exposure_time, extra="FINAL" + ) + + header = db[-3] # The most recent measurement + # command['filename'] = '{}'.format(header.start['filename'][:-1]) + command["filename"] = "{}".format(header.start["filename"]) + + ######################################## + # md['anneal_time'] = self.anneal_time + # md['preanneal_time'] = self.preanneal_time + + cost_time = time.time() - start_time + + command["cost"] = cost_time + + command["measured"] = True + command["analyzed"] = False + + samplePosNo += 1 + if samplePosNo > 2: + samplePosNo = 0 + + measure_queue.publish(commands) # Send results for analysis + + def measureManual(self, Ti, Tm, Tf, step=0, exposure_time=10, align=False): + if step < 1: + ss = input("Sample pos number? ") + if ss == "0": + smx.move(self.smxPos[0]) + elif ss == "1": + smx.move(self.smxPos[1]) + elif ss == "2": + smx.move(self.smxPos[2]) + else: + print("Wrong Number. It has to be 0 or 1 or 2.") + return + + while smx.moving == True: + time.sleep(1) + + if step < 5: + self.setOrigin(["x"]) + self.gotoOrigin() + beam.setSize(0.2, 0.05) + self.align() + beam.setSize(0.2, 0.2) + + if step < 10: + ss = input("Ready for annealing? (it has to be y or yes)") + while ss != "yes" and ss != "y": + ss = input("Ready for annealing? (it has to be y or yes)") + + BS.publish([Ti, Tm, Tf]) + if align: + wait_time_list = [5, 0, 0, 35, 85] + else: + wait_time_list = [5, 0, 0, 50, 100] + self.reset_clock() + # continuous measurement for 6 points + for ii in range(5): + self.xabs(ii * 0.2) + if ii >= 2 and align: + self.crazy_th() + time.sleep(wait_time_list[ii]) + cms.modeMeasurement() + self.measureIncidentAngle(0.12, exposure_time=exposure_time) + + # wait until the T back to RT, move to the last fresh position + while self.clock() < 310: + time.sleep(5) + self.xabs(0.2 * 5) + if align: + self.crazy_th() + else: + beam.setSize(0.2, 0.05) + self.align() + beam.setSize(0.2, 0.2) + cms.modeMeasurement() + self.measureIncidentAngles( + [0.08, 0.1, 0.12, 0.15, 0.18, 0.2, 0.25], exposure_time=exposure_time, extra="FINAL" + ) + + def alignment_set(self): + self.start_x = 0 + self.end_x = 22 + self.start_y = 39.2196 + self.end_y = 40.037 + self.start_th = 1.2 + self.end_th = 1.198 + cms.direct_beam_int = 22245 + yield from bps.null() + + +# sam=Sample(name) + + +def change_long_sample(): + smx.move(0) + + +# mov smx 122.4 +# mov laserx 0 + +# RE(move_sample_with_laser(127.2-0.6)) +# sam.setOrigin(['x']) +# xo=127.2-0.6 +# RE(sam.run_initial_alignment(xo, xo+30)) +# noAgent_scan + + +# noAgent_scan(xpos=np.linspace(xo, xo+25, 61), align=False, laserOn=False) + + +def align_long_sample(xo=127.1): + # RE(move_sample_with_laser(127.1+15)) + smx.move(xo + 15) + RE(cms.modeAlignment()) + sam.align() + + +def measure_long_sample(step=0, xo=127.1): + cms.modeMeasurement() + + if step < 5: + detselect([pilatus2M, pilatus8002]) + sam.thabs(0.25) + + for xpos in np.linspace(0, 25, 61): + smx.move(xo + xpos) + while smx.moving == True: + time.sleep(1) + # RE(move_sample_with_laser(127.1+xpos)) + + RE(sam.measure(5)) + + # if step < 15: + # detselect([pilatus8002]) + # sam.thabs(.5) + + # for xpos in np.linspace(0, 25, 61): + # smx.move(xo+xpos) + # while smx.moving==True: + # time.sleep(1) + # # RE(move_sample_with_laser(127.1+xpos)) + # RE(sam.measure(5)) + + +# cms.SAXS.setCalibration([758, 1680-607], 5.0, [-65, -73]) # 13.5 keV +# cms.SAXS.setCalibration([754, 1076], 5.03, [-65, -73]) #20190320, 13.5 keV +# cms.SAXS.setCalibration([754, 1075], 5.03, [-65, -73]) #20201021, 13.5 keV +# cms.SAXS.setCalibration([754, 1077], 5.03, [-65, -73]) #20210208, 13.5 keV +# cms.SAXS.setCalibration([761, 1075], 5.03, [-65, -73]) #20210716, 13.5 keV +# cms.SAXS.setCalibration([756, 1079], 5.83, [-65, -73]) # 20201021, 13.5 keV +cms.SAXS.setCalibration([738, 1100], 3.83, [-65, -73]) + + +# RE.md['experiment_group'] = 'MNoack' +RE.md["experiment_group"] = "K. Chen-Wiegart" +# RE.md['experiment_alias_directory'] = '/nsls2/xf11bm/data/2020_3/MNoack/Exp1/' +RE.md["experiment_alias_directory"] = "/nsls2/data/cms/legacy/xf11bm/data/2023_2/KChen-Wiegart2" +RE.md["experiment_user"] = "TBD" +RE.md["experiment_type"] = "GIAXS" +RE.md["experiment_project"] = "TBD" + + +def fake_coordinated_motion(mtr1, target1, mtr2, target2, N=1000): + start1 = yield from bps.rd(mtr1) + start2 = yield from bps.rd(mtr2) + step1 = (target1 - start1) / N + step2 = (target2 - start2) / N + for j in range(int(N)): + yield from bps.mv(mtr1, start1 + j * step1, mtr2, start2 + j * step2) + + +def parallel_fake_coordinated_motion(mtr1, target1, mtr2, target2): + ... + + +def fake_coordinated_motionr(mtr1, mtr2, delta, step=0.1): + real_step = step * abs(delta) / delta + + for j in range(int(abs(delta) / step)): + yield from bps.mvr(mtr1, real_step, mtr2, real_step) + + +def changeSample(): + # smx.move(-20) + yield from move_sample_with_laser(124.2) + yield from bps.mv(smx, 0) + + +def newSample(): + # smx.move(-20) + yield from bps.mv(smx, 124.2) + yield from bps.mv(laserx, -1.4) + + +def alignNewSample(): + yield from cms.modeAlignment() + # pos1 + # yield from bps.mv(smx, 28.67) + yield from move_sample_with_laser(124.2 + 5) + yield from sam.align() + sam.start_x = smx.position + sam.start_y = smy.position + sam.start_th = sth.position + # pos2 + # yield from bps.mv(smx, 28.67+33) + yield from move_sample_with_laser(124.2 + 30) + yield from sam.align() + sam.end_x = smx.position + sam.end_y = smy.position + sam.end_th = sth.position + + +# the strips in the same materials system should have the same file name +# the location with l_pos=0, o_pos=0 for the first strip should be mared as 0 +# the location with l_pos=0, o_pos=i for the second sample needs to be aligned in the sequence of the first strip. + + +# # Connect to ZeroMQ (zmq) +# try: +# BS +# except NameError: +# ##queue_PATH='../' +# queue_PATH='/nsls2/data/cms/legacy/xf11bm/data/2022_2/SRussell/' +# queue_PATH in sys.path or sys.path.append(queue_PATH) +# from CustomQueuePTA import BSQueue +# BS = BSQueue() + +# ## Connect to S3 +# try: +# measure_queue +# except NameError: +# ##queue_PATH='../' +# queue_PATH='/nsls2/data/cms/legacy/xf11bm/data/2022_2/SRussell/' +# queue_PATH in sys.path or sys.path.append(queue_PATH) +# from CustomS3 import Queue_measure +# measure_queue = Queue_measure() + +""" +The edge of the diving board in x + +In [237]: wsam() +smx = 81.2 +smy = 16.13191875 +sth = 1.120000000000001 + +the other edge of x (clamping spot) + +smx = 106.1 + +============ +align bare Si wafer at smx=106 + +In [298]: wsam() +smx = 106.0 +smy = 16.19016875 +sth = 0.995000000000001 + +align bare Si wafer at smx=81.1 + +In [298]: wsam() + +In [365]: wsam() +smx = 93.55 +smy = 15.7754375 +sth = 0.9976562500000004 + +1.89deg offset in schi + + +============ +y scan at the aligned position to verify the stats2/stat4. ++-----------+------------+------------+-------------------+------------------------+------------------------+------------------------+------------------------+ +| seq_num | time | smy | smy_user_setpoint | pilatus2M_stats1_total | pilatus2M_stats2_total | pilatus2M_stats3_total | pilatus2M_stats4_total | ++-----------+------------+------------+-------------------+------------------------+------------------------+------------------------+------------------------+ +| 1 | 12:02:13.5 | 15.5819 | 15.5819 | 1 | -89 | 0 | 20095 | +| 2 | 12:02:15.4 | 15.6019 | 15.6019 | 1 | -90 | 0 | 20221 | +| 3 | 12:02:17.3 | 15.6219 | 15.6219 | 0 | -90 | 0 | 20026 | +| 4 | 12:02:19.1 | 15.6419 | 15.6419 | 0 | -90 | 0 | 20337 | +| 5 | 12:02:21.1 | 15.6619 | 15.6619 | 1 | -90 | 0 | 20427 | +| 6 | 12:02:22.9 | 15.6819 | 15.6819 | 2 | -87 | 0 | 20053 | +| 7 | 12:02:24.7 | 15.7019 | 15.7019 | 2 | -84 | 3 | 20383 | +| 8 | 12:02:26.5 | 15.7219 | 15.7219 | 19 | -51 | 3 | 20052 | +| 9 | 12:02:28.4 | 15.7419 | 15.7419 | 186 | 328 | 75 | 19790 | +| 10 | 12:02:30.4 | 15.7619 | 15.7619 | 1450 | 3553 | 718 | 16054 | +| 11 | 12:02:32.3 | 15.7819 | 15.7819 | 3974 | 8884 | 2697 | 7412 | +| 12 | 12:02:34.2 | 15.8019 | 15.8019 | 2783 | 5922 | 1889 | 1563 | +| 13 | 12:02:36.1 | 15.8219 | 15.8219 | 705 | 1368 | 558 | 114 | +| 14 | 12:02:38.0 | 15.8419 | 15.8419 | 65 | 39 | 61 | 2 | +| 15 | 12:02:39.9 | 15.8619 | 15.8619 | 15 | -66 | 10 | 0 | +| 16 | 12:02:41.8 | 15.8819 | 15.8819 | 7 | -70 | 0 | 0 | +| 17 | 12:02:43.5 | 15.9019 | 15.9019 | 0 | -89 | 0 | 0 | +| 18 | 12:02:45.5 | 15.9219 | 15.9219 | 0 | -90 | 0 | 0 | +| 19 | 12:02:47.4 | 15.9419 | 15.9419 | 0 | -90 | 0 | 0 | +| 20 | 12:02:49.4 | 15.9619 | 15.9619 | 0 | -90 | 0 | 0 | +| 21 | 12:02:51.3 | 15.9819 | 15.9819 | 0 | -90 | 0 | 0 | + + + ++-----------+------------+------------+-------------------+------------------------+------------------------+------------------------+------------------------+ + + +laser power <24 + +0, 6, 12, 18, 24 + +heater @50C @100C. + + +#laser @ the edge of Si wafer +In [850]: wsam() +smx = 86.2495 +smy = 15.778553125 +sth = 1.0212500000000002 + +#2mm offset from laser @ the edge +In [854]: wsam() +smx = 88.2495 +smy = 15.778553125 +sth = 1.0212500000000002 +In [856]: laserx.position +Out[856]: 0.0 + +FIX the offfset between smx and laserx as 88.25 + + +#alignment scan @50C + + +# smy.mov(15.5) +RE(fake_coordinated_motion(smx, 82, laserx, -6.25, N=120)) +#set power +for power in np.arange(0, 24.1, 6): + + pta.setLaserPower(power) + #set x position + if power==0: + pta.laserOff() + else: + pta.laserOn() + time.sleep(30) + # for xpos in np.arrange(0, 24.1, 6): + for xpos in range(5): + smy.move(15.5) + sam.align() + if xpos<4: + RE(fake_coordinated_motionr(smx, laserx, delta=6)) + + pta.laserOff() + + RE(fake_coordinated_motion(smx, 82, laserx, -6.25, N=120)) + + +pta.setLaserPower(power) + + +""" + + +# camonitor -S XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire + +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:18:45.322852 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:18:45.406499 Done +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:18:45.332771 23333 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:18:45.332854 10 +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:18:45.562211 Done +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:10.780798 0 +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:11.563899 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:11.563945 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:11.563973 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:11.632702 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:11.937539 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:11.953721 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:11.953786 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:11.963590 23334 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:11.963779 1 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:12.055200 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:12.278970 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:12.279087 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:12.279116 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:12.347917 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:12.653034 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:12.666444 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:12.666491 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:12.674896 23335 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:12.674989 2 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:12.806157 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:12.929527 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:12.929575 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:12.929593 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:12.998175 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:13.301574 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:13.316497 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:13.316522 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:13.325644 23336 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:13.325764 3 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:13.452583 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:13.567623 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:13.567675 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:13.567699 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:13.636079 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:14.153505 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:14.168763 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:14.168805 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:14.178550 23337 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:14.178706 4 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:14.252755 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:14.380508 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:14.380533 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:14.380543 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:14.449284 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:14.756593 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:14.772070 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:14.772109 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:14.781253 23338 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:14.781299 5 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:14.859708 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:14.982903 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:14.982950 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:14.982985 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:15.051642 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:15.661136 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:15.676297 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:15.676319 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:15.685042 23339 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:15.685210 6 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:15.816051 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:15.932728 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:15.932767 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:15.932785 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:16.001699 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:16.305201 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:16.319495 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:16.319542 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:16.329081 23340 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:16.329159 7 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:16.408806 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:16.533301 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:16.533346 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:16.533364 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:16.602075 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:17.143514 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:17.157371 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:17.157411 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:17.167105 23341 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:17.167203 8 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:17.245183 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:17.369047 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:17.369103 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:17.369129 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:17.437877 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:17.743062 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:17.756966 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:17.757005 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:17.766715 23342 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:17.766777 9 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:17.919766 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:18.042324 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:18.042377 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:18.042401 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:18.111180 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:18.673632 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:18.688266 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:18.688318 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:18.697376 23343 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:18.697448 10 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:18.825073 Done + + +def test_plan(detector=None): + if detector is None: + detector = pilatus2M + # detector = get_beamline().detector[0] + + motors_for_table = [smx, smy, sth] + + @bpp.stage_decorator([detector]) + @bpp.run_decorator(md={}) + @bpp.finalize_decorator(final_plan=shutter_off) + def inner_plan(group=None): + if group: + yield from bps.wait(group) + + for n in range(10): + t0 = time.time() + # yield from bps.trigger_and_read([detector, *motors_for_table]) + yield from bps.trigger_and_read([detector]) + print(f"Detection time: {time.time() - t0}") + # yield from bps.sleep(.1) + + group_name = "setup_aligment" + yield from bps.abs_set(bsx, cms.bsx_pos + 3, group=group_name) + beam.setTransmission(1e-6) + + yield from inner_plan(group=group_name) + + yield from bps.abs_set(bsx, cms.bsx_pos, group=group_name) + yield from bps.wait(group_name) + + +sample_pta = Sample("test") + +""" +Notes at Mar 22, 2023, the 4th day at CMS + +#quick alignment for Si wafer + +#check the beam position in USB cam1 +# + +#the start edge +In [165]: wsam() +smx = 0.0 +smy = 39.23188125 +sth = 1.086875000000001 + +In [166]: sam.pos() +test.th = 0.157 deg (origin = 0.930) +test.x = 0.000 mm (origin = 0.000) +test.y = -0.028 mm (origin = 39.260) +Out[166]: {'th': 0.15687500000000087, 'x': 0.0, 'y': -0.028118749999997306} + + +#the end edge + +In [173]: wsam() +smx = 22.0005 +smy = 40.072500000000005 +sth = 1.0865624999999994 + +In [174]: sam.pos() +test.th = 0.157 deg (origin = 0.930) +test.x = 22.000 mm (origin = 0.000) +test.y = 0.813 mm (origin = 39.260) + +""" + + +""" +Notes March 22, 2023 +17:18 KY loaded "real scientific sample +name='GD4-113-4-2nd_Tb50C' + +laserPower = 1.4V (4.6w) + +smx = 3.7 ; laserx = 11.5 # IR laser is hitting edge of sample +smx = 8.7 ; laserx = 11.5 # IR laser is hitting edge of sample + + +Notes March 23, 2023 +10:40 KY loaded "real scientific sample 2 +name='GD4-113-1_Tb50C' +laserPower = 1.1V (2.3w) + +there is unexpected ~10s delay on every point during alignment. the bug is gone after restart. + +10:40 KY loaded "real scientific sample 3 +name='GD4-113-1-2nd_Tb50C' +laserPower = 1.1V (2.3w) + +In [7]: sam.start_x +Out[7]: 0.0 + +In [8]: sam.start_y +Out[8]: 39.218578125 + +In [9]: sam.start_th +Out[9]: 1.2006250000000005 + +In [10]: sam.end_x +Out[10]: 22.0005 + +In [11]: sam.end_y +Out[11]: 40.037328125 + +In [12]: sam.end_th +Out[12]: 1.1979687500000011 + + +#####protocol +=============bsui================== +#change sample --mov smx -100 and mount the fresh sample +RE(sam.run_initial_alignment(start_x=0, end_x=22)) #align samples at smx=0 and 22 and calculate the lookup table for smy and th +#print out sam.start_x/y/th and smx.end_x/y/th and HARD code them in sam.alignment_set() +=============bsui part is done. exit bsui============================= +#restart the env in Queue monitor +#pre-load 'agent_alignemnt_set' and 'agent_laser_on' +==>>ws2, agent.start(True) +==>>ws1, start the queue +""" + +# def fake_fly(mtr, start, stop, exp_time): +# det = pilatus2M + +# det.tiff.kind = 'omitted' +# det.tiff.disable_on_stage() +# det.stats4.total.kind='hinted' + + +# @bpp.stage_decorator([det]) +# @bpp.monitor_during_decorator([det.stats4.total, mtr]) +# @bpp.run_decorator() +# @bpp.finalize_decorator(final_plan=shutter_off) +# def inner(): +# yield from shutter_on() + +# yield from bps.trigger(det, group='fake_fly') +# yield from bps.abs_set(mtr, stop, group='fake_fly') +# yield from bps.wait(group='fake_fly') + +# @bpp.reset_positions_decorator([det.cam.num_images, det.cam.acquire_time, det.cam.acquire_period]) +# def inner2(): +# yield from bps.mv(det.cam.acquire_time, exp_time) +# yield from bps.mv(det.cam.acquire_period, exp_time +.05) +# total_time = np.abs(stop - start) + +# yield from bps.mv(det.cam.num_images, num) +# yield from bps.mv(mtr, start) +# yield from inner() + +# group_name = "setup_aligment" +# yield from bps.abs_set(bsx, cms.bsx_pos + 3, group=group_name) +# yield from bps.wait(group=group_name) + +# beam.setTransmission(1e-6) + +# yield from inner2() + +# yield from bps.abs_set(bsx, cms.bsx_pos, group=group_name) +# yield from bps.wait(group_name) + + +# def fake_fly2_test(mtr, start, stop, step, exp_time): + +# # motors: smy (+/- 2), sth (+/- 1) +# det = pilatus2M + +# # It takes 0.4 to 0.7 s longer to complete motion, so let's add 1 s for now +# # It should be computed/estimated more accurately +# num = int(np.abs(stop - start) / step) +# total_time = num * exp_time +# velocity = np.abs(stop - start) / total_time + +# det.tiff.kind = 'omitted' +# det.tiff.disable_on_stage() +# det.stats4.total.kind='hinted' + +# frame_numbers = [] +# frame_timestamps = [] +# frame_mtr_pos = [] +# frame_roi2_int = [] +# frame_roi3_int = [] +# frame_roi4_int = [] + +# def accumulate(value, old_value, timestamp, **kwargs): +# frame_numbers.append(value) +# frame_timestamps.append(timestamp) +# frame_mtr_pos.append(mtr.position) + +# def accumulate_roi2(value, old_value, timestamp, **kwargs): +# roi2_int = pilatus2M.stats2.total.get() +# frame_roi2_int.append(roi2_int) + +# def accumulate_roi3(value, old_value, timestamp, **kwargs): +# roi3_int = pilatus2M.stats3.total.get() +# frame_roi3_int.append(roi3_int) + +# def accumulate_roi4(value, old_value, timestamp, **kwargs): +# roi4_int = pilatus2M.stats4.total.get() +# frame_roi4_int.append(roi4_int) + +# @bpp.stage_decorator([det]) +# def inner(): +# cid = pilatus2M.cam.array_counter.subscribe(accumulate) +# cid2 = pilatus2M.stats2.array_counter.subscribe(accumulate_roi2) +# cid3 = pilatus2M.stats3.array_counter.subscribe(accumulate_roi3) +# cid4 = pilatus2M.stats4.array_counter.subscribe(accumulate_roi4) +# try: +# yield from bps.trigger(det, group='fake_fly') +# yield from bps.abs_set(mtr, stop, group='fake_fly') +# yield from bps.wait(group='fake_fly') +# finally: +# pilatus2M.cam.array_counter.unsubscribe(cid) +# pilatus2M.stats2.array_counter.unsubscribe(cid2) +# pilatus2M.stats3.array_counter.unsubscribe(cid3) +# pilatus2M.stats4.array_counter.unsubscribe(cid4) + +# @bpp.reset_positions_decorator([det.cam.num_images, det.cam.acquire_time, det.cam.acquire_period, +# mtr.velocity]) +# def inner2(): +# yield from bps.abs_set(mtr, start, wait=True) +# yield from bps.mv(mtr.velocity, velocity) + +# print(f"Number of acquired images: {num}. Exposure time: {exp_time}") + +# yield from bps.mv(det.cam.acquire_time, exp_time - 0.005) +# yield from bps.mv(det.cam.acquire_period, exp_time) + +# yield from bps.mv(det.cam.num_images, num) +# yield from inner() + +# yield from inner2() + +# def trim_list(v, num): +# n_first = max(len(v) - num, 0) +# return v[n_first:] + +# frame_numbers = trim_list(frame_numbers, num) +# frame_timestamps = trim_list(frame_timestamps, num) +# frame_mtr_pos = trim_list(frame_mtr_pos, num) +# frame_roi2_int = trim_list(frame_roi2_int, num) +# frame_roi3_int = trim_list(frame_roi3_int, num) +# frame_roi4_int = trim_list(frame_roi4_int, num) + +# print(f"frame_numbers = {frame_numbers}") +# print(f"frame_timestamps = {frame_timestamps}") +# print(f"mtr_pos = {frame_mtr_pos}") +# print(f"roi2 = {frame_roi2_int}") +# print(f"roi3 = {frame_roi3_int}") +# print(f"roi4 = {frame_roi4_int}") + +# return frame_mtr_pos, frame_roi2_int, frame_roi3_int, frame_roi4_int + + +def fake_fly3(det, mtr, start, stop, step, exp_time): + # motors: smy (+/- 2), sth (+/- 1) + # det = pilatus2M + + # It takes 0.4 to 0.7 s longer to complete motion, so let's add 1 s for now + # It should be computed/estimated more accurately + num = int(np.abs(stop - start) / step) + total_time = num * exp_time + velocity = np.abs(stop - start) / total_time + + det.tiff.kind = "omitted" + det.tiff.disable_on_stage() + det.stats4.total.kind = "hinted" + + frame_numbers = [] + frame_timestamps = [] + frame_mtr_pos = [] + frame_roi2_ts = [] + frame_roi3_ts = [] + frame_roi4_ts = [] + + frame_roi2_total_ts = [] + frame_roi3_total_ts = [] + frame_roi4_total_ts = [] + frame_roi2_total = [] + frame_roi3_total = [] + frame_roi4_total = [] + + def accumulate(value, old_value, timestamp, **kwargs): + frame_numbers.append(value) + frame_timestamps.append(timestamp) + frame_mtr_pos.append(mtr.position) + + def accumulate_roi2(value, old_value, timestamp, **kwargs): + frame_roi2_ts.append(timestamp) + + def accumulate_roi3(value, old_value, timestamp, **kwargs): + frame_roi3_ts.append(timestamp) + + def accumulate_roi4(value, old_value, timestamp, **kwargs): + frame_roi4_ts.append(timestamp) + + def accumulate_roi2_total(value, old_value, timestamp, **kwargs): + frame_roi2_total_ts.append(timestamp) + frame_roi2_total.append(value) + + def accumulate_roi3_total(value, old_value, timestamp, **kwargs): + frame_roi3_total_ts.append(timestamp) + frame_roi3_total.append(value) + + def accumulate_roi4_total(value, old_value, timestamp, **kwargs): + frame_roi4_total_ts.append(timestamp) + frame_roi4_total.append(value) + + def inner(): + cid = pilatus2M.cam.array_counter.subscribe(accumulate) + cid2 = pilatus2M.stats2.array_counter.subscribe(accumulate_roi2) + cid3 = pilatus2M.stats3.array_counter.subscribe(accumulate_roi3) + cid4 = pilatus2M.stats4.array_counter.subscribe(accumulate_roi4) + cid2a = pilatus2M.stats2.total.subscribe(accumulate_roi2_total) + cid3a = pilatus2M.stats3.total.subscribe(accumulate_roi3_total) + cid4a = pilatus2M.stats4.total.subscribe(accumulate_roi4_total) + try: + yield from bps.trigger(det, group="fake_fly") + yield from bps.abs_set(mtr, stop, group="fake_fly") + yield from bps.wait(group="fake_fly") + finally: + pilatus2M.cam.array_counter.unsubscribe(cid) + pilatus2M.stats2.array_counter.unsubscribe(cid2) + pilatus2M.stats3.array_counter.unsubscribe(cid3) + pilatus2M.stats4.array_counter.unsubscribe(cid4) + pilatus2M.stats2.total.unsubscribe(cid2a) + pilatus2M.stats3.total.unsubscribe(cid3a) + pilatus2M.stats4.total.unsubscribe(cid4a) + + @bpp.reset_positions_decorator( + [det.cam.num_images, det.cam.acquire_time, det.cam.acquire_period, mtr.velocity] + ) + def inner2(): + print(f"setting motor start position") + yield from bps.abs_set(mtr, start, wait=True) + print(f"setting motor start velocity: {velocity}") + yield from bps.mv(mtr.velocity, velocity) + + print(f"Number of acquired images: {num}. Exposure time: {exp_time}") + + yield from bps.mv(det.cam.acquire_time, exp_time - 0.005) + yield from bps.mv(det.cam.acquire_period, exp_time) + + yield from bps.mv(det.cam.num_images, num) + yield from inner() + + yield from inner2() + + def trim_list(v, num): + n_first = max(len(v) - num, 0) + return v[n_first:] + + def set_total_values(frame_roi_ts, total_ts, total, dt=0.25 * exp_time): + total_ts = [_ - dt for _ in total_ts] + vals = [0] * len(frame_roi_ts) + n_current, v_current = 0, 0 + for n in range(len(vals)): + if n_current < len(total_ts) and total_ts[n_current] < frame_roi_ts[n]: + v_current = total[n_current] + n_current += 1 + vals[n] = v_current + return vals + + # 0-th frame is discarded during trimming + _ = frame_mtr_pos + frame_mtr_pos = [_[0]] + [(_[n] + _[n - 1]) / 2 for n in range(1, len(_))] + + total_roi2 = set_total_values(frame_roi2_ts, frame_roi2_total_ts, frame_roi2_total) + total_roi3 = set_total_values(frame_roi3_ts, frame_roi3_total_ts, frame_roi3_total) + total_roi4 = set_total_values(frame_roi4_ts, frame_roi4_total_ts, frame_roi4_total) + + num = num - 1 # Discard the 1st point + + frame_numbers = trim_list(frame_numbers, num) + frame_timestamps = trim_list(frame_timestamps, num) + frame_mtr_pos = trim_list(frame_mtr_pos, num) + frame_roi2_ts = trim_list(frame_roi2_ts, num) + frame_roi3_ts = trim_list(frame_roi3_ts, num) + frame_roi4_ts = trim_list(frame_roi4_ts, num) + total_roi2 = trim_list(total_roi2, num) + total_roi3 = trim_list(total_roi3, num) + total_roi4 = trim_list(total_roi4, num) + + print("**********************************************************************") + + # print(f"frame_numbers = {frame_numbers}") + # print(f"frame_timestamps = {frame_timestamps}") + # print(f"mtr_pos = {frame_mtr_pos}") + + # print(f"roi2_ts = {frame_roi2_ts}") + # print(f"roi3_ts = {frame_roi3_ts}") + # print(f"roi4_ts = {frame_roi4_ts}") + + # print(f"frame_roi2_total_ts = {frame_roi2_total_ts}") + # print(f"frame_roi3_total_ts = {frame_roi3_total_ts}") + # print(f"frame_roi4_total_ts = {frame_roi4_total_ts}") + + # print(f"frame_roi2_total = {frame_roi2_total}") + # print(f"frame_roi3_total = {frame_roi3_total}") + # print(f"frame_roi4_total = {frame_roi4_total}") + # print("\n") + + # print(f"total_roi2 = {total_roi2}") + # print(f"total_roi3 = {total_roi3}") + # print(f"total_roi4 = {total_roi4}") + + print(f"POSITION, TOTAL_ROI2, TOTAL_ROI3, TOTAL_ROI4") + for n, pos in enumerate(frame_mtr_pos): + print(f"{pos:11.5f} {total_roi2[n]:11.1f} {total_roi3[n]:11.1f} {total_roi4[n]:11.1f}") + print("**********************************************************************") + + return frame_mtr_pos, total_roi2, total_roi3, total_roi4 + + +# from matplotlib import pyplot as plt +# fig_fast_scan, fig_fast_scan_ax1, fig_fast_scan_ax2 = None, None, None + +# def create_fig_fast_scan(): +# global fig_fast_scan, fig_fast_scan_ax1, fig_fast_scan_ax2 +# if not fig_fast_scan: +# fig_fast_scan = plt.figure() +# fig_fast_scan_ax1 = fig_fast_scan.add_subplot(2,1,1) +# fig_fast_scan_ax2 = fig_fast_scan.add_subplot(2,1,2) +# else: +# fig_fast_scan_ax1.clear() +# fig_fast_scan_ax2.clear() + + +def align_motor_y(det, mtr, start_rel, stop_rel, step, exp_time, mtr_max_velocity=0.08): + mtr_current = mtr.position + start, stop = mtr_current + start_rel, mtr_current + stop_rel + + max_step = exp_time * mtr_max_velocity + step = min(step, max_step) + print(f"Y-scan step: {step}") + # exp_time_min = step / mtr_max_velocity + # exp_time = max(exp_time, exp_time_min) + # print(f"Y-scan exposure time: {exp_time}") + + @bpp.finalize_decorator(final_plan=shutter_off) + def inner(): + yield from shutter_on() + pos, roi2, roi3, roi4 = yield from fake_fly3(det, mtr, start, stop, step, exp_time) + + # max_roi4 = max(roi4) + # n_half = 0 + # for n in range(len(roi4)): + # if roi4[n] < max_roi4 / 2: + # n_half = n print(f"Center: {cen}") + + # break + + # yield from bps.abs_set(mtr, pos[n_half], wait=True) + + cen_return = None + try: + cen, _, _ = do_fitting(pos, roi4, model_type="step") + cen_return = cen + print(f"Center: {cen}") + except Exception as ex: + cen = mtr_current + print(f"ERROR: Failed to find the edge: {ex}") + + yield from bps.abs_set(mtr, cen, wait=True) + + yield from bps.mv(det.cam.num_images, 1) + yield from bps.trigger(det, group="fake_fly") + yield from bps.wait(group="fake_fly") + return cen_return + + return (yield from inner()) + + +def align_motor_y2(det, mtr, start_rel, stop_rel, step, exp_time, mtr_max_velocity=0.08): + mtr_current = mtr.position + start, stop = mtr_current + start_rel, mtr_current + stop_rel + + max_step = exp_time * mtr_max_velocity + step = min(step, max_step) + print(f"Y-scan step: {step}") + # exp_time_min = step / mtr_max_velocity + # exp_time = max(exp_time, exp_time_min) + # print(f"Y-scan exposure time: {exp_time}") + + @bpp.finalize_decorator(final_plan=shutter_off) + def inner(): + yield from shutter_on() + pos, roi2, roi3, roi4 = yield from fake_fly3(det, mtr, start, stop, step, exp_time) + + # max_roi4 = max(roi4) + # n_half = 0 + # for n in range(len(roi4)): + # if roi4[n] < max_roi4 / 2: + # n_half = n print(f"Center: {cen}") + + # break + + # yield from bps.abs_set(mtr, pos[n_half], wait=True) + + cen_return = None + try: + cen, _, _ = do_fitting(pos, roi2, model_type="peak") + cen_return = cen + print(f"Center: {cen}") + except Exception as ex: + cen = mtr_current + print(f"ERROR: Failed to find the edge: {ex}") + + yield from bps.abs_set(mtr, cen, wait=True) + + yield from bps.mv(det.cam.num_images, 1) + yield from bps.trigger(det, group="fake_fly") + yield from bps.wait(group="fake_fly") + return cen_return + + return (yield from inner()) + + +def align_motor_th( + det, mtr, start_rel, stop_rel, step, exp_time, fine_scan=True, mtr_backlash=0.1, mtr_max_velocity=0.1 +): + mtr_current = mtr.position + start, stop = mtr_current + start_rel, mtr_current + stop_rel + + max_step = exp_time * mtr_max_velocity + step = min(step, max_step) + print(f"TH-scan step: {step}") + # exp_time_min = step / mtr_max_velocity + # exp_time = max(exp_time, exp_time_min) + # print(f"TH-scan exposure time: {exp_time}") + + @bpp.finalize_decorator(final_plan=shutter_off) + def inner(): + yield from shutter_on() + pos, roi2, roi3, roi4 = yield from fake_fly3(det, mtr, start, stop, step, exp_time) + + # if fine_scan: + # n_max = np.argmax(roi3) + # else: + # n_max = np.argmax(roi2) + + # yield from bps.abs_set(mtr, pos[n_max], wait=True) + + roi = roi3 if fine_scan else roi2 + # roi = roi3 if fine_scan else roi4 + + cen, _, _ = do_fitting(pos, roi, model_type="peak") + print(f"Center: {cen}") + backlash = mtr_backlash if stop_rel > start_rel else -mtr_backlash + yield from bps.abs_set(mtr, cen - backlash, wait=True) + yield from bps.abs_set(mtr, cen, wait=True) + + yield from bps.mv(det.cam.num_images, 1) + yield from bps.trigger(det, group="fake_fly") + yield from bps.wait(group="fake_fly") + return cen - 0.12 + + return (yield from inner()) + + +import time + + +def align_stub(det, exp_time=0.3): + # mtr_backlash=0 + mtr_backlash = 0.1 # Use for PTA stages + + ceny, centh = 0, 0 + + # create_fig_fast_scan() + + tstart = time.time() + + # ceny = yield from align_motor_y(det, smy, -2, 2, 0.05, exp_time) + # if ceny is None: + # print(f"Failed to find the edge. Repeating the scan with the wider range.") + # ceny = yield from align_motor_y(det, smy, -4, 4, 0.05, exp_time) + # if ceny is None: + # raise RuntimeError(f"Failed to find the edge: the beam is blocked or the shutter is closed.") + + # yield from align_motor_th(det, sth, -1, 1, 0.02, exp_time, fine_scan=False, mtr_backlash=mtr_backlash) + + # ceny = yield from align_motor_y(det, smy, -0.2, 0.2, 0.02, exp_time) + ceny = yield from align_motor_y2(det, smy, -0.4, 0.4, 0.03, exp_time) + yield from bps.sleep(2) + # centh = yield from align_motor_th(det, sth, -0.1, 0.1, 0.0025, exp_time, fine_scan=True, mtr_backlash=mtr_backlash) + # centh = yield from align_motor_th(det, sth, -0.1, 0.1, 0.005, exp_time, fine_scan=True, mtr_backlash=mtr_backlash) + centh = sth.position + + print(f"Alignment completed: time {time.time() - tstart}") + return ceny, centh + + +# In [86]: printStartEnd() +# 127.2 +# 24.65625 +# 1.3200000000000003 +# 157.20000000000002 +# 24.543750000000003 +# 1.3854687500000011 + + +def align_test2(): + det = pilatus2M + + @bpp.stage_decorator([det]) + def inner(): + yield from align_stub(det) + + yield from inner() + + +def fast_align(det=None): + """ + Attempt to align the detector. + + This is not a plan (produces no events), but expects the detector to be + unstaged. + + This will: + + 1. use a software flyscan to collect measurements + 2. fit a peak + 3. move to the center of the peak + + in both the smy and sth motors. + + If too far from aligned will fail catastrophically. + + Returns + ------- + y_center, th_center + """ + if det is None: + det = pilatus2M + exp_time = 0.3 + yield from cms.modeAlignment() + + # beam.setTransmission(1e-6) + + @bpp.stage_decorator([det]) + def inner(): + return (yield from align_stub(det=det, exp_time=exp_time)) + + det.tiff.disable_on_stage() + try: + return (yield from inner()) + finally: + det.tiff.enable_on_stage() + + +def agent_feedback_plan(sample_x, md=None): + """ + Plan for adaptive round 2} + """ + md = md or {} + + yield from sam.align_lookup(sample_x) + print("ALIGN DONE") + yield from cms.modeMeasurement_plan() + print("IN MEASUE MODE") + yield from sam.measure(1, **md) + print("DONE") + + +# def agent_bootstrap_alignment(end_x=60, start_x=35): +def agent_bootstrap_alignment(end_x=127.2 + 30, start_x=127.2 + 0): + # yield from sam.run_initial_alignment() + + # origin smx = 124.2 + + smx.move(122.4) + laserx.move(0) + RE(cms.modeAlignment()) + + RE(move_sample_with_laser(end_x)) + # smy.move(24.6) + # yield from bps.mv(smx, start_x) + # yield from self.align_crazy_v3_plan(direct_beam_int=direct_beam_int) + sam.align() + + sam.end_x = smx.position + sam.end_y = smy.position + sam.end_th = sth.position + + # yield from bps.mv(smx, end_x) + RE(move_sample_with_laser(start_x)) + # smy.move(129.2+30) + # yield from bps.mv(smy, 24.5) + # yield from self.align_crazy_v3_plan(direct_beam_int=direct_beam_int) + sam.align() + # yield from self.align() + + sam.start_x = smx.position + sam.start_y = smy.position + sam.start_th = sth.position + + RE(cms.modeMeasurement_plan()) + + +# from collections.abc import List + + +def agent_start_sample(init_x_pos: list[float], *, md=None): + """ + The plan to start an adaptive experiment. + + This plan: + + - goes to the first point + - turns on the laser + - restarts the "clock" + - aligns the sample + - sets the state for the look up to align along the length + - takes the first N points to prime the agents + + + Parameters + ---------- + init_x_pos : list[float] + The initial sample positions to take data at. + """ + md = md or {} + + # sam.end_x = 60 + # sam.end_y = 18.2 + # sam.end_th = 1.004 + + calib_x, *_ = init_x_pos + + xpos, ypos, thpos = sam.calc_lookuptable(calib_x) + + yield from move_sample_with_laser(xpos) + # yield from bps.mv(smy, ypos, sth, thpos+0.12) + yield from bps.mv(smy, ypos, sth, thpos + 0.25) + + # yield from move_sample_with_laser(calib_x) + # yield from cms.modeAlignment() + + sam.reset_clock() + RE.md["sample_clock_zero"] = sam.clock_zero + yield from bps.mv(laser.manual_button, 1) + + if abs(calib_x - sam.start_x) > 1: + sam.start_x = calib_x + sam.start_y, sam.start_th = yield from fast_align() + else: + yield from fast_align() + for x in init_x_pos: + yield from agent_feedback_time_plan(x, 0, align=False) + + +def agent_stop_sample(*, md=None): + """ + Plan to run when the agent is done and would like no more data. + + Turns off the laser. + """ + md = md or {} + yield from bps.mv(laser.manual_button, 0) + + +def move_sample_with_laser(xpos): + """ + Moves the sample x and laserx in sync + + TODO: make this a pseudo positioner + """ + cur_x = yield from bps.rd(smx) + + delta = xpos - cur_x + + yield from bps.mvr(smx, delta, laserx, -delta) + + +def agent_feedback_time_plan( + sample_x: float, target_time: float, align: bool = False, exposure: float = 5, md=None +): + """ + The main data acqusition plan for the adaptive experiments + + Parameters + ---------- + sample_x : float + The absolute position to measure the sample at transverse to beam (and along gradient) + + target_time : float + Seconds from epoch. Do not take the data before this wall time. If in the past, take + data as soon as possible + + align : bool, optional + If `fast_align` should be used before taking data + + exposure : float, optional + The exposure time in seconds. + + md : dict, optional + Any additional payload to put in the start document. + + + """ + import time as ttime + + md = md or {} + md.setdefault("PTA", True) + + # this lookup table is primed by agent_start_sample + # it is just linear interpolation + xpos, ypos, thpos = sam.calc_lookuptable(sample_x) + + yield from move_sample_with_laser(xpos) + yield from bps.mv(smy, ypos, sth, thpos + 0.12) + # yield from bps.mv(smy, ypos, sth, thpos+0.25) + # yield from bps.mv(smy, ypos, sth, thpos) + + if align: + ypos_align, thpos_align = yield from fast_align() + # sam.start_x = xpos + # sam.start_y = ypos_align + # sam.start_th = thpos_align + yield from bps.mv(sth, thpos_align + 0.25 - 0.12) + else: + # yield from bps.mv(sth, thpos+.12) + yield from bps.mv(sth, thpos + 0.25) + + yield from cms.modeMeasurement_plan() + + now = ttime.time() + lag = target_time - now + + if lag > 0: + yield from bps.sleep(lag) + + detselect([pilatus2M, pilatus8002]) + yield from sam.measure(exposure, **md) + + +def changeSample(): + yield from move_sample_with_laser(28.67) + yield from bps.mv(smx, -100) + + +def calcTemperature(xpos): + slope = (245 - 70) / (21.8 - 6.3) + xpos = 62.67 - xpos + T = (xpos - 6.3) * slope + 70 + + return T + + +def calcXpos(T): + slope = (245 - 70) / (21.8 - 6.3) + + xpos = (T - 70) / slope + 6.3 + + return 62.67 - xpos + + +""" +In [84]: wsam() +smx = 0.0 +smy = 17.543750000000003 +sth = 1.2385937499999997 + + + +2023,May, 22 + +align with bare Si wafer. +Laser is set 4mm away from the edge of the diving board. + +The clamp edge of the diving board +In [84]: wsam() +smx = 62.554 +smy = 17.543750000000003 +sth = 1.2385937499999997 + +The laser edge of the diving board +In [95]: wsam() +smx = 41.8545 +smy = 17.6 +sth = 1.3318750000000001 + + +align at laser position +In [102]: wsam() +smx = 45.8545 +smy = 17.1875 +sth = 1.0812500000000007 + +align at the clamp position +In [119]: wsam() +smx = 61.8545 +smy = 17.918750000000003 +sth = 1.0806249999999995 + + + +align at laser position with laser ON=2.3 +In [64]: wsam() +smx = 45.7995 +smy = 17.16690625 +sth = 1.22453125 + + + + +===================Heat equilibrium --30-50s at 8 and 16w + +In [98]: pta.setLaserPower(16) +PTA> Setting laser to 16.00 W (using control voltage of 2.93 V) + +In [99]: RE(tmp()) + + +Transient Scan ID: 1060961 Time: 2023-05-22 19:58:21 +Persistent Unique Scan ID: 'afb1ed8e-0363-4d59-a23c-5a446d3a09cf' +/nsls2/conda/envs/2023-2.0-py310-tiled/lib/python3.10/site-packages/nslsii/ad33.py:82: UserWarning: .dispatch is deprecated, use .generate_datum instead + self.dispatch(self._image_name, ttime.time()) +New stream: 'primary' ++-----------+------------+------------------------+------------------------+------------------------+ +| seq_num | time | pilatus2M_stats2_total | pilatus2M_stats3_total | pilatus2M_stats4_total | ++-----------+------------+------------------------+------------------------+------------------------+ +| 1 | 19:58:22.2 | 1018 | 202 | 2028 | +| 2 | 19:58:23.1 | 995 | 183 | 2130 | +| 3 | 19:58:24.0 | 847 | 135 | 2037 | +| 4 | 19:58:24.9 | 864 | 133 | 1949 | +| 5 | 19:58:25.7 | 939 | 141 | 1888 | +| 6 | 19:58:26.6 | 1012 | 158 | 1966 | +| 7 | 19:58:27.4 | 946 | 154 | 1971 | +| 8 | 19:58:28.4 | 849 | 128 | 2100 | +| 9 | 19:58:29.2 | 938 | 147 | 2093 | +| 10 | 19:58:30.1 | 960 | 154 | 2165 | +| 11 | 19:58:30.9 | 968 | 162 | 2168 | +| 12 | 19:58:31.9 | 909 | 131 | 2202 | +| 13 | 19:58:32.7 | 892 | 113 | 2254 | +| 14 | 19:58:33.6 | 896 | 121 | 2063 | +| 15 | 19:58:34.4 | 864 | 117 | 2317 | +| 16 | 19:58:35.4 | 835 | 114 | 2369 | +| 17 | 19:58:36.2 | 809 | 102 | 2271 | +| 18 | 19:58:37.1 | 763 | 94 | 2303 | +| 19 | 19:58:38.0 | 847 | 119 | 2424 | +| 20 | 19:58:38.9 | 762 | 106 | 2531 | +| 21 | 19:58:39.7 | 733 | 103 | 2521 | +| 22 | 19:58:40.5 | 704 | 95 | 2512 | +| 23 | 19:58:41.4 | 719 | 91 | 2552 | +| 24 | 19:58:42.4 | 721 | 89 | 2597 | +| 25 | 19:58:43.2 | 693 | 75 | 2636 | +| 26 | 19:58:44.0 | 721 | 80 | 2629 | +| 27 | 19:58:44.9 | 694 | 81 | 2630 | +| 28 | 19:58:45.9 | 694 | 80 | 2806 | +| 29 | 19:58:46.7 | 638 | 75 | 2750 | +| 30 | 19:58:47.5 | 648 | 85 | 2895 | +| 31 | 19:58:48.3 | 731 | 79 | 2905 | +| 32 | 19:58:49.1 | 586 | 74 | 2703 | +| 33 | 19:58:50.0 | 644 | 67 | 2970 | +| 34 | 19:58:50.9 | 651 | 72 | 2824 | +| 35 | 19:58:51.7 | 696 | 91 | 3065 | +| 36 | 19:58:52.5 | 617 | 64 | 3013 | +| 37 | 19:58:53.3 | 605 | 72 | 2701 | +| 38 | 19:58:54.2 | 533 | 70 | 2638 | +| 39 | 19:58:55.0 | 571 | 74 | 2897 | +| 40 | 19:58:55.8 | 618 | 84 | 3018 | +| 41 | 19:58:56.7 | 585 | 69 | 3036 | +| 42 | 19:58:57.5 | 546 | 73 | 2883 | +| 43 | 19:58:58.4 | 564 | 64 | 2906 | +| 44 | 19:58:59.3 | 544 | 62 | 2928 | +| 45 | 19:59:00.1 | 580 | 73 | 3029 | +| 46 | 19:59:00.9 | 545 | 67 | 3123 | +| 47 | 19:59:01.8 | 540 | 81 | 2943 | +| 48 | 19:59:02.6 | 536 | 83 | 3071 | +| 49 | 19:59:03.5 | 517 | 72 | 3167 | ++-----------+------------+------------------------+------------------------+------------------------+ +| seq_num | time | pilatus2M_stats2_total | pilatus2M_stats3_total | pilatus2M_stats4_total | ++-----------+------------+------------------------+------------------------+------------------------+ +| 50 | 19:59:04.3 | 526 | 74 | 3077 | +| 51 | 19:59:05.1 | 522 | 77 | 3213 | +| 52 | 19:59:05.9 | 500 | 63 | 2978 | +| 53 | 19:59:06.9 | 504 | 59 | 3044 | +| 54 | 19:59:07.7 | 555 | 92 | 3196 | +| 55 | 19:59:08.6 | 494 | 76 | 3231 | +| 56 | 19:59:09.4 | 512 | 83 | 3030 | +| 57 | 19:59:10.3 | 509 | 71 | 2946 | +| 58 | 19:59:11.2 | 480 | 76 | 3116 | +| 59 | 19:59:12.0 | 492 | 70 | 3052 | +| 60 | 19:59:12.8 | 515 | 78 | 3137 | +| 61 | 19:59:13.8 | 490 | 79 | 3064 | +| 62 | 19:59:14.7 | 496 | 70 | 3200 | +| 63 | 19:59:15.5 | 513 | 89 | 3085 | +| 64 | 19:59:16.3 | 520 | 80 | 3298 | +| 65 | 19:59:17.2 | 493 | 59 | 3052 | +| 66 | 19:59:18.0 | 489 | 76 | 3338 | +| 67 | 19:59:18.8 | 470 | 61 | 3167 | +| 68 | 19:59:19.8 | 471 | 53 | 3013 | +| 69 | 19:59:20.7 | 476 | 65 | 3124 | +| 70 | 19:59:21.5 | 526 | 87 | 3250 | +| 71 | 19:59:22.3 | 471 | 67 | 3093 | +| 72 | 19:59:23.1 | 508 | 75 | 3123 | +| 73 | 19:59:23.9 | 471 | 75 | 3171 | +| 74 | 19:59:24.8 | 481 | 77 | 3360 | +| 75 | 19:59:25.6 | 444 | 75 | 3163 | +| 76 | 19:59:26.5 | 510 | 61 | 3186 | +| 77 | 19:59:27.3 | 469 | 80 | 3092 | +| 78 | 19:59:28.1 | 460 | 71 | 3079 | +| 79 | 19:59:28.9 | 428 | 88 | 3428 | +| 80 | 19:59:29.9 | 511 | 98 | 3118 | +| 81 | 19:59:30.7 | 499 | 76 | 3169 | +| 82 | 19:59:31.5 | 474 | 69 | 3112 | +| 83 | 19:59:32.3 | 470 | 83 | 3045 | +| 84 | 19:59:33.1 | 503 | 85 | 3140 | +| 85 | 19:59:34.0 | 422 | 70 | 3265 | +| 86 | 19:59:34.8 | 452 | 71 | 3226 | +| 87 | 19:59:35.7 | 445 | 83 | 3250 | +| 88 | 19:59:36.5 | 456 | 73 | 3069 | +| 89 | 19:59:37.4 | 445 | 66 | 3219 | +| 90 | 19:59:38.4 | 447 | 68 | 3137 | +| 91 | 19:59:39.1 | 421 | 49 | 2991 | +| 92 | 19:59:39.9 | 479 | 75 | 3266 | +| 93 | 19:59:40.9 | 459 | 61 | 3229 | +| 94 | 19:59:41.7 | 463 | 92 | 3273 | +| 95 | 19:59:42.5 | 482 | 75 | 3366 | +| 96 | 19:59:43.3 | 469 | 77 | 2825 | +| 97 | 19:59:44.4 | 454 | 65 | 3137 | +| 98 | 19:59:45.2 | 536 | 103 | 3153 | +| 99 | 19:59:46.0 | 504 | 59 | 3197 | ++-----------+------------+------------------------+------------------------+------------------------+ +| seq_num | time | pilatus2M_stats2_total | pilatus2M_stats3_total | pilatus2M_stats4_total | ++-----------+------------+------------------------+------------------------+------------------------+ +| 100 | 19:59:46.9 | 512 | 80 | 3354 | ++-----------+------------+------------------------+------------------------+------------------------+ +generator count ['afb1ed8e'] (scan num: 1060961) + + + +Out[99]: ('afb1ed8e-0363-4d59-a23c-5a446d3a09cf',) + +In [100]: def tmp(): + ...: yield from beam.on() + ...: yield from bps.mv(laser.manual_button, 1) + ...: yield from bp.count([pilatus2M, core_laser], 100) + ...: yield from bps.mv(laser.manual_button, 0) + ...: yield from beam.off() + ...: + ...: + +In [101]: + +In [101]: pta.setLaserPower(8) +PTA> Setting laser to 8.00 W (using control voltage of 1.86 V) + +In [102]: RE(tmp()) + + +Transient Scan ID: 1060962 Time: 2023-05-22 20:00:43 +Persistent Unique Scan ID: '21042f80-ae1a-4b9b-bd8a-7158ec0dad77' +/nsls2/conda/envs/2023-2.0-py310-tiled/lib/python3.10/site-packages/nslsii/ad33.py:82: UserWarning: .dispatch is deprecated, use .generate_datum instead + self.dispatch(self._image_name, ttime.time()) +New stream: 'primary' ++-----------+------------+------------------------+------------------------+------------------------+ +| seq_num | time | pilatus2M_stats2_total | pilatus2M_stats3_total | pilatus2M_stats4_total | ++-----------+------------+------------------------+------------------------+------------------------+ +| 1 | 20:00:44.2 | 997 | 252 | 1635 | +| 2 | 20:00:45.1 | 1014 | 269 | 1715 | +| 3 | 20:00:46.0 | 968 | 226 | 1641 | +| 4 | 20:00:46.9 | 918 | 215 | 1635 | +| 5 | 20:00:47.9 | 946 | 204 | 1637 | +| 6 | 20:00:48.8 | 957 | 245 | 1667 | +| 7 | 20:00:49.7 | 1078 | 265 | 1608 | +| 8 | 20:00:50.6 | 995 | 229 | 1729 | +| 9 | 20:00:51.5 | 964 | 236 | 1608 | +| 10 | 20:00:52.4 | 977 | 256 | 1757 | +| 11 | 20:00:53.4 | 944 | 225 | 1723 | +| 12 | 20:00:54.2 | 997 | 244 | 1826 | +| 13 | 20:00:55.1 | 1010 | 242 | 1678 | +| 14 | 20:00:56.0 | 907 | 235 | 1819 | +| 15 | 20:00:56.9 | 1014 | 249 | 1835 | +| 16 | 20:00:57.8 | 996 | 235 | 1935 | +| 17 | 20:00:58.7 | 1025 | 225 | 1919 | +| 18 | 20:00:59.5 | 981 | 234 | 1829 | +| 19 | 20:01:00.5 | 956 | 194 | 1848 | +| 20 | 20:01:01.4 | 1094 | 236 | 1904 | +| 21 | 20:01:02.4 | 926 | 193 | 2014 | +| 22 | 20:01:03.3 | 992 | 221 | 2068 | +| 23 | 20:01:04.2 | 863 | 182 | 2027 | +| 24 | 20:01:05.0 | 951 | 204 | 2019 | +| 25 | 20:01:05.9 | 961 | 212 | 2087 | +| 26 | 20:01:06.8 | 1031 | 225 | 2172 | +| 27 | 20:01:07.7 | 980 | 205 | 2035 | +| 28 | 20:01:08.6 | 974 | 209 | 2145 | +| 29 | 20:01:09.4 | 971 | 202 | 2233 | +| 30 | 20:01:10.3 | 1042 | 220 | 2190 | +| 31 | 20:01:11.4 | 940 | 222 | 2094 | +| 32 | 20:01:12.3 | 794 | 170 | 2154 | +| 33 | 20:01:13.2 | 862 | 188 | 2019 | +| 34 | 20:01:14.2 | 900 | 184 | 2265 | +| 35 | 20:01:15.0 | 993 | 189 | 2259 | +| 36 | 20:01:15.9 | 842 | 161 | 2128 | +| 37 | 20:01:16.8 | 836 | 169 | 2199 | +| 38 | 20:01:17.7 | 886 | 171 | 2317 | +| 39 | 20:01:18.5 | 871 | 176 | 2229 | +| 40 | 20:01:19.4 | 917 | 166 | 2140 | +| 41 | 20:01:20.3 | 880 | 175 | 2266 | +| 42 | 20:01:21.2 | 890 | 194 | 2316 | +| 43 | 20:01:22.1 | 854 | 185 | 2217 | +| 44 | 20:01:23.0 | 854 | 180 | 2224 | +| 45 | 20:01:23.9 | 978 | 199 | 2277 | +| 46 | 20:01:24.8 | 837 | 171 | 2287 | +| 47 | 20:01:25.7 | 816 | 171 | 2376 | +| 48 | 20:01:26.6 | 863 | 188 | 2275 | +| 49 | 20:01:27.5 | 903 | 189 | 2409 | ++-----------+------------+------------------------+------------------------+------------------------+ +| seq_num | time | pilatus2M_stats2_total | pilatus2M_stats3_total | pilatus2M_stats4_total | ++-----------+------------+------------------------+------------------------+------------------------+ +| 50 | 20:01:28.4 | 828 | 177 | 2349 | +| 51 | 20:01:29.4 | 834 | 168 | 2273 | +| 52 | 20:01:30.3 | 829 | 168 | 2308 | +| 53 | 20:01:31.1 | 807 | 161 | 2391 | +| 54 | 20:01:32.0 | 808 | 149 | 2413 | +| 55 | 20:01:32.9 | 839 | 172 | 2408 | +| 56 | 20:01:33.7 | 864 | 186 | 2403 | +| 57 | 20:01:34.6 | 864 | 170 | 2368 | +| 58 | 20:01:35.5 | 738 | 162 | 2294 | +| 59 | 20:01:36.4 | 805 | 171 | 2385 | +| 60 | 20:01:37.4 | 866 | 185 | 2551 | +| 61 | 20:01:38.3 | 826 | 167 | 2312 | +| 62 | 20:01:39.1 | 799 | 161 | 2322 | +| 63 | 20:01:40.1 | 818 | 164 | 2438 | +| 64 | 20:01:41.0 | 806 | 177 | 2416 | +| 65 | 20:01:42.0 | 783 | 175 | 2356 | +| 66 | 20:01:42.9 | 839 | 195 | 2388 | +| 67 | 20:01:43.9 | 822 | 153 | 2446 | +| 68 | 20:01:44.8 | 853 | 182 | 2498 | +| 69 | 20:01:45.7 | 865 | 167 | 2309 | +| 70 | 20:01:46.6 | 771 | 160 | 2539 | +| 71 | 20:01:47.5 | 773 | 145 | 2486 | +| 72 | 20:01:48.4 | 829 | 172 | 2399 | +| 73 | 20:01:49.3 | 891 | 167 | 2633 | +| 74 | 20:01:50.2 | 855 | 184 | 2512 | +| 75 | 20:01:51.1 | 811 | 173 | 2426 | +| 76 | 20:01:52.0 | 804 | 167 | 2271 | +| 77 | 20:01:52.9 | 873 | 174 | 2407 | +| 78 | 20:01:53.8 | 880 | 147 | 2634 | +| 79 | 20:01:54.7 | 778 | 140 | 2431 | +| 80 | 20:01:55.6 | 887 | 153 | 2510 | +| 81 | 20:01:56.5 | 821 | 157 | 2531 | +| 82 | 20:01:57.4 | 788 | 169 | 2441 | +| 83 | 20:01:58.4 | 762 | 146 | 2341 | +| 84 | 20:01:59.3 | 793 | 168 | 2433 | +| 85 | 20:02:00.2 | 735 | 143 | 2471 | +| 86 | 20:02:01.1 | 798 | 181 | 2408 | +| 87 | 20:02:02.0 | 876 | 188 | 2537 | +| 88 | 20:02:02.9 | 792 | 163 | 2518 | +| 89 | 20:02:03.8 | 747 | 163 | 2430 | +| 90 | 20:02:04.7 | 682 | 146 | 2400 | +| 91 | 20:02:05.6 | 723 | 154 | 2477 | +| 92 | 20:02:06.5 | 837 | 173 | 2471 | +| 93 | 20:02:07.4 | 798 | 153 | 2382 | +| 94 | 20:02:08.4 | 767 | 146 | 2424 | +| 95 | 20:02:09.2 | 765 | 153 | 2486 | +| 96 | 20:02:10.1 | 736 | 154 | 2538 | +| 97 | 20:02:11.0 | 801 | 123 | 2515 | +| 98 | 20:02:11.8 | 771 | 161 | 2547 | +| 99 | 20:02:12.8 | 698 | 140 | 2474 | ++-----------+------------+------------------------+------------------------+------------------------+ +| seq_num | time | pilatus2M_stats2_total | pilatus2M_stats3_total | pilatus2M_stats4_total | ++-----------+------------+------------------------+------------------------+------------------------+ +| 100 | 20:02:13.7 | 748 | 142 | 2401 | ++-----------+------------+------------------------+------------------------+------------------------+ +generator count ['21042f80'] (scan num: 1060962) + + + + + +2023, 05, 23 + +#change to standard REAL sample. + +@the edge of the clamp side +%mov smx 62.67 +In [191]: wsam() + ...: + ...: +smx = 61.67 +smy = 18.29416875 +sth = 0.9845312499999999 + + +@the edge of the laser side +In [176]: wsam() + +smx = 30.3705 +smy = 17.268571875 +sth = 1.1320312500000007 + +@the laser is located at 34mm away from the clamp +Positioner Value Low Limit High Limit Offset +laserx -0.0025 -100.0 100.0 0.0 +smx 28.67 -100.0 100.0 0.0 + + + +In [183]: wsam() +smx = 28.67 +smy = 17.24416875 +sth = 1.1196874999999995 + + +Temperature calibration + +turn on the laser at 17Watts + the burn mark1 (245C) is 21.8mm away from the clamp + the burn mark2 (70C) is 6.3mm away from the clamp + +start the REAL sample + +align @ clamp edge +In [333]: wsam() +smx = 60.0 +smy = 18.2 +sth = 1.0035937500000003 + + +align @ smx = 40 +In [388]: wsam() +smx = 40.0 +smy = 17.5 +sth = 1.0076562500000001 + +align @ smx = 35 +smx = 35.0 +smy = 17.3375 +sth = 1.0935937500000001 + + +In [613]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[613]: (35, 24.644, 1.057, 60, 25.4945, 1.0257999999999998) + +sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th = 35, 24.644, 1.057, 60, 25.4945, 1.0257999999999998 + + + +#new sample run2 + +In [708]: sam.name +Out[709]: 'C67_0HP_Tb50C_LP17w_run2' + +In [711]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[711]: (35, 25.441634375, 1.069, 60, 25.81, 1.063) + +run lasted 30min with 52 data points. + + +#new sample run3 + +In [708]: sam.name +Out[709]: 'C67_0HP_Tb50C_LP17w_run3' + +In [744]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[745]: (35, 25.505, 1.092968, 60.0, 25.836803125, 1.0717187500000005) + +run3 will last 10 hours until the morning of May 24. +run3 actually was terminated in midnight due to an error of agent. +extra data was taken at 11hours after the start of laser + + +In [852]: sam.name +Out[852]: 'C67_40HP_Tb50C_LP17w_run4' + +In [851]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[851]: (35, 25.175671875000003, 1.07, 60.0, 25.723056250000003, 1.0684375) + + +In [852]: sam.name +Out[852]: 'C67_40HP_Tb50C_LP17w_run5' +In [868]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[868]: (35.0, 25.382625, 1.04296875, 60.0, 25.825959375, 1.0212500000000002) + + +In [852]: sam.name +Out[852]: 'C67_20HP_Tb50C_LP17w_run6' +In [868]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[887]: +(35.0, + 25.457353125, + 1.1807812500000008, + 60.0, + 25.815703125000002, + 1.1545312499999998) + +In [852]: sam.name +Out[852]: 'C67_40HP_Tb50C_LP17w_run7' +In [897]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[897]: +(35.0, + 25.4574, + 1.0407812500000002, + 60.0, + 25.818787500000003, + 1.0543750000000003) + + +In [852]: sam.name +Out[852]: 'C67_0HP_Tb50C_LP17w_run5' #should be run8, supposed to run 10hours + + In [903]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[903]: (35.0, 25.32549375, 1.0982812499999994, 60.0, 25.76560625, 1.0948437500000008) + +In [852]: sam.name +Out[852]: 'C67_20HP_Tb50C_LP17w_run9' + + +In [852]: sam.name +Out[852]: 'C67_40HP_Tb50C_LP17w_run10' + +In [919]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[919]: +(35.0, + 25.629559375, + 1.1354687500000011, + 60.0, + 25.907678125, + 1.0960937499999996) + +In [852]: sam.name +Out[852]: 'C67_0HP_Tb50C_LP17w_run11' + + In [935]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[935]: (35.0, 24.944746875, 1.043906250000001, 60.0, 25.626225, 1.0310937500000001) + + +protocol: +changeSample() +sam=Sample('test') +agent_bootstrap_alignment() #automatic alignment at smx = 35 and 60 +#save sam.start_x/y/th, sam.end_x/y/th position. + +#start agent +#start initial measurement + +#in a different python env, enable the autostart to automatically run the commands in qserver. +PYTHONPATH=/nsls2/data/cms/shared/config/bluesky_overlay/2023-2.0-py310-tiled/lib/python3.10/site-packages qserver queue autostart enable + +PYTHONPATH=/nsls2/data/cms/shared/config/bluesky_overlay/2023-2.0-py310-tiled/lib/python3.10/site-packages qserver status + +========================================= +when the experiment is done-- + +PYTHONPATH=/nsls2/data/cms/shared/config/bluesky_overlay/2023-2.0-py310-tiled/lib/python3.10/site-packages qserver queue autostart disable + +""" + + +# smx = 38.9045 +# smy = 17.435846875000003 +# sth = 1.3117187500000007 + + +""" +smx = 160.1 @ x-ray beam on the heat edge + +smx = 125.4 @ x-ray beam on the sapphire wafer + +smx = 127.1 @ x-ray beam on the edge betwee sapphire and Si wafer + + +""" + + +# exhausive scan + + +def noAgent_scan(xpos_list, cycles=10, align=True, laserOn=True, reset_clock=True): + RE(move_sample_with_laser(127.2)) + + if laserOn == True: + pta.laserOn() + if reset_clock == True: + sam.reset_clock() + for cycle in range(cycles): + for xpos in xpos_list: + RE(agent_feedback_time_plan(xpos, 0, align=align)) + + pta.laserOff() diff --git a/startup/999_user_PTA.py_ b/startup/999_user_PTA.py_ new file mode 100644 index 0000000..3b6d4a6 --- /dev/null +++ b/startup/999_user_PTA.py_ @@ -0,0 +1,4557 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# vi: ts=4 sw=4 + + + +####### +# v3 --> v4: coord based on KY_coord_form.py + +# applied on sample : 16(7th) , 7(8th), 6(9th), 11(10th), 12(11th), 1(12th, LonC), 5(13th), 3(14th, LonC) + +####### + + +################################################################################ +# Short-term settings (specific to a particular user/experiment) can +# be placed in this file. You may instead wish to make a copy of this file in +# the user's data directory, and use that as a working copy. +################################################################################ + +from ophyd import Device, Component as Cpt, EpicsSignal, EpicsSignalRO +from bluesky.suspenders import SuspendFloor +import bluesky.plan_stubs as bps +import bluesky.preprocessors as bpp + +import sympy as sym + +print(f"Loading {__file__!r} ...") + +if True: + # Define suspenders to hold data collection if x-ray + # beam is not available. + + ring_current = EpicsSignal("SR:OPS-BI{DCCT:1}I:Real-I") + sus = SuspendFloor(ring_current, 100, resume_thresh=400, sleep=600) + RE.install_suspender(sus) + +# absorber_pos = EpicsSignal( 'XF:11BMB-ES{SM:1-Ax:ArmR}Mtr.RBV') +# sus_abs_low = SuspendFloor(absorber_pos, -56, resume_thresh=-55) +# sus_abs_hi = SuspendCeil(absorber_pos, -54, resume_thresh=-55) +# RE.install_suspender(sus_abs_low) +# RE.install_suspender(sus_abs_hi) + +# RE.clear_suspenders() + + +if False: + # The following shortcuts can be used for unit conversions. For instance, + # for a motor operating in 'mm' units, one could instead do: + # sam.xr( 10*um ) + # To move it by 10 micrometers. HOWEVER, one must be careful if using + # these conversion parameters, since they make implicit assumptions. + # For instance, they assume linear axes are all using 'mm' units. Conversely, + # you will not receive an error if you try to use 'um' for a rotation axis! + m = 1e3 + cm = 10.0 + mm = 1.0 + um = 1e-3 + nm = 1e-6 + + inch = 25.4 + pixel = 0.172 # Pilatus + + deg = 1.0 + rad = np.degrees(1.0) + mrad = np.degrees(1e-3) + urad = np.degrees(1e-6) + + +INTENSITY_EXPECTED_050 = 18800.0 +INTENSITY_EXPECTED_025 = INTENSITY_EXPECTED_050 * 0.5 + + +def get_default_stage(): + return stg + + +# TODO consider if this is better than using EpicsSignal with different read / +# write PVs +class PairSP(Device): + """ + Hold a pair of PVs as a set-point / readback pair + + set forwards to the set point. + """ + sp = Cpt(EpicsSignal, '-SP', kind='normal') + rb = Cpt(EpicsSignalRO, '-RB', kind='hinted') + + def set(self, value, **kwargs): + return self.sp.set(value, **kwargs) + + +class PairSEL(Device): + """ + Hold a pair of PVs as bool / readback pair + + set forwards to the Select + """ + sel = Cpt(EpicsSignal, '-Sel', kind='normal') + rb = Cpt(EpicsSignalRO, '-RB', kind='hinted', string=True, auto_monitor=True) + + def set(self, value, **kwargs): + return self.sel.set(value, **kwargs) + + +class PairCMD(Device): + """ + Hold a pair of PVs as CMD / readback pair + + set forwards to the CMD + """ + cmd = Cpt(EpicsSignal, '-CMD', kind='omitted') + rb = Cpt(EpicsSignalRO, '-RB', kind='hinted') + + def set(self, value, **kwargs): + return self.cmd.set(value, **kwargs) + + +class Laser(Device): + """ + Class to represent the PTA laser as controlled by the beckoff I/O + """ + # Set pulse width for output + # Milliseconds units + width = Cpt(PairSP, 'OutWidthSet:1') + # Set delay between input trigger and output trigger + # Milliseconds units + delay = Cpt(PairSP, 'OutDelaySet:1') + # Set number of discrete pulses per trigger event + pulses = Cpt(PairSP, 'OutPulsesSet:1') + + # Read inputs + # 1 = PV trigger, 2 = physical trigger + input1 = Cpt(EpicsSignalRO, 'Input:1-RB') + input2 = Cpt(EpicsSignalRO, 'Input:2-RB') + + # Enable/disable trigger inputs + # 1 = PV trigger, 2 = physical trigger + pv_bitmask = Cpt(PairSEL, 'InMaskBit:1') + physical_bitmank = Cpt(PairSEL, 'InMaskBit:2') + + # PV Trigger + pv_trigger = Cpt(PairCMD, 'Trigger:PV') + + # Enable/disable output trigger mode + trigger_mode = Cpt(PairSEL, 'OutMaskBit:1') + + # Output override and output readback + # Override only works when trigger disabled + manual_button = Cpt(PairSEL, 'Output:1') + + def manual_mode(self): + yield from bps.mv(self.trigger, 0) + + def turn_on(self): + # TODO check if we are in manual mode + yield from bps.mv(self.manual_button, 1) + + def turn_off(self): + # TODO check if we are in manual mode + yield from bps.mv(self.manual_button, 0) + + +laser = Laser('XF:11BM-CT{BIOME-MTO:1}', name='laser') + + +class SampleTSAXS(SampleTSAXS_Generic): + def __init__(self, name, base=None, **md): + super().__init__(name=name, base=base, **md) + self.naming_scheme = ["name", "extra", "temperature", "exposure_time"] + + self.md["exposure_time"] = 30.0 + + +class SampleGISAXS(SampleGISAXS_Generic): + def __init__(self, name, base=None, **md): + super().__init__(name=name, base=base, **md) + self.naming_scheme = ["name", "extra", "th", "exposure_time"] + + +# class Sample(SampleTSAXS): +class Sample(SampleGISAXS): + def __init__(self, name, base=None, **md): + super().__init__(name=name, base=base, **md) + + # self.naming_scheme = ['name', 'extra', 'clock', 'temperature', 'th', 'exposure_time'] + # self.naming_scheme = ['name', 'extra', 'temperature', 'th', 'exposure_time'] + # self.naming_scheme = ['name', 'extra', 'th', 'exposure_time'] + # self.naming_scheme = ['name', 'extra', 'y', 'th', 'clock', 'exposure_time'] + # self.naming_scheme = ['name', 'extra', 'opos', 'lpos', 'x', 'th', 'exposure_time'] + # self.naming_scheme = ['name', 'extra', 'clock', 'localT', 'exposure_time'] + # self.naming_scheme = ['name', 'extra', 'x', 'yy', 'exposure_time'] + # self.naming_scheme = ['name', 'extra', 'SamX', 'SamY', 'exposure_time'] + # self.naming_scheme = ['name', 'extra', 'x', 'yy', 'SamX', 'SamY', 'exposure_time'] + # self.naming_scheme = ['name', 'extra', 'x', 'yy', 'h1', 'h2', 'exposure_time'] + self.naming_scheme = ["name", "extra", "Tc", "clock", "x", "th", "exposure_time"] + self.name_o = self.name + self.md["exposure_time"] = 5.0 + # self.incident_angles_default = [0.08, 0.10, 0.12, 0.15, 0.20] + + # self.anneal_time = int(self.name.split('_')[-2].split('anneal')[-1]) + # self.anneal_time = int(self.name.split('anneal')[-1].split('_')[0]) + # self.preanneal_time = int(self.name.split('pre')[-1].split('_')[0]) + + self._positional_axis = ["x", "y"] + + self.smxPos = [121.5, 142.5, 162.5] + + # self._axes["x"].origin = 130 + # self._axes["y"].origin = 16.8 # smy stage should be set with the limit [-5.5, -5] + # self._axes["th"].origin = 0 + + self._axes["x"].origin = 0 + self._axes["y"].origin = 39.26 # smy stage should be set with the limit [-5.5, -5] + self._axes["th"].origin = 0.93 + + #default position for laser position on the edge of the sample (5mm offset) + #smx = -1.5, laserx = 0 + #smx and laserx should move simultaneously. + + # def get_attribute(self, attribute): + # '''Return the value of the requested md.''' + # #return the value of temperature by IR laser where the + # if attribute == 'localT': + # return 'localT{:.1f}'.format(self.x2localT()) + # elif attribute == 'clockT': + # return 'clock{:.2f}'.format(self.clock()) + # else: + # return super().get_attribute(attribute) + + # #convert temperature to x position to tempreature in the gradient created by laser + # def localT2x(self, temperature, t_range=[25, 500], xo=0, length=10): + # #xo is located at the HOT temperature (laser spot) + # #(x_pos-xo)/(-length) = (temperature-t_range[1])/(t_range[0]-t_range[1]) + # #x_pos = (temperature-t_range[1])/(t_range[0]-t_range[1])*(-length) + xo + + # x_pos = (492 - temperature)/24.7 # P_frac = 0.45 + # return -x_pos + + # #convert x position to tempreature in the gradient created by laser + # def x2localT(self, t_range=[25, 500], xo=0, length=10): + # #(x_pos-xo)/(-length) = (temperature-t_range[1])/(t_range[0]-t_range[1]) + # x_pos = self.xpos(verbosity=0) + # #temperature = (x_pos-xo)/(-length)*(t_range[0]-t_range[1]) + t_range[1] + + # T_est = 492 - abs(x_pos)*24.7 # P_frac = 0.45 + + # return T_est + + def setFlow(self, channel, voltage=0): + # device = 'A1' + ioL.set(AO[channel], 0) + time.sleep(1) + ioL.set(AO[channel], voltage) + + def setDryFlow(self, voltage=None): + if voltage == None or voltage > 5 or voltage < 0: + print("Input voltage betwee 0 and 5V") + self.setFlow(1, voltage=voltage) + + def _set_axes_definitions(self): + """Internal function which defines the axes for this stage. This is kept + as a separate function so that it can be over-ridden easily.""" + + # The _axes_definitions array holds a list of dicts, each defining an axis + super()._set_axes_definitions() + + # self._axes_definitions.append ( {'name': 'y', + # 'motor': smy2, + # 'enabled': True, + # 'scaling': +1.0, + # 'units': 'mm', + # 'hint': 'positive moves stage up', + # }, + # {'name': 'x', + # 'motor': , + # 'enabled': True, + # 'scaling': +1.0, + # 'units': 'mm', + # 'hint': 'positive moves stage up', + # } ) + + def get_attribute(self, attribute): + """Return the value of the requested md.""" + if attribute == "Tc": + # return 'SamX{:.2f}'.format(-1*self.yypos(verbosity=0)) # Nov 2020 + return "Tc{:.2f}".format(pta.getTemperature(verbosity=0)) # Feb 2021 + else: + return super().get_attribute(attribute) + + def get_md(self, prefix="sample_", include_marks=True, **md): + """Returns a dictionary of the current metadata. + The 'prefix' argument is prepended to all the md keys, which allows the + metadata to be grouped with other metadata in a clear way. (Especially, + to make it explicit that this metadata came from the sample.)""" + + # Update internal md + # self.md['key'] = value + + yield from bps.null() ##!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + md_return = self.md.copy() + md_return["name"] = self.name + + if include_marks: + for label, positions in self._marks.items(): + md_return["mark_" + label] = positions + + # Add md that varies over time + md_return["clock"] = self.clock() + + for axis_name, axis in self._axes.items(): + md_return[axis_name] = axis.get_position(verbosity=0) + md_return["motor_" + axis_name] = axis.get_motor_position(verbosity=0) + + md_return["savename"] = self.get_savename() # This should be over-ridden by 'measure' + + # Include the user-specified metadata + md_return.update(md) + + # Add an optional prefix + if prefix is not None: + md_return = {"{:s}{:s}".format(prefix, key): value for key, value in md_return.items()} + + return md_return + + def align(self, step=0, reflection_angle=0.12, verbosity=3): + """Align the sample with respect to the beam. GISAXS alignment involves + vertical translation to the beam center, and rocking theta to get the + sample plane parralel to the beam. Finally, the angle is re-optimized + in reflection mode. + + The 'step' argument can optionally be given to jump to a particular + step in the sequence.""" + start_time = time.time() + alignment = "Success" + initial_y = smy.position + initial_th = sth.position + + align_crazy = self.swing(reflection_angle=reflection_angle) + crazy_y = smy.position + crazy_th = sth.position + + if align_crazy[0] == False: + alignment = "Failed" + if step <= 4: + if verbosity >= 4: + print(" align: fitting") + + fit_scan(smy, 1.2, 21, fit="HMi") + ##time.sleep(2) + fit_scan(sth, 1.5, 21, fit="max") + # time.sleep(2) + + if step <= 8: + # fit_scan(smy, 0.3, 21, fit='sigmoid_r') + + fit_edge(smy, 0.6, 21) + # time.sleep(2) + # fit_edge(smy, 0.4, 21) + fit_scan(sth, 0.8, 21, fit="COM") + # time.sleep(2) + self.setOrigin(["y", "th"]) + + if step <= 9 and reflection_angle is not None: + # Final alignment using reflected beam + if verbosity >= 4: + print(" align: reflected beam") + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2.0) + # get_beamline().setReflectedBeamROI(total_angle=reflection_angle*2.0, size=[12,2]) + + self.thabs(reflection_angle) + + result = fit_scan(sth, 0.4, 41, fit="max") + # result = fit_scan(sth, 0.2, 81, fit='max') #it's useful for alignment of SmarAct stage + sth_target = result.values["x_max"] - reflection_angle + + if result.values["y_max"] > 50: + th_target = self._axes["th"].motor_to_cur(sth_target) + self.thsetOrigin(th_target) + + # fit_scan(smy, 0.2, 21, fit='max') + # self.setOrigin(['y']) + + if step <= 10: + self.thabs(0.0) + beam.off() + + ### save the alignment information + align_time = time.time() - start_time + + # current_data = { + # "a_sample": self.name, + # "i_smx": smx.position, + # "j_smy": smy.position, + # "k_sth": sth.position, + # "l_laserx": laserx.position, + # "m_power": caget(pta.powerV_PV), + # "b_quick_alignment": alignment, + # "c_align_time": align_time, + # "d_offset_y": smy.position - initial_y, + # "e_offset_th": sth.position - initial_th, + # "f_crazy_offset_y": smy.position - crazy_y, + # "g_crazy_offset_th": sth.position - crazy_th, + # "h_search_no": align_crazy[1], + # } + + # temp_data = pds.DataFrame([current_data]) + + # INT_FILENAME = "{}/data/{}.csv".format(os.path.dirname(__file__), "alignment_results.csv") + + # if os.path.isfile(INT_FILENAME): + # output_data = pds.read_csv(INT_FILENAME, index_col=0) + # output_data = output_data.append(temp_data, ignore_index=True) + # output_data.to_csv(INT_FILENAME) + # else: + # temp_data.to_csv(INT_FILENAME) + + def align_old(self, step=0, reflection_angle=0.12, verbosity=3): + """Align the sample with respect to the beam. GISAXS alignment involves + vertical translation to the beam center, and rocking theta to get the + sample plane parralel to the beam. Finally, the angle is re-optimized + in reflection mode. + + The 'step' argument can optionally be given to jump to a particular + step in the sequence.""" + # if step<=4: + # if verbosity>=4: + # print(' align: fitting') + + # fit_scan(smy, 1.2, 21, fit='HMi') + # ##time.sleep(2) + # fit_scan(sth, 1.5, 21, fit='max') + ##time.sleep(2) + cms.modeAlignment() + self.yo() + self.tho() + if step <= 8: + # fit_scan(smy, 0.3, 21, fit='sigmoid_r') + + fit_edge(smy, 0.6, 21) + # time.sleep(2) + # fit_edge(smy, 0.4, 21) + fit_scan(sth, 0.8, 21, fit="COM") + # time.sleep(2) + self.setOrigin(["y", "th"]) + + if step <= 9 and reflection_angle is not None: + # Final alignment using reflected beam + if verbosity >= 4: + print(" align: reflected beam") + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2.0) + # get_beamline().setReflectedBeamROI(total_angle=reflection_angle*2.0, size=[12,2]) + + self.thabs(reflection_angle) + + result = fit_scan(sth, 0.4, 41, fit="max") + # result = fit_scan(sth, 0.2, 81, fit='max') #it's useful for alignment of SmarAct stage + sth_target = result.values["x_max"] - reflection_angle + + if result.values["y_max"] > 50: + th_target = self._axes["th"].motor_to_cur(sth_target) + self.thsetOrigin(th_target) + + # fit_scan(smy, 0.2, 21, fit='max') + # self.setOrigin(['y']) + + if step <= 10: + self.thabs(0.0) + beam.off() + + def align_th(self, step=0, reflection_angle=0.12, verbosity=3): + """Align the sample with respect to the beam. GISAXS alignment involves + vertical translation to the beam center, and rocking theta to get the + sample plane parralel to the beam. Finally, the angle is re-optimized + in reflection mode. + + The 'step' argument can optionally be given to jump to a particular + step in the sequence.""" + # if step<=4: + # if verbosity>=4: + # print(' align: fitting') + + # fit_scan(smy, 1.2, 21, fit='HMi') + # ##time.sleep(2) + # fit_scan(sth, 1.5, 21, fit='max') + ##time.sleep(2) + cms.modeAlignment() + self.yo() + self.tho() + + if step <= 9 and reflection_angle is not None: + # Final alignment using reflected beam + if verbosity >= 4: + print(" align: reflected beam") + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2.0) + # get_beamline().setReflectedBeamROI(total_angle=reflection_angle*2.0, size=[12,2]) + + self.thabs(reflection_angle) + + result = fit_scan(sth, 0.2, 21, fit="max") + # result = fit_scan(sth, 0.2, 81, fit='max') #it's useful for alignment of SmarAct stage + sth_target = result.values["x_max"] - reflection_angle + + if result.values["y_max"] > 50: + th_target = self._axes["th"].motor_to_cur(sth_target) + self.thsetOrigin(th_target) + + # fit_scan(smy, 0.2, 21, fit='max') + # self.setOrigin(['y']) + + if step <= 10: + self.thabs(0.0) + beam.off() + + def align_crazy_v2( + self, step=0, reflection_angle=0.12, ROI_size=[10, 180], th_range=0.3, int_threshold=10, verbosity=3 + ): + + # setting parameters + rel_th = 1 + ct = 0 + cycle = 0 + intenisty_threshold = 10 + + # re-assure the 3 ROI positon + get_beamline().setDirectBeamROI() + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2) + + # set ROI2 as a fixed area + get_beamline().setROI2ReflectBeamROI(total_angle=reflection_angle * 2, size=ROI_size) + pilatus2M.roi2.size.y.set(200) + pilatus2M.roi2.min_xyz.min_y.set(852) + + # def ROI3 in 160pixels with the center located at reflection beam + # get_beamline().setReflectedBeamROI(total_angle = reflection_angle*2, size=ROI_size) #set ROI3 + + # self.thabs(reflection_angle) + if verbosity >= 4: + print(" Aligning {}".format(self.name)) + + if step <= 0: + # Prepare for alignment + + if RE.state != "idle": + RE.abort() + + if get_beamline().current_mode != "alignment": + # if verbosity>=2: + # print("WARNING: Beamline is not in alignment mode (mode is '{}')".format(get_beamline().current_mode)) + print("Switching to alignment mode (current mode is '{}')".format(get_beamline().current_mode)) + get_beamline().modeAlignment() + + get_beamline().setDirectBeamROI() + + beam.on() + + if step <= 2: + if verbosity >= 4: + print(" align: searching") + + # Estimate full-beam intensity + value = None + if True: + # You can eliminate this, in which case RE.md['beam_intensity_expected'] is used by default + self.yr(-0.5) + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + value_name = get_beamline().TABLE_COLS[0] + RE(count([detector])) + value = detector.read()[value_name]["value"] + self.yr(0.5) + + if "beam_intensity_expected" in RE.md: + if value < RE.md["beam_intensity_expected"] * 0.75: + print( + "WARNING: Direct beam intensity ({}) lower than it should be ({})".format( + value, RE.md["beam_intensity_expected"] + ) + ) + + # check the last value: + ii = 0 + while abs(pilatus2M.stats4.total.get() - value) / value < 0.1 and ii < 3: + ii += 1 + # Find the step-edge + self.ysearch( + step_size=0.2, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1 + ) + + # Find the peak + self.thsearch(step_size=0.2, min_step=0.01, target="max", verbosity=verbosity) + + # last check for height + self.ysearch( + step_size=0.05, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1 + ) + + # check reflection beam + self.thr(reflection_angle) + RE(count([detector])) + + if ( + abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) < 20 + and detector.stats2.max_value.get() > intenisty_threshold + ): + + # continue the fast alignment + print("The reflective beam is found! Continue the fast alignment") + + while abs(rel_th) > 0.005 and ct < 5: + # while detector.roi3.max_value.get() > 50 and ct < 5: + + # absolute beam position + refl_beam = detector.roi2.min_xyz.min_y.get() + detector.stats2.max_xy.y.get() + + # roi3 position + roi3_beam = detector.roi3.min_xyz.min_y.get() + detector.roi3.size.y.get() / 2 + + # distance from current postion to the center of roi2 (the disired rel beam position) + # rel_ypos = detector.stats2.max_xy.get().y - detector.stats2.size.get().y + rel_ypos = refl_beam - roi3_beam + + rel_th = rel_ypos / get_beamline().SAXS.distance / 1000 * 0.172 / np.pi * 180 / 2 + + print("The th offset is {}".format(rel_th)) + self.thr(rel_th) + + ct += 1 + RE(count([detector])) + + if detector.stats3.total.get() > 50: + + print("The fast alignment works!") + self.thr(-reflection_angle) + self.setOrigin(["y", "th"]) + + beam.off() + + return True, ii + + else: + print("Alignment Error: Cannot Locate the reflection beam") + self.thr(-reflection_angle) + beam.off() + + return False, ii + + elif abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) > 5: + print("Max and Centroid dont Match!") + + # perform the full alignment + print("Alignment Error: No reflection beam is found!") + self.thr(-reflection_angle) + beam.off() + return False, ii + + else: + print("Intensiy < threshold!") + + # perform the full alignment + print("Alignment Error: No reflection beam is found!") + self.thr(-reflection_angle) + beam.off() + return False, ii + + def align_crazy_v3( + self, step=0, reflection_angle=0.12, ROI_size=[10, 180], th_range=0.3, int_threshold=10, verbosity=3 + ): + + # setting parameters + rel_th = 1 + ct = 0 + cycle = 0 + intenisty_threshold = 10 + + # re-assure the 3 ROI positon + get_beamline().setDirectBeamROI() + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2) + detector = get_beamline().detector[0] + + # set ROI2 as a fixed area + get_beamline().setROI2ReflectBeamROI(total_angle=reflection_angle * 2, size=ROI_size) + pilatus2M.roi2.size.y.set(200) + pilatus2M.roi2.min_xyz.min_y.set(842) + + # def ROI3 in 160pixels with the center located at reflection beam + # get_beamline().setReflectedBeamROI(total_angle = reflection_angle*2, size=ROI_size) #set ROI3 + + # self.thabs(reflection_angle) + if verbosity >= 4: + print(" Aligning {}".format(self.name)) + + if step <= 0: + # Prepare for alignment + + if RE.state != "idle": + RE.abort() + + if get_beamline().current_mode != "alignment": + # if verbosity>=2: + # print("WARNING: Beamline is not in alignment mode (mode is '{}')".format(get_beamline().current_mode)) + print("Switching to alignment mode (current mode is '{}')".format(get_beamline().current_mode)) + get_beamline().modeAlignment() + + get_beamline().setDirectBeamROI() + + beam.on() + + if step <= 2: + + ######################### fast alignment in the case2 and 3 -- NO refl beam + self.thabs(0.12) + self.snap(0.5) + roi2_int = pilatus2M.stats2.total.get() + roi4_int = pilatus2M.stats4.total.get() + threshold = 100 + beam_int = 20000 + target_ratio = 0.5 + beam.on() + if roi2_int < threshold: + + print("CASE 2 or 3") + + roi4_int = pilatus2M.stats4.total.get() + roi2_int = pilatus2M.stats2.total.get() + + roi4_beam = roi4_int / beam_int + + min_step = 0.005 + # if roi4_beam 0.005 and ct < 5: + # while detector.roi3.max_value.get() > 50 and ct < 5: + + print("CASE 2 ") + + # absolute beam position + refl_beam = detector.roi2.min_xyz.min_y.get() + detector.stats2.max_xy.y.get() + + # roi3 position + roi3_beam = detector.roi3.min_xyz.min_y.get() + detector.roi3.size.y.get() / 2 + + # distance from current postion to the center of roi2 (the disired rel beam position) + # rel_ypos = detector.stats2.max_xy.get().y - detector.stats2.size.get().y + rel_ypos = refl_beam - roi3_beam + + rel_th = rel_ypos / get_beamline().SAXS.distance / 1000 * 0.172 / np.pi * 180 / 2 + + print("The th offset is {}".format(rel_th)) + self.thr(rel_th) + + ct += 1 + RE(count([pilatus2M])) + # self.ysearch(step_size=0.01, min_step=0.005, intensity=beam_int, target=0.5, verbosity=verbosity, polarity=-1) + + ######################### fast alignment in the case1 -- both refl and direct beam + target_ratio = 1 + # self.snap() + print("CASE 1") + + def get_roi2_4(): + roi2_int = pilatus2M.stats2.total.get() + roi2_int = roi2_int if roi2_int > 0 else 0 + roi4_int = pilatus2M.stats4.total.get() + roi4_int = roi4_int if roi4_int > 0 else 0 + return roi2_int / (roi4_int + 10) + + roi2_4 = get_roi2_4() + + min_step = 0.005 + while abs(roi2_4 - target_ratio) > 0.2: + print(roi2_4) + if roi2_4 < target_ratio: + # print(" +Y") + step = min_step + else: + # print(" -Y") + step = -min_step + + self.yr(step) + self.snap() + roi2_4 = get_roi2_4() + + if step > 5: + + if verbosity >= 4: + print(" align: searching") + + # Estimate full-beam intensity + value = None + if True: + # You can eliminate this, in which case RE.md['beam_intensity_expected'] is used by default + self.yr(-0.5) + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + value_name = get_beamline().TABLE_COLS[0] + RE(count([detector])) + value = detector.read()[value_name]["value"] + self.yr(0.5) + + if "beam_intensity_expected" in RE.md: + if value < RE.md["beam_intensity_expected"] * 0.75: + print( + "WARNING: Direct beam intensity ({}) lower than it should be ({})".format( + value, RE.md["beam_intensity_expected"] + ) + ) + + # check the last value: + ii = 0 + while abs(pilatus2M.stats4.total.get() - value) / value < 0.1 and ii < 3: + ii += 1 + # Find the step-edge + self.ysearch( + step_size=0.2, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1 + ) + + # Find the peak + self.thsearch(step_size=0.2, min_step=0.01, target="max", verbosity=verbosity) + + # last check for height + self.ysearch( + step_size=0.05, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1 + ) + + if step > 5: + + # check reflection beam + self.thr(reflection_angle) + RE(count([detector])) + + if ( + abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) < 20 + and detector.stats2.max_value.get() > intenisty_threshold + ): + + # continue the fast alignment + print("The reflective beam is found! Continue the fast alignment") + + while abs(rel_th) > 0.005 and ct < 5: + # while detector.roi3.max_value.get() > 50 and ct < 5: + + # absolute beam position + refl_beam = detector.roi2.min_xyz.min_y.get() + detector.stats2.max_xy.y.get() + + # roi3 position + roi3_beam = detector.roi3.min_xyz.min_y.get() + detector.roi3.size.y.get() / 2 + + # distance from current postion to the center of roi2 (the disired rel beam position) + # rel_ypos = detector.stats2.max_xy.get().y - detector.stats2.size.get().y + rel_ypos = refl_beam - roi3_beam + + rel_th = rel_ypos / get_beamline().SAXS.distance / 1000 * 0.172 / np.pi * 180 / 2 + + print("The th offset is {}".format(rel_th)) + self.thr(rel_th) + + ct += 1 + RE(count([detector])) + + # if detector.stats3.total.get()>50: + + # print('The fast alignment works!') + # self.thr(-reflection_angle) + # self.setOrigin(['y', 'th']) + + # beam.off() + + # return True, ii + + # else: + # print('Alignment Error: Cannot Locate the reflection beam') + # self.thr(-reflection_angle) + # beam.off() + + # return False, ii + + # elif abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) > 5: + # print('Max and Centroid dont Match!') + + # #perform the full alignment + # print('Alignment Error: No reflection beam is found!') + # self.thr(-reflection_angle) + # beam.off() + # return False, ii + + # else: + # print('Intensiy < threshold!') + + # #perform the full alignment + # print('Alignment Error: No reflection beam is found!') + # self.thr(-reflection_angle) + # beam.off() + # return False, ii + + def align_crazy_v3_plan( + self, + step=0, + reflection_angle=0.12, + ROI_size=[10, 180], + th_range=0.3, + int_threshold=10, + direct_beam_int=None, + verbosity=3, + detector=None, + detector_suffix=None, + ): + + if detector is None: + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + + # if detector_suffix is None: + # #value_name = gs.TABLE_COLS[0] + # value_name = get_beamline().TABLE_COLS[0] + # else: + # value_name = detector.name + detector_suffix + + motors_for_table = [smx, smy, sth] + + @bpp.stage_decorator([detector]) + @bpp.run_decorator(md={}) + @bpp.finalize_decorator(final_plan=shutter_off) + def inner_align(group=None): + nonlocal step, reflection_angle + + if group: + yield from bps.wait(group) + + # setting parameters + rel_th = 1 + ct = 0 + cycle = 0 + intenisty_threshold = 50 + + # re-assure the 3 ROI positon + get_beamline().setDirectBeamROI() + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2) + detector = get_beamline().detector[0] + + # set ROI2 as a fixed area + get_beamline().setROI2ReflectBeamROI(total_angle=reflection_angle * 2, size=ROI_size) + pilatus2M.roi2.size.y.set(200) + pilatus2M.roi2.min_xyz.min_y.set(842) + + # def ROI3 in 160pixels with the center located at reflection beam + # get_beamline().setReflectedBeamROI(total_angle = reflection_angle*2, size=ROI_size) #set ROI3 + + # self.thabs(reflection_angle) + if verbosity >= 4: + print(" Aligning {}".format(self.name)) + + if step <= 0: + print(f"Step <= 0") + # Prepare for alignment + if get_beamline().current_mode != "alignment": + # if verbosity>=2: + # print("WARNING: Beamline is not in alignment mode (mode is '{}')".format(get_beamline().current_mode)) + print("Switching to alignment mode (current mode is '{}')".format(get_beamline().current_mode)) + yield from get_beamline().modeAlignment() + + get_beamline().setDirectBeamROI() + + yield from shutter_on() + + if direct_beam_int is not None: + value = direct_beam_int + elif hasattr(cms, "direct_beam_int") and cms.direct_beam_int is not None: + value = cms.direct_beam_int + else: + value = 0 + # You can eliminate this, in which case RE.md['beam_intensity_expected'] is used by default + for n in range(1, 4): + self.yr(-0.5) + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + value_name = get_beamline().TABLE_COLS[0] + yield from bps.trigger_and_read([detector, *motors_for_table]) + value = detector.read()[value_name]["value"] + if value > 100: + cms.direct_beam_int = value + self.yr(0.5) + break + + + if "beam_intensity_expected" in RE.md: + if value < RE.md["beam_intensity_expected"] * 0.75: + print( + "WARNING: Direct beam intensity ({}) lower than it should be ({})".format( + value, RE.md["beam_intensity_expected"] + ) + ) + + if step <= 2: + print("Step <= 2") + + ######################### fast alignment in the case2 and 3 -- NO refl beam + self.thabs(0.12) + # self.snap(0.5) + yield from bps.trigger_and_read([detector, *motors_for_table]) + roi2_int = pilatus2M.stats2.total.get() + roi4_int = pilatus2M.stats4.total.get() + threshold = 500 + beam_int = value + target_ratio = 0.5 + # yield from shutter_on() + print(f"roi2_int={roi2_int} threshold={threshold}") + + if roi2_int < threshold: + + print("CASE 2 or 3") + + roi4_int = pilatus2M.stats4.total.get() + roi2_int = pilatus2M.stats2.total.get() + + roi4_beam = roi4_int / beam_int + + min_step = 0.005 + # if roi4_beam 0 and norm_stats4 > 0.2: + break + + # Find the step-edge + yield from self.search_stub2( + motor=smy, + step_size=0.2, + min_step=0.005, + target=0.5, + intensity=beam_int, + polarity=-1, + detector=detector, + detector_suffix="_stats4_total", + ) + + yield from self.search_stub2( + motor=sth, + step_size=0.2, + min_step=0.01, + target="max", + polarity=-1, + detector=detector, + detector_suffix="_stats4_total", + ) + + # self.ysearch(step_size=0.2, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1) + + # # Find the peak + # self.thsearch(step_size=0.2, min_step=0.01, target='max', verbosity=verbosity) + + # last check for height + # self.ysearch(step_size=0.05, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1) + yield from self.search_stub2( + motor=smy, + step_size=0.05, + min_step=0.005, + target=0.5, + intensity=beam_int, + polarity=-1, + detector=detector, + detector_suffix="_stats4_total", + ) + + # self.ysearch(step_size=0.01, min_step=0.005, intensity=beam_int, target=0.5, verbosity=verbosity, polarity=-1) + # else: + # print(' -Y') + # self.ysearch(step_size=0.01, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1) + + roi4_beam = roi4_int / beam_int + roi2_int = pilatus2M.stats2.total.get() + + else: + #very close to aligned position + reflection_angle = 0 + # #use the beam heigh to find the correct refl beam + # print('Search the refl beam') + # yield from bps.trigger_and_read([detector, *motors_for_table]) + # # RE(count([pilatus2M])) + + # roi4_beam = roi4_int/beam_int + # roi2_int = pilatus2M.stats2.total.get() + # # roi2_int = roi2_i + # th_step = 0.1 + + # while roi2_int 0.005 and ct < 5: + # # while detector.roi3.max_value.get() > 50 and ct < 5: + + # print("CASE 2 ") + + # #absolute beam position + # refl_beam = detector.roi2.min_xyz.min_y.get() + detector.stats2.max_xy.y.get() + + # #roi3 position + # roi3_beam = detector.roi3.min_xyz.min_y.get() + detector.roi3.size.y.get()/2 + + # #distance from current postion to the center of roi2 (the disired rel beam position) + # # rel_ypos = detector.stats2.max_xy.get().y - detector.stats2.size.get().y + # rel_ypos = refl_beam - roi3_beam + + # rel_th = rel_ypos/get_beamline().SAXS.distance/1000*0.172/np.pi*180/2 + + # print('The th offset is {}'.format(rel_th)) + # self.thr(rel_th) + + # ct += 1 + # yield from bps.trigger_and_read([detector, *motors_for_table]) + # # RE(count([pilatus2M])) + # # self.ysearch(step_size=0.01, min_step=0.005, intensity=beam_int, target=0.5, verbosity=verbosity, polarity=-1) + + ######################### fast alignment in the case1 -- both refl and direct beam + + # self.thr(reflection_angle) + # yield from bps.trigger_and_read([detector, *motors_for_table]) + # RE(count([detector])) + + # # if abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) < 20 and detector.stats2.max_value.get() > intenisty_threshold: + + # target_ratio = 1 + # # self.snap() + # print("CASE 1") + + # def get_roi2_4(): + # roi2_int = pilatus2M.stats2.total.get() + # roi2_int = roi2_int if roi2_int > 0 else 0 + # roi4_int = pilatus2M.stats4.total.get() + # roi4_int = roi4_int if roi4_int > 0 else 0 + # return roi2_int/(roi4_int + 10) + + # roi2_4 = get_roi2_4() + + # min_step=0.005 + # while abs(roi2_4 - target_ratio)>0.2: + # print(roi2_4) + # if roi2_45: + + # if verbosity>=4: + # print(' align: searching') + + # # Estimate full-beam intensity + # value = None + # if True: + # # You can eliminate this, in which case RE.md['beam_intensity_expected'] is used by default + # self.yr(-0.5) + # #detector = gs.DETS[0] + # detector = get_beamline().detector[0] + # value_name = get_beamline().TABLE_COLS[0] + # yield from bps.trigger_and_read([detector, *motors_for_table]) + # # RE(count([detector])) + # value = detector.read()[value_name]['value'] + # self.yr(0.5) + + # if 'beam_intensity_expected' in RE.md: + # if value intenisty_threshold): + + # continue the fast alignment + print("The reflective beam is found! Continue the fast alignment") + + while abs(rel_th) > 0.005 and ct < 5: + # while detector.roi3.max_value.get() > 50 and ct < 5: + + # absolute beam position + refl_beam = detector.roi2.min_xyz.min_y.get() + detector.stats2.max_xy.y.get() + + # roi3 position + roi3_beam = detector.roi3.min_xyz.min_y.get() + detector.roi3.size.y.get() / 2 + + # distance from current postion to the center of roi2 (the disired rel beam position) + # rel_ypos = detector.stats2.max_xy.get().y - detector.stats2.size.get().y + rel_ypos = refl_beam - roi3_beam + + rel_th = rel_ypos / get_beamline().SAXS.distance / 1000 * 0.172 / np.pi * 180 / 2 + + print("The th offset is {}".format(rel_th)) + self.thr(rel_th) + + ct += 1 + yield from bps.trigger_and_read([detector, *motors_for_table]) + # RE(count([detector])) + + # if detector.stats3.total.get()>50: + + # print('The fast alignment works!') + # self.thr(-reflection_angle) + # self.setOrigin(['y', 'th']) + + # beam.off() + + # return True, ii + + # else: + # print('Alignment Error: Cannot Locate the reflection beam') + # self.thr(-reflection_angle) + # beam.off() + + # return False, ii + + # elif abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) > 5: + # print('Max and Centroid dont Match!') + + # #perform the full alignment + # print('Alignment Error: No reflection beam is found!') + # self.thr(-reflection_angle) + # beam.off() + # return False, ii + + # else: + # print('Intensiy < threshold!') + + # #perform the full alignment + # print('Alignment Error: No reflection beam is found!') + # self.thr(-reflection_angle) + # beam.off() + # return False, ii + + group_name = "setup_aligment" + + #alignment mode + yield from bps.abs_set(bsx, cms.bsx_pos + 3, group=group_name) + beam.setTransmission(1e-6) + + #align as abovve + yield from inner_align(group=group_name) + + #move bs back + yield from bps.abs_set(bsx, cms.bsx_pos, group=group_name) + yield from bps.wait(group_name) + + #set the position for sample + # self.thr(reflection_angle) + # self.setOrigin(['y', 'th']) + + def swing_v2( + self, step=0, reflection_angle=0.12, ROI_size=[10, 180], th_range=0.3, int_threshold=10, verbosity=3 + ): + + # setting parameters + rel_th = 1 + ct = 0 + cycle = 0 + intenisty_threshold = 10 + + # re-assure the 3 ROI positon + get_beamline().setDirectBeamROI() + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2) + + # set ROI2 as a fixed area + get_beamline().setROI2ReflectBeamROI(total_angle=reflection_angle * 2, size=ROI_size) + pilatus2M.roi2.size.y.set(190) + pilatus2M.roi2.min_xyz.min_y.set(852) + + # def ROI3 in 160pixels with the center located at reflection beam + # get_beamline().setReflectedBeamROI(total_angle = reflection_angle*2, size=ROI_size) #set ROI3 + + # self.thabs(reflection_angle) + if verbosity >= 4: + print(" Aligning {}".format(self.name)) + + # if step<=0: + # # Prepare for alignment + + # if RE.state!='idle': + # RE.abort() + + # if get_beamline().current_mode!='alignment': + # #if verbosity>=2: + # #print("WARNING: Beamline is not in alignment mode (mode is '{}')".format(get_beamline().current_mode)) + # print("Switching to alignment mode (current mode is '{}')".format(get_beamline().current_mode)) + # get_beamline().modeAlignment() + + get_beamline().setDirectBeamROI() + + beam.on() + + if step <= 2: + # if verbosity>=4: + # print(' align: searching') + + # Estimate full-beam intensity + value = None + if True: + # You can eliminate this, in which case RE.md['beam_intensity_expected'] is used by default + self.yr(-0.5) + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + # value_name = get_beamline().TABLE_COLS[0] + beam.on() + RE(count([detector])) + value = detector.read()["pilatus2M_stats4_total"]["value"] + self.yr(0.5) + + # if 'beam_intensity_expected' in RE.md: + # if value intenisty_threshold + ): + + # continue the fast alignment + print("The reflective beam is found! Continue the fast alignment") + + while abs(rel_th) > 0.005 and ct < 5: + # while detector.roi3.max_value.get() > 50 and ct < 5: + + # absolute beam position + refl_beam = detector.roi2.min_xyz.min_y.get() + detector.stats2.max_xy.y.get() + + # roi3 position + roi3_beam = detector.roi3.min_xyz.min_y.get() + detector.roi3.size.y.get() / 2 + + # distance from current postion to the center of roi2 (the disired rel beam position) + # rel_ypos = detector.stats2.max_xy.get().y - detector.stats2.size.get().y + rel_ypos = refl_beam - roi3_beam + + rel_th = rel_ypos / get_beamline().SAXS.distance / 1000 * 0.172 / np.pi * 180 / 2 + + print("The th offset is {}".format(rel_th)) + self.thr(rel_th) + + ct += 1 + RE(count([detector])) + + if detector.stats3.total.get() > 50: + + print("The fast alignment works!") + self.thr(-reflection_angle) + + if fastsearch == False: + RE( + self.search_plan( + motor=smy, + step_size=0.05, + min_step=0.005, + target=0.5, + intensity=20000, + polarity=-1, + detector_suffix="_stats4_total", + ) + ) + + self.setOrigin(["y", "th"]) + + beam.off() + + return True, ii + + else: + print("Alignment Error: Cannot Locate the reflection beam") + self.thr(-reflection_angle) + beam.off() + + return False, ii + + elif abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) > 5: + print("Max and Centroid dont Match!") + + # perform the full alignment + print("Alignment Error: No reflection beam is found!") + self.thr(-reflection_angle) + beam.off() + return False, ii + + else: + print("Intensiy < threshold!") + + # perform the full alignment + print("Alignment Error: No reflection beam is found!") + self.thr(-reflection_angle) + beam.off() + return False, ii + + def swing_March( + self, step=0, reflection_angle=0.12, ROI_size=[10, 180], th_range=0.3, intensity=20000, int_threshold=10, verbosity=3 + ): + + # setting parameters + rel_th = 1 + ct = 0 + cycle = 0 + intenisty_threshold = 10 + + # re-assure the 3 ROI positon + get_beamline().setDirectBeamROI() + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2) + + # set ROI2 as a fixed area + get_beamline().setROI2ReflectBeamROI(total_angle=reflection_angle * 2, size=ROI_size) + pilatus2M.roi2.size.y.set(190) + pilatus2M.roi2.min_xyz.min_y.set(852) + + # def ROI3 in 160pixels with the center located at reflection beam + # get_beamline().setReflectedBeamROI(total_angle = reflection_angle*2, size=ROI_size) #set ROI3 + + # self.thabs(reflection_angle) + if verbosity >= 4: + print(" Aligning {}".format(self.name)) + + # if step<=0: + # # Prepare for alignment + + # if RE.state!='idle': + # RE.abort() + + # if get_beamline().current_mode!='alignment': + # #if verbosity>=2: + # #print("WARNING: Beamline is not in alignment mode (mode is '{}')".format(get_beamline().current_mode)) + # print("Switching to alignment mode (current mode is '{}')".format(get_beamline().current_mode)) + # get_beamline().modeAlignment() + + get_beamline().setDirectBeamROI() + + beam.on() + + if step <= 2: + # if verbosity>=4: + # print(' align: searching') + + # Estimate full-beam intensity + value = None + if True: + # You can eliminate this, in which case RE.md['beam_intensity_expected'] is used by default + # self.yr(-0.5) + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + # value_name = get_beamline().TABLE_COLS[0] + beam.on() + RE(count([detector])) + value = detector.read()["pilatus2M_stats4_total"]["value"] + # self.yr(0.5) + + # if 'beam_intensity_expected' in RE.md: + # if value intenisty_threshold + ): + + # continue the fast alignment + print("The reflective beam is found! Continue the fast alignment") + + #for sth + while abs(rel_th) > 0.005 and ct < 5: + # while detector.roi3.max_value.get() > 50 and ct < 5: + + # absolute beam position + refl_beam = detector.roi2.min_xyz.min_y.get() + detector.stats2.max_xy.y.get() + + # roi3 position + roi3_beam = detector.roi3.min_xyz.min_y.get() + detector.roi3.size.y.get() / 2 + + # distance from current postion to the center of roi2 (the disired rel beam position) + # rel_ypos = detector.stats2.max_xy.get().y - detector.stats2.size.get().y + rel_ypos = refl_beam - roi3_beam + + rel_th = rel_ypos / get_beamline().SAXS.distance / 1000 * 0.172 / np.pi * 180 / 2 + + print("The th offset is {}".format(rel_th)) + self.thr(rel_th) + + ct += 1 + RE(count([detector])) + + #for smy + # Find the step-edge + fastsearch = RE( + self.search_plan( + motor=smy, + step_size=0.05, + min_step=0.01, + target="max", + # intensity=intensity, + polarity=-1, + # fastsearch=True, + detector_suffix="_stats3_total", + ) + ) + + + # if detector.stats3.total.get() > 50: + + # print("The fast alignment works!") + # self.thr(-reflection_angle) + + # if fastsearch == False: + # RE( + # self.search_plan( + # motor=smy, + # step_size=0.05, + # min_step=0.005, + # target=0.5, + # intensity=20000, + # polarity=-1, + # detector_suffix="_stats4_total", + # ) + # ) + + self.setOrigin(["y", "th"]) + + beam.off() + + return True, ii + + # else: + # print("Alignment Error: Cannot Locate the reflection beam") + # self.thr(-reflection_angle) + # beam.off() + + # return False, ii + + # elif abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) > 5: + # print("Max and Centroid dont Match!") + + # # perform the full alignment + # print("Alignment Error: No reflection beam is found!") + # self.thr(-reflection_angle) + # beam.off() + # return False, ii + + # else: + # print("Intensiy < threshold!") + + # # perform the full alignment + # print("Alignment Error: No reflection beam is found!") + # self.thr(-reflection_angle) + # beam.off() + # return False, ii + + def swing( + self, step=0, reflection_angle=0.12, ROI_size=[10, 180], th_range=0.3, int_threshold=10, verbosity=3 + ): + + # setting parameters + rel_th = 1 + ct = 0 + cycle = 0 + intenisty_threshold = 10 + + # re-assure the 3 ROI positon + get_beamline().setDirectBeamROI() + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2) + + # set ROI2 as a fixed area + get_beamline().setROI2ReflectBeamROI(total_angle=reflection_angle * 2, size=ROI_size) + pilatus2M.roi2.size.y.set(190) + pilatus2M.roi2.min_xyz.min_y.set(852) + + # def ROI3 in 160pixels with the center located at reflection beam + # get_beamline().setReflectedBeamROI(total_angle = reflection_angle*2, size=ROI_size) #set ROI3 + + # self.thabs(reflection_angle) + if verbosity >= 4: + print(" Aligning {}".format(self.name)) + + # if step<=0: + # # Prepare for alignment + + # if RE.state!='idle': + # RE.abort() + + # if get_beamline().current_mode!='alignment': + # #if verbosity>=2: + # #print("WARNING: Beamline is not in alignment mode (mode is '{}')".format(get_beamline().current_mode)) + # print("Switching to alignment mode (current mode is '{}')".format(get_beamline().current_mode)) + # get_beamline().modeAlignment() + + get_beamline().setDirectBeamROI() + + RE(beam.on()) + + if step <= 2: + # if verbosity>=4: + # print(' align: searching') + + # Estimate full-beam intensity + value = None + if True: + # You can eliminate this, in which case RE.md['beam_intensity_expected'] is used by default + self.yr(-1) + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + # value_name = get_beamline().TABLE_COLS[0] + RE(beam.on()) + RE(count([detector])) + value = detector.read()["pilatus2M_stats4_total"]["value"] + self.yr(1) + + # if 'beam_intensity_expected' in RE.md: + # if value intenisty_threshold + ): + + # continue the fast alignment + print("The reflective beam is found! Continue the fast alignment") + + while abs(rel_th) > 0.005 and ct < 5: + # while detector.roi3.max_value.get() > 50 and ct < 5: + + # absolute beam position + refl_beam = detector.roi2.min_xyz.min_y.get() + detector.stats2.max_xy.y.get() + + # roi3 position + roi3_beam = detector.roi3.min_xyz.min_y.get() + detector.roi3.size.y.get() / 2 + + # distance from current postion to the center of roi2 (the disired rel beam position) + # rel_ypos = detector.stats2.max_xy.get().y - detector.stats2.size.get().y + rel_ypos = refl_beam - roi3_beam + + rel_th = rel_ypos / get_beamline().SAXS.distance / 1000 * 0.172 / np.pi * 180 / 2 + + print("The th offset is {}".format(rel_th)) + self.thr(rel_th) + + ct += 1 + RE(count([detector])) + + if detector.stats3.total.get() > 50: + + print("The fast alignment works!") + self.thr(-reflection_angle) + + self.setOrigin(["y", "th"]) + + beam.off() + + return True, ii + + else: + print("Alignment Error: Cannot Locate the reflection beam") + self.thr(-reflection_angle) + beam.off() + + return False, ii + + elif abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) > 5: + print("Max and Centroid dont Match!") + + # perform the full alignment + print("Alignment Error: No reflection beam is found!") + self.thr(-reflection_angle) + beam.off() + return False, ii + + else: + print("Intensiy < threshold!") + + # perform the full alignment + print("Alignment Error: No reflection beam is found!") + self.thr(-reflection_angle) + beam.off() + return False, ii + + def crazy_th( + self, step=0, reflection_angle=0.12, ROI_size=[10, 180], th_range=0.3, int_threshold=10, verbosity=3 + ): + + # setting parameters + rel_th = 1 + ct = 0 + cycle = 0 + intenisty_threshold = 10 + + # re-assure the 3 ROI positon + get_beamline().setDirectBeamROI() + get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2) + + # set ROI2 as a fixed area + get_beamline().setROI2ReflectBeamROI(total_angle=reflection_angle * 2, size=ROI_size) + pilatus2M.roi2.size.y.set(200) + pilatus2M.roi2.min_xyz.min_y.set(852) + + # def ROI3 in 160pixels with the center located at reflection beam + # get_beamline().setReflectedBeamROI(total_angle = reflection_angle*2, size=ROI_size) #set ROI3 + + # self.thabs(reflection_angle) + if verbosity >= 4: + print(" Aligning {}".format(self.name)) + + if step <= 0: + # Prepare for alignment + + if RE.state != "idle": + RE.abort() + + if get_beamline().current_mode != "alignment": + # if verbosity>=2: + # print("WARNING: Beamline is not in alignment mode (mode is '{}')".format(get_beamline().current_mode)) + print("Switching to alignment mode (current mode is '{}')".format(get_beamline().current_mode)) + get_beamline().modeAlignment() + + get_beamline().setDirectBeamROI() + + beam.on() + + detector = pilatus2M + RE(pilatus2M.setExposureTime(0.5)) + self.thabs(reflection_angle) + RE(count([detector])) + + if ( + abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) < 20 + and detector.stats2.max_value.get() > intenisty_threshold + ): + + # continue the fast alignment + print("The reflective beam is found! Continue the fast alignment") + + while abs(rel_th) > 0.005 and ct < 5: + # while detector.roi3.max_value.get() > 50 and ct < 5: + + # absolute beam position + refl_beam = detector.roi2.min_xyz.min_y.get() + detector.stats2.max_xy.y.get() + + # roi3 position + roi3_beam = detector.roi3.min_xyz.min_y.get() + detector.roi3.size.y.get() / 2 + + # distance from current postion to the center of roi2 (the disired rel beam position) + # rel_ypos = detector.stats2.max_xy.get().y - detector.stats2.size.get().y + rel_ypos = refl_beam - roi3_beam + + rel_th = rel_ypos / get_beamline().SAXS.distance / 1000 * 0.172 / np.pi * 180 / 2 + + print("The th offset is {}".format(rel_th)) + self.thr(rel_th) + + ct += 1 + RE(count([detector])) + + if detector.stats3.total.get() > 50: + + print("The fast alignment works!") + self.thr(-reflection_angle) + self.setOrigin(["y", "th"]) + + beam.off() + + return True, ii + + else: + print("Alignment Error: Cannot Locate the reflection beam") + self.thr(-reflection_angle) + beam.off() + + return False, ii + + elif abs(detector.stats2.max_xy.get().y - detector.stats2.centroid.get().y) > 5: + print("Max and Centroid dont Match!") + + # perform the full alignment + print("Alignment Error: No reflection beam is found!") + self.thr(-reflection_angle) + beam.off() + return False, ii + + else: + print("Intensiy < threshold!") + + # perform the full alignment + print("Alignment Error: No reflection beam is found!") + self.thr(-reflection_angle) + beam.off() + return False, ii + + def measureInitial(self, exposure_time=10, bounds=[0, 50]): + + pos_list = np.meshgrid(bounds[0], bounds[1], 2) + # pos_list.append([np.average(bounds),np.average(bounds)]) + command["out_of_bound"] = False + + for x_pos, y_pos in pos_list: + start_time = time.time() + if verbosity >= 3: + print( + "{}Driving to point {}/{}; (x,yy) = ({:.3f}, {:.3f})".format( + prefix, imeasure, num_to_measure, x_pos, yy_pos + ) + ) + + self.xabs(x_pos) + # self.yabs(y_pos) + self.yyabs(yy_pos) + + while smx.moving == True or smy2.moving == True: + time.sleep(1) + while abs(self.xpos(verbosity=0) - x_pos) > 0.1 or abs(self.yypos(verbosity=0) - yy_pos) > 0.1: + time.sleep(1) + + self.measure(exposure_time=exposure_time, extra=extra, **md) + header = db[-1] # The most recent measurement + # command['filename'] = '{}'.format(header.start['filename'][:-1]) + command["filename"] = "{}".format(header.start["filename"]) + command["x_position"] = self.xpos(verbosity=0) + command["y_position"] = self.yypos(verbosity=0) + command["h1_position"] = self.xy2h(self.xpos(), self.yypos())[0] + command["h2_position"] = self.xy2h(self.xpos(), self.yypos())[1] + + cost_time = time.time() - start_time + + command["cost"] = cost_time + + command["h1_para"] = self.para1 + command["h2_para"] = self.para2 + + command["measured"] = True + command["analyzed"] = False + + measure_queue.publish(commands) # Send results for analysis + + def search_plan( + self, + motor=smy, + step_size=0.2, + min_step=0.05, + intensity=None, + target=0.5, + detector=None, + detector_suffix=None, + polarity=-1, + verbosity=3, + ): + """Moves this axis, searching for a target value. + + Parameters + ---------- + step_size : float + The initial step size when moving the axis + min_step : float + The final (minimum) step size to try + intensity : float + The expected full-beam intensity readout + target : 0.0 to 1.0 + The target ratio of full-beam intensity; 0.5 searches for half-max. + The target can also be 'max' to find a local maximum. + detector, detector_suffix + The beamline detector (and suffix, such as '_stats4_total') to trigger to measure intensity + polarity : +1 or -1 + Positive motion assumes, e.g. a step-height 'up' (as the axis goes more positive) + """ + print("HERE!!") + + if detector is None: + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + if detector_suffix is None: + # value_name = gs.TABLE_COLS[0] + value_name = get_beamline().TABLE_COLS[0] + else: + value_name = detector.name + detector_suffix + + print(f"detector={detector}") + + @bpp.stage_decorator([detector]) + @bpp.run_decorator(md={}) + def inner_search(): + nonlocal intensity, target, step_size + + if not get_beamline().beam.is_on(): + print("WARNING: Experimental shutter is not open.") + + if intensity is None: + intensity = RE.md["beam_intensity_expected"] + + # bec.disable_table() + + # Check current value + vv = yield from bps.trigger_and_read([detector, motor]) + value = vv[value_name]["value"] + # RE(count([detector])) + # value = detector.read()[value_name]['value'] + + if target == "max": + + if verbosity >= 5: + print("Performing search on axis '{}' target is 'max'".format(self.name)) + + max_value = value + # max_position = self.get_position(verbosity=0) + + direction = +1 * polarity + + while step_size >= min_step: + if verbosity >= 4: + print(" move {} by {} × {}".format(self.name, direction, step_size)) + + # pos = yield from bps.rd(motor) + yield from bps.mvr(motor, direction * step_size) + # self.move_relative(move_amount=direction*step_size, verbosity=verbosity-2) + + prev_value = value + yield from bps.trigger_and_read([detector, motor]) + # RE(count([detector])) + + value = detector.read()[value_name]["value"] + # if verbosity>=3: + # print(" {} = {:.3f} {}; value : {}".format(self.name, self.get_position(verbosity=0), self.units, value)) + + if value > max_value: + max_value = value + # max_position = self.get_position(verbosity=0) + + if value > prev_value: + # Keep going in this direction... + pass + else: + # Switch directions! + direction *= -1 + step_size *= 0.5 + + elif target == "min": + + if verbosity >= 5: + print("Performing search on axis '{}' target is 'min'".format(self.name)) + + direction = +1 * polarity + + while step_size >= min_step: + if verbosity >= 4: + print(" move {} by {} × {}".format(self.name, direction, step_size)) + + # pos = yield from bps.rd(motor) + yield from bps.mvr(motor, direction * step_size) + # self.move_relative(move_amount=direction*step_size, verbosity=verbosity-2) + + prev_value = value + yield from bps.trigger_and_read([detector, motor]) + # RE(count([detector])) + value = detector.read()[value_name]["value"] + if verbosity >= 3: + print( + " {} = {:.3f} {}; value : {}".format( + self.name, self.get_position(verbosity=0), self.units, value + ) + ) + + if value < prev_value: + # Keep going in this direction... + pass + else: + # Switch directions! + direction *= -1 + step_size *= 0.5 + + else: + + target_rel = target + target = target_rel * intensity + + if verbosity >= 5: + print( + "Performing search on axis '{}' target {} × {} = {}".format( + self.name, target_rel, intensity, target + ) + ) + if verbosity >= 4: + print(" value : {} ({:.1f}%)".format(value, 100.0 * value / intensity)) + + # Determine initial motion direction + if value > target: + direction = -1 * polarity + else: + direction = +1 * polarity + + while step_size >= min_step: + + if verbosity >= 4: + print(" move {} by {} × {}".format(self.name, direction, step_size)) + + # pos = yield from bps.rd(motor) + yield from bps.mvr(motor, direction * step_size) + # self.move_relative(move_amount=direction*step_size, verbosity=verbosity-2) + + yield from bps.trigger_and_read([detector, motor]) + # RE(count([detector])) + value = detector.read()[value_name]["value"] + # if verbosity>=3: + # print(" {} = {:.3f} {}; value : {} ({:.1f}%)".format(self.name, self.get_position(verbosity=0), self.units, value, 100.0*value/intensity)) + + # Determine direction + if value > target: + new_direction = -1.0 * polarity + else: + new_direction = +1.0 * polarity + + if abs(direction - new_direction) < 1e-4: + # Same direction as we've been going... + # ...keep moving this way + pass + else: + # Switch directions! + direction *= -1 + step_size *= 0.5 + + # bec.enable_table() + + yield from inner_search() + + def search_stub2( + self, + motor=smy, + step_size=1.0, + min_step=0.05, + intensity=None, + target=0.5, + detector=None, + detector_suffix=None, + polarity=1, + verbosity=3, + ): + + if detector is None: + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + if detector_suffix is None: + # value_name = gs.TABLE_COLS[0] + value_name = get_beamline().TABLE_COLS[0] + else: + value_name = detector.name + detector_suffix + + if intensity is None: + intensity = RE.md["beam_intensity_expected"] + + motors_for_table = [smx, smy, sth] + + # Check current value + vv = yield from bps.trigger_and_read([detector, *motors_for_table]) + value = vv[value_name]["value"] + + if target == "max": + + if verbosity >= 5: + print("Performing search on axis '{}' target is 'max'".format(self.name)) + + max_value = value + # max_position = self.get_position(verbosity=0) + + direction = polarity + + while step_size >= min_step: + if verbosity >= 4: + print(" move {} by {} × {}".format(self.name, direction, step_size)) + + yield from bps.mvr(motor, direction * step_size) + + prev_value = value + yield from bps.trigger_and_read([detector, *motors_for_table]) + + value = detector.read()[value_name]["value"] + # if verbosity>=3: + # print(" {} = {:.3f} {}; value : {}".format(self.name, self.get_position(verbosity=0), self.units, value)) + + if value > max_value: + max_value = value + # max_position = self.get_position(verbosity=0) + + if value > prev_value: + # Keep going in this direction... + pass + else: + # Switch directions! + direction *= -1 + step_size *= 0.5 + + elif target == "min": + + if verbosity >= 5: + print("Performing search on axis '{}' target is 'min'".format(self.name)) + + direction = +1 * polarity + + while step_size >= min_step: + if verbosity >= 4: + print(" move {} by {} × {}".format(self.name, direction, step_size)) + + # pos = yield from bps.rd(motor) + yield from bps.mvr(motor, direction * step_size) + # self.move_relative(move_amount=direction*step_size, verbosity=verbosity-2) + + prev_value = value + yield from bps.trigger_and_read([detector, *motors_for_table]) + value = detector.read()[value_name]["value"] + if verbosity >= 3: + print( + " {} = {:.3f} {}; value : {}".format( + self.name, self.get_position(verbosity=0), self.units, value + ) + ) + + if value < prev_value: + # Keep going in this direction... + pass + else: + # Switch directions! + direction *= -1 + step_size *= 0.5 + + else: + + target_rel = target + target = target_rel * intensity + + if verbosity >= 5: + print( + "Performing search on axis '{}' target {} × {} = {}".format( + self.name, target_rel, intensity, target + ) + ) + if verbosity >= 4: + print(" value : {} ({:.1f}%)".format(value, 100.0 * value / intensity)) + + # Determine initial motion direction + if value > target: + direction = -1 * polarity + else: + direction = +1 * polarity + + while step_size >= min_step: + + if verbosity >= 4: + print(" move {} by {} × {}".format(self.name, direction, step_size)) + + yield from bps.mvr(motor, direction * step_size) + + yield from bps.trigger_and_read([detector, *motors_for_table]) + value = detector.read()[value_name]["value"] + # if verbosity>=3: + # print(" {} = {:.3f} {}; value : {} ({:.1f}%)".format(self.name, self.get_position(verbosity=0), self.units, value, 100.0*value/intensity)) + + # Determine direction + if value > target: + new_direction = -1.0 * polarity + else: + new_direction = +1.0 * polarity + + if abs(direction - new_direction) < 1e-4: + # Same direction as we've been going... + # ...keep moving this way + pass + else: + # Switch directions! + direction *= -1 + step_size *= 0.5 + + # bec.enable_table() + + # def calc_lookuptable(self,target_x): + # #make a look up table for + + # start_x = self.start_x + # start_y = self.start_y + # start_th = self.start_th + + # end_x = self.end_x + # end_y = self.end_y + # end_th = self.end_th + + # target_y = (target_x-end_x)/(start_x-end_x)*(start_y-end_y)+end_y + # target_th = (target_x-end_x)/(start_x-end_x)*(start_th-end_th)+end_th + + # return target_x, target_y, target_th + + def run_initial_alignment(self,start_x=60, end_x=30, direct_beam_int=None): + #make a look up table for + + yield from bps.mv(smx, 28.67) + yield from bps.mv(laserx, 0) + + yield from move_sample_with_laser(end_x) + yield from bps.mv(smy, 25.5) + # yield from bps.mv(smx, start_x) + yield from self.align_crazy_v3_plan(direct_beam_int=direct_beam_int) + # yield from self.align() + + end_x = smx.position + end_y = smy.position + end_th = sth.position + + self.end_x = end_x + self.end_y = end_y + self.end_th = end_th + + # yield from bps.mv(smx, end_x) + yield from move_sample_with_laser(start_x) + yield from bps.mv(smy, 24.5) + yield from self.align_crazy_v3_plan(direct_beam_int=direct_beam_int) + # yield from self.align() + + + start_x = smx.position + start_y = smy.position + start_th = sth.position + self.start_x = start_x + self.start_y = start_y + self.start_th = start_th + # start_x = self.start_x + # start_y = self.start_y + # start_th = self.start_th + + # end_x = self.end_x + # end_y = self.end_y + # end_th = self.end_th + # return self.calc_lookuptable() + + def calc_lookuptable(self, target_x): + + start_x = self.start_x + start_y = self.start_y + start_th = self.start_th + + end_x = self.end_x + end_y = self.end_y + end_th = self.end_th + + target_y = (target_x-end_x)/(start_x-end_x)*(start_y-end_y)+end_y + target_th = (target_x-end_x)/(start_x-end_x)*(start_th-end_th)+end_th + + return target_x, target_y, target_th + + + def align_lookup(self, target_x, direct_beam_int=None): + + xpos, ypos, thpos = self.calc_lookuptable(target_x) + + #move to the position in lookup table + yield from bps.mv(smx, xpos, smy, ypos, sth, thpos) + + yield from self.align_crazy_v3_plan(direct_beam_int=direct_beam_int) + + + + + def search_plan2( + self, + motor=smy, + step_size=0.2, + min_step=0.05, + intensity=None, + target=0.5, + detector=None, + detector_suffix=None, + polarity=-1, + verbosity=3, + ): + """Moves this axis, searching for a target value. + + Parameters + ---------- + step_size : float + The initial step size when moving the axis + min_step : float + The final (minimum) step size to try + intensity : float + The expected full-beam intensity readout + target : 0.0 to 1.0 + The target ratio of full-beam intensity; 0.5 searches for half-max. + The target can also be 'max' to find a local maximum. + detector, detector_suffix + The beamline detector (and suffix, such as '_stats4_total') to trigger to measure intensity + polarity : +1 or -1 + Positive motion assumes, e.g. a step-height 'up' (as the axis goes more positive) + """ + + if detector is None: + # detector = gs.DETS[0] + detector = get_beamline().detector[0] + + @bpp.stage_decorator([detector]) + @bpp.run_decorator(md={}) + @bpp.finalize_decorator(final_plan=shutter_off) + def inner_search(group=None): + nonlocal intensity, target, step_size + + if not get_beamline().beam.is_on(): + print("WARNING: Experimental shutter is not open.") + + if intensity is None: + intensity = RE.md["beam_intensity_expected"] + + if group: + yield from bps.wait(group) + + yield from shutter_on() + + yield from self.search_stub2( + motor=motor, + step_size=step_size, + min_step=min_step, + intensity=intensity, + target=target, + detector=detector, + detector_suffix=detector_suffix, + polarity=polarity, + verbosity=verbosity, + ) + + group_name = "setup_aligment" + yield from bps.abs_set(bsx, cms.bsx_pos + 3, group=group_name) + # beam.setTransmission(1e-6) + + yield from inner_search(group=group_name) + + yield from bps.abs_set(bsx, cms.bsx_pos, group=group_name) + yield from bps.wait(group_name) + + def measureAutonomous( + self, + runno=0, + exposure_time=10, + extra=None, + max_measurements=600000, + prefix="measureAutonomous > ", + verbosity=3, + **md, + ): + """Measure points in a loop, relying on an external queue to specify what + position to actually measure. If the 'position' is not (x,y) sample coordinates, + then you will have to add code to do the appropriate coordinate conversion, + or trigger the right beamline motors/components.""" + + for i in range(runno, max_measurements): + + if verbosity >= 3: + print("{}Waiting for AE command on queue...".format(prefix)) + + # forceload_repeat = 0 + # if forceLoad == True: + # commands = measure_queue.get() + # forceload_repeat = 1 + # elif forceLoad == False or forceload_repeat == 1: + commands = measure_queue.get() # Get measurement command from queue + num_to_measure = sum([1.0 for command in commands if command["measured"] is False]) + + if verbosity >= 3: + # print('{}Received command to measure {} points'.format(num_to_measure)) + print("{}Received command to measure {} points".format(prefix, num_to_measure)) + + imeasure = 0 + for icommand, command in enumerate(commands): + if verbosity >= 5: + print("{}Considering point {}/{}".format(prefix, icommand, len(commands))) + + if not command["measured"]: + imeasure += 1 + if verbosity >= 3: + print("{}Measuring point {}/{}".format(prefix, imeasure, num_to_measure)) + + start_time = time.time() + + ######################################## + # Move to point + ######################################## + # Here you should define the beamline changes needed to go + # to the desired position. (You shouldn't in general need + # to change code outside of this block.) + ######################################## + + # convert x_pos, yy_pos of stage to x_position, y_position of sample + # yy_pos = -1*command['position']['x_position'] + # x_pos = command['position']['y_position'] + + # [x_pos, yy_pos] = command['position'] + Ti, Tm, Tf = command["position"] + # command['position_gpcam'] = command['position'] + + # align the sample + ss = input("Change the sample: (it has to be y or yes)") + while ss != "yes" and ss != "y": + ss = input("Change the sample: (it has to be y or yes)") + pta.laserOff() + smx.move(-20) + + ss = input("Is the sample ready? (it has to be y or yes)") + while ss != "yes" and ss != "y": + ss = input("Is the sample ready? (it has to be y or yes)") + + self.xo() + self.align() + cms.modeMeasurement() + self.xabs(0) + self.thabs(0.12) + + # offset the sample for high T + # self.yr(xxx) + # self.thabs(xxx) + + input("ready to go?") + # now use zmq to set PTA + # CustomQueue.push the message + BS.publish([Ti, Tm, Tf]) + # check it's working + # if verbosity>=3: + # print('{}Driving to point {}/{}; (x,yy) = ({:.3f}, {:.3f})'.format(prefix, imeasure, num_to_measure, x_pos, yy_pos)) + + self.name = ( + self.name_o + "_Ti{:.1f}".format(Ti) + "_Tm{:.1f}".format(Tm) + "_Tf{:.1f}".format(Tf) + ) + + # continuous measurement for 5 points + + wait_time_list = [5, 0, 0, 35, 85] + self.reset_clock() + # continuous measurement for 6 points + for ii in range(5): + self.xabs(ii * 0.2) + if ii >= 2: + self.crazy_th() + cms.modeMeasurement() + time.sleep(wait_time_list[ii]) + + self.measureIncidentAngle(0.12, exposure_time=exposure_time, **md) + + # wait until the T back to RT, move to the last fresh position + while self.clock() < 310: + time.sleep(5) + self.xabs(0.2 * 6) + self.crazy_th() + cms.modeMeasurement() + self.measureIncidentAngle(0.12, exposure_time=exposure_time, extra="FINAL", **md) + + header = db[-1] # The most recent measurement + # command['filename'] = '{}'.format(header.start['filename'][:-1]) + command["filename"] = "{}".format(header.start["filename"]) + + ######################################## + # md['anneal_time'] = self.anneal_time + # md['preanneal_time'] = self.preanneal_time + + cost_time = time.time() - start_time + + command["cost"] = cost_time + + command["measured"] = True + command["analyzed"] = False + + measure_queue.publish(commands) # Send results for analysis + + def measureAutonomous_3samples( + self, + runNo=0, + exposure_time=10, + extra=None, + max_measurements=600000, + samplePosNo=0, + prefix="measureAutonomous > ", + verbosity=3, + align=False, + **md, + ): + """Measure points in a loop, relying on an external queue to specify what + position to actually measure. If the 'position' is not (x,y) sample coordinates, + then you will have to add code to do the appropriate coordinate conversion, + or trigger the right beamline motors/components.""" + + samplePosNo_list = np.arange(0, 3) + samplePos = [123, 143.5, 163] + # samplePos = self.smxPos + # samplePosOffset = [pos1, pos2, pos3] + samplePosNo = samplePosNo + + for i in range(runNo, max_measurements): + + if verbosity >= 3: + print("{}Waiting for AE command on queue...".format(prefix)) + + commands = measure_queue.get() # Get measurement command from queue + num_to_measure = sum([1.0 for command in commands if command["measured"] is False]) + + if verbosity >= 3: + # print('{}Received command to measure {} points'.format(num_to_measure)) + print("{}Received command to measure {} points".format(prefix, num_to_measure)) + + imeasure = 0 + for icommand, command in enumerate(commands): + if verbosity >= 5: + print("{}Considering point {}/{}".format(prefix, icommand, len(commands))) + + if not command["measured"]: + imeasure += 1 + if verbosity >= 3: + print("{}Measuring point {}/{}".format(prefix, imeasure, num_to_measure)) + + start_time = time.time() + + # [x_pos, yy_pos] = command['position'] + Ti, Tm, Tf = command["position"] + print("The next Temperatures are: Ti {:.1f}, Tm {:.1f}, Tf {:.1f}".format(Ti, Tm, Tf)) + # command['position_gpcam'] = command['position'] + self.name = ( + self.name_o + + "_Ti{:.1f}".format(Ti) + + "_Tm{:.1f}".format(Tm) + + "_Tf{:.1f}".format(Tf) + + "_run{}".format(i) + ) + + # align the sample + if samplePosNo == 0: + + ss = input("Change the sample: (it has to be y or yes)") + while ss != "yes" and ss != "y": + ss = input("Change the sample: (it has to be y or yes)") + pta.laserOff() + smx.move(-20) + + ss = input("Are the samples ready? (it has to be y or yes)") + while ss != "yes" and ss != "y": + ss = input("Are the samples ready? (it has to be y or yes)") + print("Running Postion {}".format(samplePosNo)) + smx.move(samplePos[samplePosNo]) + sth.move(0) + self.setOrigin(["th"]) + + while smx.moving == True: + time.sleep(1) + beam.setSize(0.2, 0.05) + self.align() + beam.setSize(0.2, 0.2) + self.setOrigin(["x"]) + input("ready to go?") + # now use zmq to set PTA + # CustomQueue.push the message + BS.publish([Ti, Tm, Tf]) + # check it's working + + # continuous measurement for 5 points + + wait_time_list = [5, 0, 0, 50, 100] + + self.reset_clock() + for ii in range(5): + self.xabs(ii * 0.2) + if ii >= 2 and align: + self.crazy_th() + time.sleep(wait_time_list[ii]) + cms.modeMeasurement() + self.measureIncidentAngle(0.12, exposure_time=exposure_time) + + # wait until the T back to RT, move to the last fresh position + while self.clock() < 310: + time.sleep(5) + self.xabs(0.2 * 5) + if align: + self.crazy_th() + else: + beam.setSize(0.2, 0.05) + self.align() + beam.setSize(0.2, 0.2) + cms.modeMeasurement() + self.measureIncidentAngles( + [0.08, 0.1, 0.12, 0.15, 0.18, 0.2, 0.25], exposure_time=exposure_time, extra="FINAL" + ) + + header = db[-3] # The most recent measurement + # command['filename'] = '{}'.format(header.start['filename'][:-1]) + command["filename"] = "{}".format(header.start["filename"]) + + ######################################## + # md['anneal_time'] = self.anneal_time + # md['preanneal_time'] = self.preanneal_time + + cost_time = time.time() - start_time + + command["cost"] = cost_time + + command["measured"] = True + command["analyzed"] = False + + samplePosNo += 1 + if samplePosNo > 2: + samplePosNo = 0 + + measure_queue.publish(commands) # Send results for analysis + + def measureManual(self, Ti, Tm, Tf, step=0, exposure_time=10, align=False): + if step < 1: + ss = input("Sample pos number? ") + if ss == "0": + smx.move(self.smxPos[0]) + elif ss == "1": + smx.move(self.smxPos[1]) + elif ss == "2": + smx.move(self.smxPos[2]) + else: + print("Wrong Number. It has to be 0 or 1 or 2.") + return + + while smx.moving == True: + time.sleep(1) + + if step < 5: + self.setOrigin(["x"]) + self.gotoOrigin() + beam.setSize(0.2, 0.05) + self.align() + beam.setSize(0.2, 0.2) + + if step < 10: + ss = input("Ready for annealing? (it has to be y or yes)") + while ss != "yes" and ss != "y": + ss = input("Ready for annealing? (it has to be y or yes)") + + BS.publish([Ti, Tm, Tf]) + if align: + wait_time_list = [5, 0, 0, 35, 85] + else: + wait_time_list = [5, 0, 0, 50, 100] + self.reset_clock() + # continuous measurement for 6 points + for ii in range(5): + self.xabs(ii * 0.2) + if ii >= 2 and align: + self.crazy_th() + time.sleep(wait_time_list[ii]) + cms.modeMeasurement() + self.measureIncidentAngle(0.12, exposure_time=exposure_time) + + # wait until the T back to RT, move to the last fresh position + while self.clock() < 310: + time.sleep(5) + self.xabs(0.2 * 5) + if align: + self.crazy_th() + else: + beam.setSize(0.2, 0.05) + self.align() + beam.setSize(0.2, 0.2) + cms.modeMeasurement() + self.measureIncidentAngles( + [0.08, 0.1, 0.12, 0.15, 0.18, 0.2, 0.25], exposure_time=exposure_time, extra="FINAL" + ) + + def alignment_set(self): + self.start_x = 0 + self.end_x = 22 + self.start_y = 39.2196 + self.end_y = 40.037 + self.start_th = 1.2 + self.end_th = 1.198 + cms.direct_beam_int = 22245 + yield from bps.null() + + + +# cms.SAXS.setCalibration([758, 1680-607], 5.0, [-65, -73]) # 13.5 keV +# cms.SAXS.setCalibration([754, 1076], 5.03, [-65, -73]) #20190320, 13.5 keV +# cms.SAXS.setCalibration([754, 1075], 5.03, [-65, -73]) #20201021, 13.5 keV +# cms.SAXS.setCalibration([754, 1077], 5.03, [-65, -73]) #20210208, 13.5 keV +# cms.SAXS.setCalibration([761, 1075], 5.03, [-65, -73]) #20210716, 13.5 keV +cms.SAXS.setCalibration([756, 1079], 5.83, [-65, -73]) # 20201021, 13.5 keV + + +# RE.md['experiment_group'] = 'MNoack' +RE.md["experiment_group"] = "KYager" +# RE.md['experiment_alias_directory'] = '/nsls2/xf11bm/data/2020_3/MNoack/Exp1/' +RE.md["experiment_alias_directory"] = "/nsls2/data/cms/legacy/xf11bm/data/2023_2/PTA/" +RE.md["experiment_user"] = "TBD" +RE.md["experiment_type"] = "SAXS" +RE.md["experiment_project"] = "TBD" + + +def fake_coordinated_motion(mtr1, target1, mtr2, target2, N=1000): + start1 = yield from bps.rd(mtr1) + start2 = yield from bps.rd(mtr2) + step1 = (target1 - start1) / N + step2 = (target2 - start2) / N + for j in range(int(N)): + yield from bps.mv(mtr1, start1 + j * step1, mtr2, start2 + j * step2) + +def parallel_fake_coordinated_motion(mtr1, target1, mtr2, target2): + ... + +def fake_coordinated_motionr(mtr1, mtr2, delta, step=0.1): + + real_step= step*abs(delta)/delta + + for j in range(int(abs(delta)/ step)): + + yield from bps.mvr(mtr1, real_step, mtr2, real_step) + + +def changeSample(): + #smx.move(-20) + yield from move_sample_with_laser(28.67) + yield from bps.mv(smx, -100) + +def newSample(): + #smx.move(-20) + yield from bps.mv(smx, 28.67) + yield from bps.mv(laserx, 0) + +def alignNewSample(): + + yield from cms.modeAlignment() + #pos1 + # yield from bps.mv(smx, 28.67) + yield from move_sample_with_laser(28.67) + yield from sam.align() + sam.start_x = smx.position + sam.start_y = smy.position + sam.start_th = sth.position + #pos2 + # yield from bps.mv(smx, 28.67+33) + yield from move_sample_with_laser(28.67+33) + yield from sam.align() + sam.end_x = smx.position + sam.end_y = smy.position + sam.end_th = sth.position + + + +# the strips in the same materials system should have the same file name +# the location with l_pos=0, o_pos=0 for the first strip should be mared as 0 +# the location with l_pos=0, o_pos=i for the second sample needs to be aligned in the sequence of the first strip. + + +# # Connect to ZeroMQ (zmq) +# try: +# BS +# except NameError: +# ##queue_PATH='../' +# queue_PATH='/nsls2/data/cms/legacy/xf11bm/data/2022_2/SRussell/' +# queue_PATH in sys.path or sys.path.append(queue_PATH) +# from CustomQueuePTA import BSQueue +# BS = BSQueue() + +# ## Connect to S3 +# try: +# measure_queue +# except NameError: +# ##queue_PATH='../' +# queue_PATH='/nsls2/data/cms/legacy/xf11bm/data/2022_2/SRussell/' +# queue_PATH in sys.path or sys.path.append(queue_PATH) +# from CustomS3 import Queue_measure +# measure_queue = Queue_measure() + +""" +The edge of the diving board in x + +In [237]: wsam() +smx = 81.2 +smy = 16.13191875 +sth = 1.120000000000001 + +the other edge of x (clamping spot) + +smx = 106.1 + +============ +align bare Si wafer at smx=106 + +In [298]: wsam() +smx = 106.0 +smy = 16.19016875 +sth = 0.995000000000001 + +align bare Si wafer at smx=81.1 + +In [298]: wsam() + +In [365]: wsam() +smx = 93.55 +smy = 15.7754375 +sth = 0.9976562500000004 + +1.89deg offset in schi + + +============ +y scan at the aligned position to verify the stats2/stat4. ++-----------+------------+------------+-------------------+------------------------+------------------------+------------------------+------------------------+ +| seq_num | time | smy | smy_user_setpoint | pilatus2M_stats1_total | pilatus2M_stats2_total | pilatus2M_stats3_total | pilatus2M_stats4_total | ++-----------+------------+------------+-------------------+------------------------+------------------------+------------------------+------------------------+ +| 1 | 12:02:13.5 | 15.5819 | 15.5819 | 1 | -89 | 0 | 20095 | +| 2 | 12:02:15.4 | 15.6019 | 15.6019 | 1 | -90 | 0 | 20221 | +| 3 | 12:02:17.3 | 15.6219 | 15.6219 | 0 | -90 | 0 | 20026 | +| 4 | 12:02:19.1 | 15.6419 | 15.6419 | 0 | -90 | 0 | 20337 | +| 5 | 12:02:21.1 | 15.6619 | 15.6619 | 1 | -90 | 0 | 20427 | +| 6 | 12:02:22.9 | 15.6819 | 15.6819 | 2 | -87 | 0 | 20053 | +| 7 | 12:02:24.7 | 15.7019 | 15.7019 | 2 | -84 | 3 | 20383 | +| 8 | 12:02:26.5 | 15.7219 | 15.7219 | 19 | -51 | 3 | 20052 | +| 9 | 12:02:28.4 | 15.7419 | 15.7419 | 186 | 328 | 75 | 19790 | +| 10 | 12:02:30.4 | 15.7619 | 15.7619 | 1450 | 3553 | 718 | 16054 | +| 11 | 12:02:32.3 | 15.7819 | 15.7819 | 3974 | 8884 | 2697 | 7412 | +| 12 | 12:02:34.2 | 15.8019 | 15.8019 | 2783 | 5922 | 1889 | 1563 | +| 13 | 12:02:36.1 | 15.8219 | 15.8219 | 705 | 1368 | 558 | 114 | +| 14 | 12:02:38.0 | 15.8419 | 15.8419 | 65 | 39 | 61 | 2 | +| 15 | 12:02:39.9 | 15.8619 | 15.8619 | 15 | -66 | 10 | 0 | +| 16 | 12:02:41.8 | 15.8819 | 15.8819 | 7 | -70 | 0 | 0 | +| 17 | 12:02:43.5 | 15.9019 | 15.9019 | 0 | -89 | 0 | 0 | +| 18 | 12:02:45.5 | 15.9219 | 15.9219 | 0 | -90 | 0 | 0 | +| 19 | 12:02:47.4 | 15.9419 | 15.9419 | 0 | -90 | 0 | 0 | +| 20 | 12:02:49.4 | 15.9619 | 15.9619 | 0 | -90 | 0 | 0 | +| 21 | 12:02:51.3 | 15.9819 | 15.9819 | 0 | -90 | 0 | 0 | + + + ++-----------+------------+------------+-------------------+------------------------+------------------------+------------------------+------------------------+ + + +laser power <24 + +0, 6, 12, 18, 24 + +heater @50C @100C. + + +#laser @ the edge of Si wafer +In [850]: wsam() +smx = 86.2495 +smy = 15.778553125 +sth = 1.0212500000000002 + +#2mm offset from laser @ the edge +In [854]: wsam() +smx = 88.2495 +smy = 15.778553125 +sth = 1.0212500000000002 +In [856]: laserx.position +Out[856]: 0.0 + +FIX the offfset between smx and laserx as 88.25 + + +#alignment scan @50C + + +# smy.mov(15.5) +RE(fake_coordinated_motion(smx, 82, laserx, -6.25, N=120)) +#set power +for power in np.arange(0, 24.1, 6): + + pta.setLaserPower(power) + #set x position + if power==0: + pta.laserOff() + else: + pta.laserOn() + time.sleep(30) + # for xpos in np.arrange(0, 24.1, 6): + for xpos in range(5): + smy.move(15.5) + sam.align() + if xpos<4: + RE(fake_coordinated_motionr(smx, laserx, delta=6)) + + pta.laserOff() + + RE(fake_coordinated_motion(smx, 82, laserx, -6.25, N=120)) + + +pta.setLaserPower(power) + + +""" + + +# camonitor -S XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire + +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:18:45.322852 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:18:45.406499 Done +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:18:45.332771 23333 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:18:45.332854 10 +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:18:45.562211 Done +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:10.780798 0 +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:11.563899 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:11.563945 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:11.563973 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:11.632702 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:11.937539 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:11.953721 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:11.953786 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:11.963590 23334 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:11.963779 1 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:12.055200 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:12.278970 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:12.279087 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:12.279116 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:12.347917 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:12.653034 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:12.666444 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:12.666491 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:12.674896 23335 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:12.674989 2 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:12.806157 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:12.929527 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:12.929575 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:12.929593 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:12.998175 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:13.301574 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:13.316497 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:13.316522 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:13.325644 23336 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:13.325764 3 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:13.452583 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:13.567623 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:13.567675 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:13.567699 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:13.636079 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:14.153505 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:14.168763 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:14.168805 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:14.178550 23337 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:14.178706 4 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:14.252755 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:14.380508 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:14.380533 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:14.380543 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:14.449284 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:14.756593 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:14.772070 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:14.772109 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:14.781253 23338 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:14.781299 5 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:14.859708 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:14.982903 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:14.982950 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:14.982985 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:15.051642 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:15.661136 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:15.676297 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:15.676319 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:15.685042 23339 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:15.685210 6 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:15.816051 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:15.932728 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:15.932767 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:15.932785 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:16.001699 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:16.305201 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:16.319495 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:16.319542 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:16.329081 23340 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:16.329159 7 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:16.408806 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:16.533301 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:16.533346 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:16.533364 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:16.602075 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:17.143514 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:17.157371 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:17.157411 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:17.167105 23341 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:17.167203 8 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:17.245183 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:17.369047 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:17.369103 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:17.369129 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:17.437877 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:17.743062 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:17.756966 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:17.757005 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:17.766715 23342 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:17.766777 9 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:17.919766 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:18.042324 Acquiring data +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:18.042377 Acquire +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:18.042401 Acquiring STATE MINOR +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:18.111180 Waiting for 7OK response +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:18.673632 Reading image file /ramdisk/current_0000.tiff +# XF:11BMB-ES{Det:PIL2M}:cam1:Acquire 2023-03-20 15:25:18.688266 Done +# XF:11BMB-ES{Det:PIL2M}:cam1:StatusMessage_RBV 2023-03-20 15:25:18.688318 Waiting for acquire command +# XF:11BMB-ES{Det:PIL2M}:Trans1:ArrayCounter_RBV 2023-03-20 15:25:18.697376 23343 +# XF:11BMB-ES{Det:PIL2M}:TIFF1:ArrayCounter_RBV 2023-03-20 15:25:18.697448 10 +# XF:11BMB-ES{Det:PIL2M}:cam1:AcquireBusy 2023-03-20 15:25:18.825073 Done + + +def test_plan(detector=None): + + if detector is None: + detector=pilatus2M + # detector = get_beamline().detector[0] + + motors_for_table = [smx, smy, sth] + + @bpp.stage_decorator([detector]) + @bpp.run_decorator(md={}) + @bpp.finalize_decorator(final_plan=shutter_off) + def inner_plan(group=None): + + if group: + yield from bps.wait(group) + + for n in range(10): + t0 = time.time() + # yield from bps.trigger_and_read([detector, *motors_for_table]) + yield from bps.trigger_and_read([detector]) + print(f"Detection time: {time.time() - t0}") + # yield from bps.sleep(.1) + + group_name = "setup_aligment" + yield from bps.abs_set(bsx, cms.bsx_pos + 3, group=group_name) + beam.setTransmission(1e-6) + + yield from inner_plan(group=group_name) + + yield from bps.abs_set(bsx, cms.bsx_pos, group=group_name) + yield from bps.wait(group_name) + +sample_pta = Sample('test') + +''' +Notes at Mar 22, 2023, the 4th day at CMS + +#quick alignment for Si wafer + +#check the beam position in USB cam1 +# + +#the start edge +In [165]: wsam() +smx = 0.0 +smy = 39.23188125 +sth = 1.086875000000001 + +In [166]: sam.pos() +test.th = 0.157 deg (origin = 0.930) +test.x = 0.000 mm (origin = 0.000) +test.y = -0.028 mm (origin = 39.260) +Out[166]: {'th': 0.15687500000000087, 'x': 0.0, 'y': -0.028118749999997306} + + +#the end edge + +In [173]: wsam() +smx = 22.0005 +smy = 40.072500000000005 +sth = 1.0865624999999994 + +In [174]: sam.pos() +test.th = 0.157 deg (origin = 0.930) +test.x = 22.000 mm (origin = 0.000) +test.y = 0.813 mm (origin = 39.260) + +''' + + +''' +Notes March 22, 2023 +17:18 KY loaded "real scientific sample +name='GD4-113-4-2nd_Tb50C' + +laserPower = 1.4V (4.6w) + +smx = 3.7 ; laserx = 11.5 # IR laser is hitting edge of sample +smx = 8.7 ; laserx = 11.5 # IR laser is hitting edge of sample + + +Notes March 23, 2023 +10:40 KY loaded "real scientific sample 2 +name='GD4-113-1_Tb50C' +laserPower = 1.1V (2.3w) + +there is unexpected ~10s delay on every point during alignment. the bug is gone after restart. + +10:40 KY loaded "real scientific sample 3 +name='GD4-113-1-2nd_Tb50C' +laserPower = 1.1V (2.3w) + +In [7]: sam.start_x +Out[7]: 0.0 + +In [8]: sam.start_y +Out[8]: 39.218578125 + +In [9]: sam.start_th +Out[9]: 1.2006250000000005 + +In [10]: sam.end_x +Out[10]: 22.0005 + +In [11]: sam.end_y +Out[11]: 40.037328125 + +In [12]: sam.end_th +Out[12]: 1.1979687500000011 + + +#####protocol +=============bsui================== +#change sample --mov smx -100 and mount the fresh sample +RE(sam.run_initial_alignment(start_x=0, end_x=22)) #align samples at smx=0 and 22 and calculate the lookup table for smy and th +#print out sam.start_x/y/th and smx.end_x/y/th and HARD code them in sam.alignment_set() +=============bsui part is done. exit bsui============================= +#restart the env in Queue monitor +#pre-load 'agent_alignemnt_set' and 'agent_laser_on' +==>>ws2, agent.start(True) +==>>ws1, start the queue +''' + +# def fake_fly(mtr, start, stop, exp_time): +# det = pilatus2M + +# det.tiff.kind = 'omitted' +# det.tiff.disable_on_stage() +# det.stats4.total.kind='hinted' + + +# @bpp.stage_decorator([det]) +# @bpp.monitor_during_decorator([det.stats4.total, mtr]) +# @bpp.run_decorator() +# @bpp.finalize_decorator(final_plan=shutter_off) +# def inner(): +# yield from shutter_on() + +# yield from bps.trigger(det, group='fake_fly') +# yield from bps.abs_set(mtr, stop, group='fake_fly') +# yield from bps.wait(group='fake_fly') + +# @bpp.reset_positions_decorator([det.cam.num_images, det.cam.acquire_time, det.cam.acquire_period]) +# def inner2(): +# yield from bps.mv(det.cam.acquire_time, exp_time) +# yield from bps.mv(det.cam.acquire_period, exp_time +.05) +# total_time = np.abs(stop - start) + +# yield from bps.mv(det.cam.num_images, num) +# yield from bps.mv(mtr, start) +# yield from inner() + +# group_name = "setup_aligment" +# yield from bps.abs_set(bsx, cms.bsx_pos + 3, group=group_name) +# yield from bps.wait(group=group_name) + +# beam.setTransmission(1e-6) + +# yield from inner2() + +# yield from bps.abs_set(bsx, cms.bsx_pos, group=group_name) +# yield from bps.wait(group_name) + + +# def fake_fly2_test(mtr, start, stop, step, exp_time): + +# # motors: smy (+/- 2), sth (+/- 1) +# det = pilatus2M + +# # It takes 0.4 to 0.7 s longer to complete motion, so let's add 1 s for now +# # It should be computed/estimated more accurately +# num = int(np.abs(stop - start) / step) +# total_time = num * exp_time +# velocity = np.abs(stop - start) / total_time + +# det.tiff.kind = 'omitted' +# det.tiff.disable_on_stage() +# det.stats4.total.kind='hinted' + +# frame_numbers = [] +# frame_timestamps = [] +# frame_mtr_pos = [] +# frame_roi2_int = [] +# frame_roi3_int = [] +# frame_roi4_int = [] + +# def accumulate(value, old_value, timestamp, **kwargs): +# frame_numbers.append(value) +# frame_timestamps.append(timestamp) +# frame_mtr_pos.append(mtr.position) + +# def accumulate_roi2(value, old_value, timestamp, **kwargs): +# roi2_int = pilatus2M.stats2.total.get() +# frame_roi2_int.append(roi2_int) + +# def accumulate_roi3(value, old_value, timestamp, **kwargs): +# roi3_int = pilatus2M.stats3.total.get() +# frame_roi3_int.append(roi3_int) + +# def accumulate_roi4(value, old_value, timestamp, **kwargs): +# roi4_int = pilatus2M.stats4.total.get() +# frame_roi4_int.append(roi4_int) + +# @bpp.stage_decorator([det]) +# def inner(): +# cid = pilatus2M.cam.array_counter.subscribe(accumulate) +# cid2 = pilatus2M.stats2.array_counter.subscribe(accumulate_roi2) +# cid3 = pilatus2M.stats3.array_counter.subscribe(accumulate_roi3) +# cid4 = pilatus2M.stats4.array_counter.subscribe(accumulate_roi4) +# try: +# yield from bps.trigger(det, group='fake_fly') +# yield from bps.abs_set(mtr, stop, group='fake_fly') +# yield from bps.wait(group='fake_fly') +# finally: +# pilatus2M.cam.array_counter.unsubscribe(cid) +# pilatus2M.stats2.array_counter.unsubscribe(cid2) +# pilatus2M.stats3.array_counter.unsubscribe(cid3) +# pilatus2M.stats4.array_counter.unsubscribe(cid4) + +# @bpp.reset_positions_decorator([det.cam.num_images, det.cam.acquire_time, det.cam.acquire_period, +# mtr.velocity]) +# def inner2(): +# yield from bps.abs_set(mtr, start, wait=True) +# yield from bps.mv(mtr.velocity, velocity) + +# print(f"Number of acquired images: {num}. Exposure time: {exp_time}") + +# yield from bps.mv(det.cam.acquire_time, exp_time - 0.005) +# yield from bps.mv(det.cam.acquire_period, exp_time) + +# yield from bps.mv(det.cam.num_images, num) +# yield from inner() + +# yield from inner2() + +# def trim_list(v, num): +# n_first = max(len(v) - num, 0) +# return v[n_first:] + +# frame_numbers = trim_list(frame_numbers, num) +# frame_timestamps = trim_list(frame_timestamps, num) +# frame_mtr_pos = trim_list(frame_mtr_pos, num) +# frame_roi2_int = trim_list(frame_roi2_int, num) +# frame_roi3_int = trim_list(frame_roi3_int, num) +# frame_roi4_int = trim_list(frame_roi4_int, num) + +# print(f"frame_numbers = {frame_numbers}") +# print(f"frame_timestamps = {frame_timestamps}") +# print(f"mtr_pos = {frame_mtr_pos}") +# print(f"roi2 = {frame_roi2_int}") +# print(f"roi3 = {frame_roi3_int}") +# print(f"roi4 = {frame_roi4_int}") + +# return frame_mtr_pos, frame_roi2_int, frame_roi3_int, frame_roi4_int + + +def fake_fly3(det, mtr, start, stop, step, exp_time): + + # motors: smy (+/- 2), sth (+/- 1) + # det = pilatus2M + + # It takes 0.4 to 0.7 s longer to complete motion, so let's add 1 s for now + # It should be computed/estimated more accurately + num = int(np.abs(stop - start) / step) + total_time = num * exp_time + velocity = np.abs(stop - start) / total_time + + det.tiff.kind = 'omitted' + det.tiff.disable_on_stage() + det.stats4.total.kind='hinted' + + frame_numbers = [] + frame_timestamps = [] + frame_mtr_pos = [] + frame_roi2_ts = [] + frame_roi3_ts = [] + frame_roi4_ts = [] + + frame_roi2_total_ts = [] + frame_roi3_total_ts = [] + frame_roi4_total_ts = [] + frame_roi2_total = [] + frame_roi3_total = [] + frame_roi4_total = [] + + + def accumulate(value, old_value, timestamp, **kwargs): + frame_numbers.append(value) + frame_timestamps.append(timestamp) + frame_mtr_pos.append(mtr.position) + + def accumulate_roi2(value, old_value, timestamp, **kwargs): + frame_roi2_ts.append(timestamp) + + def accumulate_roi3(value, old_value, timestamp, **kwargs): + frame_roi3_ts.append(timestamp) + + def accumulate_roi4(value, old_value, timestamp, **kwargs): + frame_roi4_ts.append(timestamp) + + def accumulate_roi2_total(value, old_value, timestamp, **kwargs): + frame_roi2_total_ts.append(timestamp) + frame_roi2_total.append(value) + + def accumulate_roi3_total(value, old_value, timestamp, **kwargs): + frame_roi3_total_ts.append(timestamp) + frame_roi3_total.append(value) + + def accumulate_roi4_total(value, old_value, timestamp, **kwargs): + frame_roi4_total_ts.append(timestamp) + frame_roi4_total.append(value) + + def inner(): + cid = pilatus2M.cam.array_counter.subscribe(accumulate) + cid2 = pilatus2M.stats2.array_counter.subscribe(accumulate_roi2) + cid3 = pilatus2M.stats3.array_counter.subscribe(accumulate_roi3) + cid4 = pilatus2M.stats4.array_counter.subscribe(accumulate_roi4) + cid2a = pilatus2M.stats2.total.subscribe(accumulate_roi2_total) + cid3a = pilatus2M.stats3.total.subscribe(accumulate_roi3_total) + cid4a = pilatus2M.stats4.total.subscribe(accumulate_roi4_total) + try: + yield from bps.trigger(det, group='fake_fly') + yield from bps.abs_set(mtr, stop, group='fake_fly') + yield from bps.wait(group='fake_fly') + finally: + pilatus2M.cam.array_counter.unsubscribe(cid) + pilatus2M.stats2.array_counter.unsubscribe(cid2) + pilatus2M.stats3.array_counter.unsubscribe(cid3) + pilatus2M.stats4.array_counter.unsubscribe(cid4) + pilatus2M.stats2.total.unsubscribe(cid2a) + pilatus2M.stats3.total.unsubscribe(cid3a) + pilatus2M.stats4.total.unsubscribe(cid4a) + + @bpp.reset_positions_decorator([det.cam.num_images, det.cam.acquire_time, det.cam.acquire_period, + mtr.velocity]) + def inner2(): + print(f"setting motor start position") + yield from bps.abs_set(mtr, start, wait=True) + print(f"setting motor start velocity: {velocity}") + yield from bps.mv(mtr.velocity, velocity) + + print(f"Number of acquired images: {num}. Exposure time: {exp_time}") + + yield from bps.mv(det.cam.acquire_time, exp_time - 0.005) + yield from bps.mv(det.cam.acquire_period, exp_time) + + yield from bps.mv(det.cam.num_images, num) + yield from inner() + + yield from inner2() + + def trim_list(v, num): + n_first = max(len(v) - num, 0) + return v[n_first:] + + def set_total_values(frame_roi_ts, total_ts, total, dt=0.25 * exp_time): + total_ts = [_ - dt for _ in total_ts] + vals = [0] * len(frame_roi_ts) + n_current, v_current = 0, 0 + for n in range(len(vals)): + if n_current < len(total_ts) and total_ts[n_current] < frame_roi_ts[n]: + v_current = total[n_current] + n_current += 1 + vals[n] = v_current + return vals + + # 0-th frame is discarded during trimming + _ = frame_mtr_pos + frame_mtr_pos = [_[0]] + [(_[n] + _[n - 1]) / 2 for n in range(1, len(_))] + + total_roi2 = set_total_values(frame_roi2_ts, frame_roi2_total_ts, frame_roi2_total) + total_roi3 = set_total_values(frame_roi3_ts, frame_roi3_total_ts, frame_roi3_total) + total_roi4 = set_total_values(frame_roi4_ts, frame_roi4_total_ts, frame_roi4_total) + + num = num - 1 # Discard the 1st point + + frame_numbers = trim_list(frame_numbers, num) + frame_timestamps = trim_list(frame_timestamps, num) + frame_mtr_pos = trim_list(frame_mtr_pos, num) + frame_roi2_ts = trim_list(frame_roi2_ts, num) + frame_roi3_ts = trim_list(frame_roi3_ts, num) + frame_roi4_ts = trim_list(frame_roi4_ts, num) + total_roi2 = trim_list(total_roi2, num) + total_roi3 = trim_list(total_roi3, num) + total_roi4 = trim_list(total_roi4, num) + + print("**********************************************************************") + + # print(f"frame_numbers = {frame_numbers}") + # print(f"frame_timestamps = {frame_timestamps}") + # print(f"mtr_pos = {frame_mtr_pos}") + + # print(f"roi2_ts = {frame_roi2_ts}") + # print(f"roi3_ts = {frame_roi3_ts}") + # print(f"roi4_ts = {frame_roi4_ts}") + + # print(f"frame_roi2_total_ts = {frame_roi2_total_ts}") + # print(f"frame_roi3_total_ts = {frame_roi3_total_ts}") + # print(f"frame_roi4_total_ts = {frame_roi4_total_ts}") + + # print(f"frame_roi2_total = {frame_roi2_total}") + # print(f"frame_roi3_total = {frame_roi3_total}") + # print(f"frame_roi4_total = {frame_roi4_total}") + # print("\n") + + # print(f"total_roi2 = {total_roi2}") + # print(f"total_roi3 = {total_roi3}") + # print(f"total_roi4 = {total_roi4}") + + print(f"POSITION, TOTAL_ROI2, TOTAL_ROI3, TOTAL_ROI4") + for n, pos in enumerate(frame_mtr_pos): + print(f"{pos:11.5f} {total_roi2[n]:11.1f} {total_roi3[n]:11.1f} {total_roi4[n]:11.1f}") + print("**********************************************************************") + + return frame_mtr_pos, total_roi2, total_roi3, total_roi4 + + + +# from matplotlib import pyplot as plt +# fig_fast_scan, fig_fast_scan_ax1, fig_fast_scan_ax2 = None, None, None + +# def create_fig_fast_scan(): +# global fig_fast_scan, fig_fast_scan_ax1, fig_fast_scan_ax2 +# if not fig_fast_scan: +# fig_fast_scan = plt.figure() +# fig_fast_scan_ax1 = fig_fast_scan.add_subplot(2,1,1) +# fig_fast_scan_ax2 = fig_fast_scan.add_subplot(2,1,2) +# else: +# fig_fast_scan_ax1.clear() +# fig_fast_scan_ax2.clear() + + + +def align_motor_y(det, mtr, start_rel, stop_rel, step, exp_time, mtr_max_velocity = 0.08): + + mtr_current = mtr.position + start, stop = mtr_current + start_rel, mtr_current + stop_rel + + max_step = exp_time * mtr_max_velocity + step = min(step, max_step) + print(f"Y-scan step: {step}") + # exp_time_min = step / mtr_max_velocity + # exp_time = max(exp_time, exp_time_min) + # print(f"Y-scan exposure time: {exp_time}") + + @bpp.finalize_decorator(final_plan=shutter_off) + def inner(): + yield from shutter_on() + pos, roi2, roi3, roi4 = yield from fake_fly3(det, mtr, start, stop, step, exp_time) + + # max_roi4 = max(roi4) + # n_half = 0 + # for n in range(len(roi4)): + # if roi4[n] < max_roi4 / 2: + # n_half = n print(f"Center: {cen}") + + # break + + # yield from bps.abs_set(mtr, pos[n_half], wait=True) + + cen_return = None + try: + cen, _, _ = do_fitting(pos, roi4, model_type="step") + cen_return = cen + print(f"Center: {cen}") + except Exception as ex: + cen = mtr_current + print(f"ERROR: Failed to find the edge: {ex}") + + yield from bps.abs_set(mtr, cen, wait=True) + + yield from bps.mv(det.cam.num_images, 1) + yield from bps.trigger(det, group='fake_fly') + yield from bps.wait(group='fake_fly') + return cen_return + + return (yield from inner()) + + +def align_motor_th(det, mtr, start_rel, stop_rel, step, exp_time, fine_scan=True, mtr_backlash=0.1, mtr_max_velocity = 0.1): + + mtr_current = mtr.position + start, stop = mtr_current + start_rel, mtr_current + stop_rel + + max_step = exp_time * mtr_max_velocity + step = min(step, max_step) + print(f"TH-scan step: {step}") + # exp_time_min = step / mtr_max_velocity + # exp_time = max(exp_time, exp_time_min) + # print(f"TH-scan exposure time: {exp_time}") + + @bpp.finalize_decorator(final_plan=shutter_off) + def inner(): + yield from shutter_on() + pos, roi2, roi3, roi4 = yield from fake_fly3(det, mtr, start, stop, step, exp_time) + + # if fine_scan: + # n_max = np.argmax(roi3) + # else: + # n_max = np.argmax(roi2) + + # yield from bps.abs_set(mtr, pos[n_max], wait=True) + + roi = roi3 if fine_scan else roi2 + # roi = roi3 if fine_scan else roi4 + + cen, _, _ = do_fitting(pos, roi, model_type="peak") + print(f"Center: {cen}") + backlash = mtr_backlash if stop_rel > start_rel else -mtr_backlash + yield from bps.abs_set(mtr, cen - backlash, wait=True) + yield from bps.abs_set(mtr, cen, wait=True) + + + yield from bps.mv(det.cam.num_images, 1) + yield from bps.trigger(det, group='fake_fly') + yield from bps.wait(group='fake_fly') + return cen-0.12 + + return (yield from inner()) + +import time + +def align_stub(det, exp_time=0.3): + + mtr_backlash=0 + # mtr_backlash=0.1 # Use for PTA stages + + ceny, centh = 0, 0 + + # create_fig_fast_scan() + + tstart = time.time() + + ceny = yield from align_motor_y(det, smy, -2, 2, 0.05, exp_time) + if ceny is None: + print(f"Failed to find the edge. Repeating the scan with the wider range.") + ceny = yield from align_motor_y(det, smy, -4, 4, 0.05, exp_time) + if ceny is None: + raise RuntimeError(f"Failed to find the edge: the beam is blocked or the shutter is closed.") + + yield from align_motor_th(det, sth, -1, 1, 0.02, exp_time, fine_scan=False, mtr_backlash=mtr_backlash) + + ceny = yield from align_motor_y(det, smy, -0.2, 0.2, 0.02, exp_time) + yield from bps.sleep(2) + centh = yield from align_motor_th(det, sth, -0.1, 0.1, 0.0025, exp_time, fine_scan=True, mtr_backlash=mtr_backlash) + # centh = sth.position+0.12 + + print(f"Alignment completed: time {time.time() - tstart}") + return ceny, centh + + +def align_test2(): + det = pilatus2M + + @bpp.stage_decorator([det]) + def inner(): + yield from align_stub(det) + + yield from inner() + + +def fast_align(det=None): + """ + Attempt to align the detector. + + This is not a plan (produces no events), but expects the detector to be + unstaged. + + This will: + + 1. use a software flyscan to collect measurements + 2. fit a peak + 3. move to the center of the peak + + in both the smy and sth motors. + + If too far from aligned will fail catastrophically. + + Returns + ------- + y_center, th_center + """ + if det is None: + det = pilatus2M + exp_time = 0.3 + yield from cms.modeAlignment() + + # beam.setTransmission(1e-6) + + + @bpp.stage_decorator([det]) + def inner(): + return (yield from align_stub(det=det, exp_time=exp_time)) + + det.tiff.disable_on_stage() + try: + return (yield from inner()) + finally: + det.tiff.enable_on_stage() + + +def agent_feedback_plan(sample_x, md=None): + """ + Plan for adaptive round 2} + """ + md = md or {} + + yield from sam.align_lookup(sample_x) + print("ALIGN DONE") + yield from cms.modeMeasurement_plan() + print("IN MEASUE MODE") + yield from sam.measure(1, **md) + print("DONE") + + +def agent_bootstrap_alignment(end_x=60, start_x=35): + # yield from sam.run_initial_alignment() + + smx.move(28.67) + laserx.move(0) + RE(cms.modeAlignment()) + + RE(move_sample_with_laser(end_x)) + smy.move(25.5) + # yield from bps.mv(smx, start_x) + # yield from self.align_crazy_v3_plan(direct_beam_int=direct_beam_int) + sam.align() + + sam.end_x = smx.position + sam.end_y = smy.position + sam.end_th = sth.position + + # yield from bps.mv(smx, end_x) + RE(move_sample_with_laser(start_x)) + smy.move(24.5) + # yield from bps.mv(smy, 24.5) + # yield from self.align_crazy_v3_plan(direct_beam_int=direct_beam_int) + sam.align() + # yield from self.align() + + + sam.start_x = smx.position + sam.start_y = smy.position + sam.start_th = sth.position + + RE(cms.modeMeasurement_plan()) + +# from collections.abc import List + + +def agent_start_sample(init_x_pos: list[float], *, md=None): + """ + The plan to start an adaptive experiment. + + This plan: + + - goes to the first point + - turns on the laser + - restarts the "clock" + - aligns the sample + - sets the state for the look up to align along the length + - takes the first N points to prime the agents + + + Parameters + ---------- + init_x_pos : list[float] + The initial sample positions to take data at. + """ + md = md or {} + + # sam.end_x = 60 + # sam.end_y = 18.2 + # sam.end_th = 1.004 + + calib_x, *_ = init_x_pos + + xpos, ypos, thpos = sam.calc_lookuptable(calib_x) + + yield from move_sample_with_laser(xpos) + yield from bps.mv(smy, ypos, sth, thpos+0.12) + + # yield from move_sample_with_laser(calib_x) + # yield from cms.modeAlignment() + + sam.reset_clock() + RE.md['sample_clock_zero'] = sam.clock_zero + yield from bps.mv(laser.manual_button, 1) + + sam.start_x = calib_x + sam.start_y, sam.start_th = yield from fast_align() + for x in init_x_pos: + yield from agent_feedback_time_plan(x, 0, align=False) + + +def agent_stop_sample(*, md=None): + """ + Plan to run when the agent is done and would like no more data. + + Turns off the laser. + """ + md = md or {} + yield from bps.mv(laser.manual_button, 0) + + +def move_sample_with_laser(xpos): + """ + Moves the sample x and laserx in sync + + TODO: make this a pseudo positioner + """ + cur_x = yield from bps.rd(smx) + + delta = xpos - cur_x + + yield from bps.mvr(smx, delta, laserx, -delta) + + +def agent_feedback_time_plan( + sample_x: float, + target_time: float, + align: bool = False, + exposure: float = 1, + md=None +): + """ + The main data acqusition plan for the adaptive experiments + + Parameters + ---------- + sample_x : float + The absolute position to measure the sample at transverse to beam (and along gradient) + + target_time : float + Seconds from epoch. Do not take the data before this wall time. If in the past, take + data as soon as possible + + align : bool, optional + If `fast_align` should be used before taking data + + exposure : float, optional + The exposure time in seconds. + + md : dict, optional + Any additional payload to put in the start document. + + + """ + import time as ttime + + md = md or {} + md.setdefault('PTA', True) + + # this lookup table is primed by agent_start_sample + # it is just linear interpolation + xpos, ypos, thpos = sam.calc_lookuptable(sample_x) + + yield from move_sample_with_laser(xpos) + yield from bps.mv(smy, ypos, sth, thpos+0.12) + + if align: + ypos_align, thpos_align = yield from fast_align() + #sam.start_x = xpos + #sam.start_y = ypos_align + #sam.start_th = thpos_align + else: + yield from bps.mv(sth, thpos+.12) + + yield from cms.modeMeasurement_plan() + + + now = ttime.time() + lag = target_time - now + + if lag > 0: + yield from bps.sleep(lag) + + yield from sam.measure(exposure, **md) + + +def changeSample(): + yield from move_sample_with_laser(28.67) + yield from bps.mv(smx, -100) + + + +def calcTemperature(xpos): + + slope = (245-70)/(21.8-6.3) + xpos = 62.67-xpos + T = (xpos-6.3)*slope+70 + + return T + +def calcXpos(T): + + slope = (245-70)/(21.8-6.3) + + xpos = (T-70)/slope+6.3 + + return 62.67-xpos + + +''' +In [84]: wsam() +smx = 0.0 +smy = 17.543750000000003 +sth = 1.2385937499999997 + + + +2023,May, 22 + +align with bare Si wafer. +Laser is set 4mm away from the edge of the diving board. + +The clamp edge of the diving board +In [84]: wsam() +smx = 62.554 +smy = 17.543750000000003 +sth = 1.2385937499999997 + +The laser edge of the diving board +In [95]: wsam() +smx = 41.8545 +smy = 17.6 +sth = 1.3318750000000001 + + +align at laser position +In [102]: wsam() +smx = 45.8545 +smy = 17.1875 +sth = 1.0812500000000007 + +align at the clamp position +In [119]: wsam() +smx = 61.8545 +smy = 17.918750000000003 +sth = 1.0806249999999995 + + + +align at laser position with laser ON=2.3 +In [64]: wsam() +smx = 45.7995 +smy = 17.16690625 +sth = 1.22453125 + + + + +===================Heat equilibrium --30-50s at 8 and 16w + +In [98]: pta.setLaserPower(16) +PTA> Setting laser to 16.00 W (using control voltage of 2.93 V) + +In [99]: RE(tmp()) + + +Transient Scan ID: 1060961 Time: 2023-05-22 19:58:21 +Persistent Unique Scan ID: 'afb1ed8e-0363-4d59-a23c-5a446d3a09cf' +/nsls2/conda/envs/2023-2.0-py310-tiled/lib/python3.10/site-packages/nslsii/ad33.py:82: UserWarning: .dispatch is deprecated, use .generate_datum instead + self.dispatch(self._image_name, ttime.time()) +New stream: 'primary' ++-----------+------------+------------------------+------------------------+------------------------+ +| seq_num | time | pilatus2M_stats2_total | pilatus2M_stats3_total | pilatus2M_stats4_total | ++-----------+------------+------------------------+------------------------+------------------------+ +| 1 | 19:58:22.2 | 1018 | 202 | 2028 | +| 2 | 19:58:23.1 | 995 | 183 | 2130 | +| 3 | 19:58:24.0 | 847 | 135 | 2037 | +| 4 | 19:58:24.9 | 864 | 133 | 1949 | +| 5 | 19:58:25.7 | 939 | 141 | 1888 | +| 6 | 19:58:26.6 | 1012 | 158 | 1966 | +| 7 | 19:58:27.4 | 946 | 154 | 1971 | +| 8 | 19:58:28.4 | 849 | 128 | 2100 | +| 9 | 19:58:29.2 | 938 | 147 | 2093 | +| 10 | 19:58:30.1 | 960 | 154 | 2165 | +| 11 | 19:58:30.9 | 968 | 162 | 2168 | +| 12 | 19:58:31.9 | 909 | 131 | 2202 | +| 13 | 19:58:32.7 | 892 | 113 | 2254 | +| 14 | 19:58:33.6 | 896 | 121 | 2063 | +| 15 | 19:58:34.4 | 864 | 117 | 2317 | +| 16 | 19:58:35.4 | 835 | 114 | 2369 | +| 17 | 19:58:36.2 | 809 | 102 | 2271 | +| 18 | 19:58:37.1 | 763 | 94 | 2303 | +| 19 | 19:58:38.0 | 847 | 119 | 2424 | +| 20 | 19:58:38.9 | 762 | 106 | 2531 | +| 21 | 19:58:39.7 | 733 | 103 | 2521 | +| 22 | 19:58:40.5 | 704 | 95 | 2512 | +| 23 | 19:58:41.4 | 719 | 91 | 2552 | +| 24 | 19:58:42.4 | 721 | 89 | 2597 | +| 25 | 19:58:43.2 | 693 | 75 | 2636 | +| 26 | 19:58:44.0 | 721 | 80 | 2629 | +| 27 | 19:58:44.9 | 694 | 81 | 2630 | +| 28 | 19:58:45.9 | 694 | 80 | 2806 | +| 29 | 19:58:46.7 | 638 | 75 | 2750 | +| 30 | 19:58:47.5 | 648 | 85 | 2895 | +| 31 | 19:58:48.3 | 731 | 79 | 2905 | +| 32 | 19:58:49.1 | 586 | 74 | 2703 | +| 33 | 19:58:50.0 | 644 | 67 | 2970 | +| 34 | 19:58:50.9 | 651 | 72 | 2824 | +| 35 | 19:58:51.7 | 696 | 91 | 3065 | +| 36 | 19:58:52.5 | 617 | 64 | 3013 | +| 37 | 19:58:53.3 | 605 | 72 | 2701 | +| 38 | 19:58:54.2 | 533 | 70 | 2638 | +| 39 | 19:58:55.0 | 571 | 74 | 2897 | +| 40 | 19:58:55.8 | 618 | 84 | 3018 | +| 41 | 19:58:56.7 | 585 | 69 | 3036 | +| 42 | 19:58:57.5 | 546 | 73 | 2883 | +| 43 | 19:58:58.4 | 564 | 64 | 2906 | +| 44 | 19:58:59.3 | 544 | 62 | 2928 | +| 45 | 19:59:00.1 | 580 | 73 | 3029 | +| 46 | 19:59:00.9 | 545 | 67 | 3123 | +| 47 | 19:59:01.8 | 540 | 81 | 2943 | +| 48 | 19:59:02.6 | 536 | 83 | 3071 | +| 49 | 19:59:03.5 | 517 | 72 | 3167 | ++-----------+------------+------------------------+------------------------+------------------------+ +| seq_num | time | pilatus2M_stats2_total | pilatus2M_stats3_total | pilatus2M_stats4_total | ++-----------+------------+------------------------+------------------------+------------------------+ +| 50 | 19:59:04.3 | 526 | 74 | 3077 | +| 51 | 19:59:05.1 | 522 | 77 | 3213 | +| 52 | 19:59:05.9 | 500 | 63 | 2978 | +| 53 | 19:59:06.9 | 504 | 59 | 3044 | +| 54 | 19:59:07.7 | 555 | 92 | 3196 | +| 55 | 19:59:08.6 | 494 | 76 | 3231 | +| 56 | 19:59:09.4 | 512 | 83 | 3030 | +| 57 | 19:59:10.3 | 509 | 71 | 2946 | +| 58 | 19:59:11.2 | 480 | 76 | 3116 | +| 59 | 19:59:12.0 | 492 | 70 | 3052 | +| 60 | 19:59:12.8 | 515 | 78 | 3137 | +| 61 | 19:59:13.8 | 490 | 79 | 3064 | +| 62 | 19:59:14.7 | 496 | 70 | 3200 | +| 63 | 19:59:15.5 | 513 | 89 | 3085 | +| 64 | 19:59:16.3 | 520 | 80 | 3298 | +| 65 | 19:59:17.2 | 493 | 59 | 3052 | +| 66 | 19:59:18.0 | 489 | 76 | 3338 | +| 67 | 19:59:18.8 | 470 | 61 | 3167 | +| 68 | 19:59:19.8 | 471 | 53 | 3013 | +| 69 | 19:59:20.7 | 476 | 65 | 3124 | +| 70 | 19:59:21.5 | 526 | 87 | 3250 | +| 71 | 19:59:22.3 | 471 | 67 | 3093 | +| 72 | 19:59:23.1 | 508 | 75 | 3123 | +| 73 | 19:59:23.9 | 471 | 75 | 3171 | +| 74 | 19:59:24.8 | 481 | 77 | 3360 | +| 75 | 19:59:25.6 | 444 | 75 | 3163 | +| 76 | 19:59:26.5 | 510 | 61 | 3186 | +| 77 | 19:59:27.3 | 469 | 80 | 3092 | +| 78 | 19:59:28.1 | 460 | 71 | 3079 | +| 79 | 19:59:28.9 | 428 | 88 | 3428 | +| 80 | 19:59:29.9 | 511 | 98 | 3118 | +| 81 | 19:59:30.7 | 499 | 76 | 3169 | +| 82 | 19:59:31.5 | 474 | 69 | 3112 | +| 83 | 19:59:32.3 | 470 | 83 | 3045 | +| 84 | 19:59:33.1 | 503 | 85 | 3140 | +| 85 | 19:59:34.0 | 422 | 70 | 3265 | +| 86 | 19:59:34.8 | 452 | 71 | 3226 | +| 87 | 19:59:35.7 | 445 | 83 | 3250 | +| 88 | 19:59:36.5 | 456 | 73 | 3069 | +| 89 | 19:59:37.4 | 445 | 66 | 3219 | +| 90 | 19:59:38.4 | 447 | 68 | 3137 | +| 91 | 19:59:39.1 | 421 | 49 | 2991 | +| 92 | 19:59:39.9 | 479 | 75 | 3266 | +| 93 | 19:59:40.9 | 459 | 61 | 3229 | +| 94 | 19:59:41.7 | 463 | 92 | 3273 | +| 95 | 19:59:42.5 | 482 | 75 | 3366 | +| 96 | 19:59:43.3 | 469 | 77 | 2825 | +| 97 | 19:59:44.4 | 454 | 65 | 3137 | +| 98 | 19:59:45.2 | 536 | 103 | 3153 | +| 99 | 19:59:46.0 | 504 | 59 | 3197 | ++-----------+------------+------------------------+------------------------+------------------------+ +| seq_num | time | pilatus2M_stats2_total | pilatus2M_stats3_total | pilatus2M_stats4_total | ++-----------+------------+------------------------+------------------------+------------------------+ +| 100 | 19:59:46.9 | 512 | 80 | 3354 | ++-----------+------------+------------------------+------------------------+------------------------+ +generator count ['afb1ed8e'] (scan num: 1060961) + + + +Out[99]: ('afb1ed8e-0363-4d59-a23c-5a446d3a09cf',) + +In [100]: def tmp(): + ...: yield from beam.on() + ...: yield from bps.mv(laser.manual_button, 1) + ...: yield from bp.count([pilatus2M, core_laser], 100) + ...: yield from bps.mv(laser.manual_button, 0) + ...: yield from beam.off() + ...: + ...: + +In [101]: + +In [101]: pta.setLaserPower(8) +PTA> Setting laser to 8.00 W (using control voltage of 1.86 V) + +In [102]: RE(tmp()) + + +Transient Scan ID: 1060962 Time: 2023-05-22 20:00:43 +Persistent Unique Scan ID: '21042f80-ae1a-4b9b-bd8a-7158ec0dad77' +/nsls2/conda/envs/2023-2.0-py310-tiled/lib/python3.10/site-packages/nslsii/ad33.py:82: UserWarning: .dispatch is deprecated, use .generate_datum instead + self.dispatch(self._image_name, ttime.time()) +New stream: 'primary' ++-----------+------------+------------------------+------------------------+------------------------+ +| seq_num | time | pilatus2M_stats2_total | pilatus2M_stats3_total | pilatus2M_stats4_total | ++-----------+------------+------------------------+------------------------+------------------------+ +| 1 | 20:00:44.2 | 997 | 252 | 1635 | +| 2 | 20:00:45.1 | 1014 | 269 | 1715 | +| 3 | 20:00:46.0 | 968 | 226 | 1641 | +| 4 | 20:00:46.9 | 918 | 215 | 1635 | +| 5 | 20:00:47.9 | 946 | 204 | 1637 | +| 6 | 20:00:48.8 | 957 | 245 | 1667 | +| 7 | 20:00:49.7 | 1078 | 265 | 1608 | +| 8 | 20:00:50.6 | 995 | 229 | 1729 | +| 9 | 20:00:51.5 | 964 | 236 | 1608 | +| 10 | 20:00:52.4 | 977 | 256 | 1757 | +| 11 | 20:00:53.4 | 944 | 225 | 1723 | +| 12 | 20:00:54.2 | 997 | 244 | 1826 | +| 13 | 20:00:55.1 | 1010 | 242 | 1678 | +| 14 | 20:00:56.0 | 907 | 235 | 1819 | +| 15 | 20:00:56.9 | 1014 | 249 | 1835 | +| 16 | 20:00:57.8 | 996 | 235 | 1935 | +| 17 | 20:00:58.7 | 1025 | 225 | 1919 | +| 18 | 20:00:59.5 | 981 | 234 | 1829 | +| 19 | 20:01:00.5 | 956 | 194 | 1848 | +| 20 | 20:01:01.4 | 1094 | 236 | 1904 | +| 21 | 20:01:02.4 | 926 | 193 | 2014 | +| 22 | 20:01:03.3 | 992 | 221 | 2068 | +| 23 | 20:01:04.2 | 863 | 182 | 2027 | +| 24 | 20:01:05.0 | 951 | 204 | 2019 | +| 25 | 20:01:05.9 | 961 | 212 | 2087 | +| 26 | 20:01:06.8 | 1031 | 225 | 2172 | +| 27 | 20:01:07.7 | 980 | 205 | 2035 | +| 28 | 20:01:08.6 | 974 | 209 | 2145 | +| 29 | 20:01:09.4 | 971 | 202 | 2233 | +| 30 | 20:01:10.3 | 1042 | 220 | 2190 | +| 31 | 20:01:11.4 | 940 | 222 | 2094 | +| 32 | 20:01:12.3 | 794 | 170 | 2154 | +| 33 | 20:01:13.2 | 862 | 188 | 2019 | +| 34 | 20:01:14.2 | 900 | 184 | 2265 | +| 35 | 20:01:15.0 | 993 | 189 | 2259 | +| 36 | 20:01:15.9 | 842 | 161 | 2128 | +| 37 | 20:01:16.8 | 836 | 169 | 2199 | +| 38 | 20:01:17.7 | 886 | 171 | 2317 | +| 39 | 20:01:18.5 | 871 | 176 | 2229 | +| 40 | 20:01:19.4 | 917 | 166 | 2140 | +| 41 | 20:01:20.3 | 880 | 175 | 2266 | +| 42 | 20:01:21.2 | 890 | 194 | 2316 | +| 43 | 20:01:22.1 | 854 | 185 | 2217 | +| 44 | 20:01:23.0 | 854 | 180 | 2224 | +| 45 | 20:01:23.9 | 978 | 199 | 2277 | +| 46 | 20:01:24.8 | 837 | 171 | 2287 | +| 47 | 20:01:25.7 | 816 | 171 | 2376 | +| 48 | 20:01:26.6 | 863 | 188 | 2275 | +| 49 | 20:01:27.5 | 903 | 189 | 2409 | ++-----------+------------+------------------------+------------------------+------------------------+ +| seq_num | time | pilatus2M_stats2_total | pilatus2M_stats3_total | pilatus2M_stats4_total | ++-----------+------------+------------------------+------------------------+------------------------+ +| 50 | 20:01:28.4 | 828 | 177 | 2349 | +| 51 | 20:01:29.4 | 834 | 168 | 2273 | +| 52 | 20:01:30.3 | 829 | 168 | 2308 | +| 53 | 20:01:31.1 | 807 | 161 | 2391 | +| 54 | 20:01:32.0 | 808 | 149 | 2413 | +| 55 | 20:01:32.9 | 839 | 172 | 2408 | +| 56 | 20:01:33.7 | 864 | 186 | 2403 | +| 57 | 20:01:34.6 | 864 | 170 | 2368 | +| 58 | 20:01:35.5 | 738 | 162 | 2294 | +| 59 | 20:01:36.4 | 805 | 171 | 2385 | +| 60 | 20:01:37.4 | 866 | 185 | 2551 | +| 61 | 20:01:38.3 | 826 | 167 | 2312 | +| 62 | 20:01:39.1 | 799 | 161 | 2322 | +| 63 | 20:01:40.1 | 818 | 164 | 2438 | +| 64 | 20:01:41.0 | 806 | 177 | 2416 | +| 65 | 20:01:42.0 | 783 | 175 | 2356 | +| 66 | 20:01:42.9 | 839 | 195 | 2388 | +| 67 | 20:01:43.9 | 822 | 153 | 2446 | +| 68 | 20:01:44.8 | 853 | 182 | 2498 | +| 69 | 20:01:45.7 | 865 | 167 | 2309 | +| 70 | 20:01:46.6 | 771 | 160 | 2539 | +| 71 | 20:01:47.5 | 773 | 145 | 2486 | +| 72 | 20:01:48.4 | 829 | 172 | 2399 | +| 73 | 20:01:49.3 | 891 | 167 | 2633 | +| 74 | 20:01:50.2 | 855 | 184 | 2512 | +| 75 | 20:01:51.1 | 811 | 173 | 2426 | +| 76 | 20:01:52.0 | 804 | 167 | 2271 | +| 77 | 20:01:52.9 | 873 | 174 | 2407 | +| 78 | 20:01:53.8 | 880 | 147 | 2634 | +| 79 | 20:01:54.7 | 778 | 140 | 2431 | +| 80 | 20:01:55.6 | 887 | 153 | 2510 | +| 81 | 20:01:56.5 | 821 | 157 | 2531 | +| 82 | 20:01:57.4 | 788 | 169 | 2441 | +| 83 | 20:01:58.4 | 762 | 146 | 2341 | +| 84 | 20:01:59.3 | 793 | 168 | 2433 | +| 85 | 20:02:00.2 | 735 | 143 | 2471 | +| 86 | 20:02:01.1 | 798 | 181 | 2408 | +| 87 | 20:02:02.0 | 876 | 188 | 2537 | +| 88 | 20:02:02.9 | 792 | 163 | 2518 | +| 89 | 20:02:03.8 | 747 | 163 | 2430 | +| 90 | 20:02:04.7 | 682 | 146 | 2400 | +| 91 | 20:02:05.6 | 723 | 154 | 2477 | +| 92 | 20:02:06.5 | 837 | 173 | 2471 | +| 93 | 20:02:07.4 | 798 | 153 | 2382 | +| 94 | 20:02:08.4 | 767 | 146 | 2424 | +| 95 | 20:02:09.2 | 765 | 153 | 2486 | +| 96 | 20:02:10.1 | 736 | 154 | 2538 | +| 97 | 20:02:11.0 | 801 | 123 | 2515 | +| 98 | 20:02:11.8 | 771 | 161 | 2547 | +| 99 | 20:02:12.8 | 698 | 140 | 2474 | ++-----------+------------+------------------------+------------------------+------------------------+ +| seq_num | time | pilatus2M_stats2_total | pilatus2M_stats3_total | pilatus2M_stats4_total | ++-----------+------------+------------------------+------------------------+------------------------+ +| 100 | 20:02:13.7 | 748 | 142 | 2401 | ++-----------+------------+------------------------+------------------------+------------------------+ +generator count ['21042f80'] (scan num: 1060962) + + + + + +2023, 05, 23 + +#change to standard REAL sample. + +@the edge of the clamp side +%mov smx 62.67 +In [191]: wsam() + ...: + ...: +smx = 61.67 +smy = 18.29416875 +sth = 0.9845312499999999 + + +@the edge of the laser side +In [176]: wsam() + +smx = 30.3705 +smy = 17.268571875 +sth = 1.1320312500000007 + +@the laser is located at 34mm away from the clamp +Positioner Value Low Limit High Limit Offset +laserx -0.0025 -100.0 100.0 0.0 +smx 28.67 -100.0 100.0 0.0 + + + +In [183]: wsam() +smx = 28.67 +smy = 17.24416875 +sth = 1.1196874999999995 + + +Temperature calibration + +turn on the laser at 17Watts + the burn mark1 (245C) is 21.8mm away from the clamp + the burn mark2 (70C) is 6.3mm away from the clamp + +start the REAL sample + +align @ clamp edge +In [333]: wsam() +smx = 60.0 +smy = 18.2 +sth = 1.0035937500000003 + + +align @ smx = 40 +In [388]: wsam() +smx = 40.0 +smy = 17.5 +sth = 1.0076562500000001 + +align @ smx = 35 +smx = 35.0 +smy = 17.3375 +sth = 1.0935937500000001 + + +In [613]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[613]: (35, 24.644, 1.057, 60, 25.4945, 1.0257999999999998) + +sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th = 35, 24.644, 1.057, 60, 25.4945, 1.0257999999999998 + + + +#new sample run2 + +In [708]: sam.name +Out[709]: 'C67_0HP_Tb50C_LP17w_run2' + +In [711]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[711]: (35, 25.441634375, 1.069, 60, 25.81, 1.063) + +run lasted 30min with 52 data points. + + +#new sample run3 + +In [708]: sam.name +Out[709]: 'C67_0HP_Tb50C_LP17w_run3' + +In [744]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[745]: (35, 25.505, 1.092968, 60.0, 25.836803125, 1.0717187500000005) + +run3 will last 10 hours until the morning of May 24. +run3 actually was terminated in midnight due to an error of agent. +extra data was taken at 11hours after the start of laser + + +In [852]: sam.name +Out[852]: 'C67_40HP_Tb50C_LP17w_run4' + +In [851]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[851]: (35, 25.175671875000003, 1.07, 60.0, 25.723056250000003, 1.0684375) + + +In [852]: sam.name +Out[852]: 'C67_40HP_Tb50C_LP17w_run5' +In [868]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[868]: (35.0, 25.382625, 1.04296875, 60.0, 25.825959375, 1.0212500000000002) + + +In [852]: sam.name +Out[852]: 'C67_20HP_Tb50C_LP17w_run6' +In [868]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[887]: +(35.0, + 25.457353125, + 1.1807812500000008, + 60.0, + 25.815703125000002, + 1.1545312499999998) + +In [852]: sam.name +Out[852]: 'C67_40HP_Tb50C_LP17w_run7' +In [897]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[897]: +(35.0, + 25.4574, + 1.0407812500000002, + 60.0, + 25.818787500000003, + 1.0543750000000003) + + +In [852]: sam.name +Out[852]: 'C67_0HP_Tb50C_LP17w_run5' #should be run8, supposed to run 10hours + + In [903]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[903]: (35.0, 25.32549375, 1.0982812499999994, 60.0, 25.76560625, 1.0948437500000008) + +In [852]: sam.name +Out[852]: 'C67_20HP_Tb50C_LP17w_run9' + + +In [852]: sam.name +Out[852]: 'C67_40HP_Tb50C_LP17w_run10' + +In [919]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[919]: +(35.0, + 25.629559375, + 1.1354687500000011, + 60.0, + 25.907678125, + 1.0960937499999996) + +In [852]: sam.name +Out[852]: 'C67_0HP_Tb50C_LP17w_run11' + + In [935]: sam.start_x, sam.start_y, sam.start_th, sam.end_x, sam.end_y, sam.end_th +Out[935]: (35.0, 24.944746875, 1.043906250000001, 60.0, 25.626225, 1.0310937500000001) + + +protocol: +changeSample() +sam=Sample('test') +agent_bootstrap_alignment() #automatic alignment at smx = 35 and 60 +#save sam.start_x/y/th, sam.end_x/y/th position. + +#start agent +#start initial measurement + +#in a different python env, enable the autostart to automatically run the commands in qserver. +PYTHONPATH=/nsls2/data/cms/shared/config/bluesky_overlay/2023-2.0-py310-tiled/lib/python3.10/site-packages qserver queue autostart enable + +PYTHONPATH=/nsls2/data/cms/shared/config/bluesky_overlay/2023-2.0-py310-tiled/lib/python3.10/site-packages qserver status + +========================================= +when the experiment is done-- + +PYTHONPATH=/nsls2/data/cms/shared/config/bluesky_overlay/2023-2.0-py310-tiled/lib/python3.10/site-packages qserver queue autostart disable + +''' + + +# smx = 38.9045 +# smy = 17.435846875000003 +# sth = 1.3117187500000007 diff --git a/startup/existing_plans_and_devices.yaml b/startup/existing_plans_and_devices.yaml new file mode 100644 index 0000000..b8a3791 --- /dev/null +++ b/startup/existing_plans_and_devices.yaml @@ -0,0 +1,13140 @@ +# This file is automatically generated. Edit at your own risk. +existing_devices: + Diode_A1: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + Diode_A2: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + Diode_A3: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + Diode_AO: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + LTensile: + classname: LinkamTensile + components: + FORCE: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + J2J_distance: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + J2J_distance_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + POS: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + POS_RAW: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + STRAIN: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + STRESS: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + cmd: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + config: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + ctrllr_err: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + disable: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + distance: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + distance_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + dsc: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + firm_ver: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + force: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + force_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + hard_ver: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + holdtime: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + holdtime_set: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + init: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + lnp_mode_set: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + lnp_speed: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + lnp_speed_set: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + mode: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + mode_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + model_array: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + power: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + ramptime: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + run_cmd: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + serial_array: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + stage_config: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + stage_model_array: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + stage_serial_array: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + status_code: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + status_code_Tensile: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + status_power: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + temperature_current: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + temperature_rate_current: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + temperature_rate_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + temperature_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + tensile_maxs_force: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + tensile_remain_cycles: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + LThermal: + classname: LinkamThermal + components: + cmd: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + config: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + ctrllr_err: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + disable: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + dsc: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + firm_ver: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + hard_ver: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + holdtime: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + holdtime_set: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + init: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + lnp_mode_set: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + lnp_speed: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + lnp_speed_set: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + model_array: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + power: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + ramptime: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + serial_array: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + stage_config: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + stage_model_array: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + stage_serial_array: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + status_code: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + status_power: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + temperature_current: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + temperature_rate_current: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + temperature_rate_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + temperature_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + MAXSbsx: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + MAXSbsy: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + MAXSx: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + MAXSy: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + SAXSx: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + SAXSy: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + SPW: + classname: SorrensonPowerSupply + components: + cmd: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + current: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + current_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + voltage: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + voltage_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + TTL2: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + WAXSx: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + WAXSy: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + WAXSz: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + armphi: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + armr: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + armx: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + army: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + armz: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + bim1: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + bim2: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + bim3y: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + bim4y: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + bim5y: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + bim6: + classname: EpicsSignalROWait + is_flyable: false + is_movable: true + is_readable: true + module: __main__ + bim6_integrating: + classname: EpicsSignalROIntegrate + is_flyable: false + is_movable: true + is_readable: true + module: __main__ + bsphi: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + bsx: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + bsy: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + cam2x: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + cam2z: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + camera: + classname: StandardProsilicaV33 + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + camx: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + camy: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + chiller: + classname: Chiller + components: + ChillerSetpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + ChillerT: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + cmd: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + core_laser: + classname: NuPhotoThermalAnnealer + components: + state: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + voltage: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + fs2: + classname: StandardProsilicaV33 + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + fs3: + classname: StandardProsilicaV33 + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + fs3y: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + fs4: + classname: StandardProsilicaV33 + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + gatex: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + ioL: + classname: ioLogik + is_flyable: false + is_movable: true + is_readable: true + module: __main__ + ion_chamber1: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + ion_chamber2: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + ion_chamber3: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + ion_chamber4: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + item_check: + classname: EpicsSignalWithRBV + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.areadetector.base + lakeshore: + classname: Lakeshore + components: + feedback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + output: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + ramp_rate: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: __main__ + laser: + classname: Laser + components: + delay: + classname: PairSP + components: + rb: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + sp: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: __main__ + input1: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + input2: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + manual_button: + classname: PairSEL + components: + rb: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + sel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: __main__ + physical_bitmank: + classname: PairSEL + components: + rb: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + sel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: __main__ + pulses: + classname: PairSP + components: + rb: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + sp: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: __main__ + pv_bitmask: + classname: PairSEL + components: + rb: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + sel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: __main__ + pv_trigger: + classname: PairCMD + components: + cmd: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + rb: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: __main__ + trigger_mode: + classname: PairSEL + components: + rb: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + sel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: __main__ + width: + classname: PairSP + components: + rb: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + sp: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: __main__ + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + laserx: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + lasery: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + mir_bend: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + mir_dsx: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + mir_dsyi: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + mir_dsyo: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + mir_usx: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + mir_usy: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + mono_bragg: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + mono_perp2: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + mono_pitch2: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + mono_roll2: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + pilatus2M: + classname: Pilatus2MV33 + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + pilatus8002: + classname: Pilatus8002V33 + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + pilatus_name: + classname: Pilatus2MV33 + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + quad_electrometer1_1: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + quad_electrometer1_2: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + quad_electrometer1_3: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + quad_electrometer1_4: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + quad_electrometer2_1: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + quad_electrometer2_2: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + quad_electrometer2_3: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + quad_electrometer2_4: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + ring_current: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + s0: + classname: Blades + components: + bt: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + ib: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + ob: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + tp: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + xc: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + xg: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + yc: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + yg: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + s1: + classname: MotorCenterAndGap + components: + xc: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + xg: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + yc: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + yg: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + s2: + classname: MotorCenterAndGap + components: + xc: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + xg: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + yc: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + yg: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + s3: + classname: MotorCenterAndGap + components: + xc: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + xg: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + yc: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + yg: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + s4: + classname: MotorCenterAndGap + components: + xc: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + xg: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + yc: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + yg: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + s5: + classname: MotorCenterAndGap + components: + xc: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + xg: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + yc: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + yg: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + scaled_ic1: + classname: ScaleSignal + is_flyable: false + is_movable: true + is_readable: true + module: __main__ + scaled_ic2: + classname: ScaleSignal + is_flyable: false + is_movable: true + is_readable: true + module: __main__ + scaled_ic3: + classname: ScaleSignal + is_flyable: false + is_movable: true + is_readable: true + module: __main__ + scaled_ic4: + classname: ScaleSignal + is_flyable: false + is_movable: true + is_readable: true + module: __main__ + schi: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + smx: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + smy: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + smy2: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + smz: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + sphi: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + stats_plugin: + classname: StatsPluginV33 + is_flyable: false + is_movable: false + is_readable: true + module: nslsii.ad33 + sth: + classname: EpicsMotor + components: + acceleration: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + direction_of_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + high_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_forward: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + home_reverse: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_switch: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + low_limit_travel: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_done_move: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_egu: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_is_moving: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + motor_stop: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + offset_freeze_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + set_use_switch: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_offset_dir: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_readback: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + user_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + velocity: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.epics_motor + tempCntlOmega: + classname: OmegaTempCntl78000 + components: + temperature_current: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + temperature_setpoint: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: false + is_readable: true + module: __main__ + two_blade_shutter: + classname: TwoBladeShutter + components: + blade1_pos: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + blade2_pos: + classname: EpicsSignalRO + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + cmd: + classname: EpicsSignal + is_flyable: false + is_movable: true + is_readable: true + module: ophyd.signal + is_flyable: false + is_movable: true + is_readable: true + module: __main__ +existing_plans: + TTL2_on: + module: __main__ + name: TTL2_on + parameters: [] + 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 + 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 + agent_feedback_plan: + description: Plan for adaptive round 2} + module: __main__ + name: agent_feedback_plan + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: sample_x + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: md + properties: + is_generator: true + agent_feedback_time_plan: + description: The main data acqusition plan for the adaptive experiments + module: __main__ + name: agent_feedback_time_plan + parameters: + - annotation: + type: float + description: The absolute position to measure the sample at transverse to beam + (and along gradient) + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: sample_x + - annotation: + type: float + description: 'Seconds from epoch. Do not take the data before this wall time. If + in the past, take + + data as soon as possible' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: target_time + - annotation: + type: bool + default: 'False' + description: If `fast_align` should be used before taking data + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: align + - annotation: + type: float + default: '5' + description: The exposure time in seconds. + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exposure + - default: None + description: Any additional payload to put in the start document. + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: md + properties: + is_generator: true + agent_start_sample: + description: The plan to start an adaptive experiment. + module: __main__ + name: agent_start_sample + parameters: + - annotation: + type: list[float] + description: The initial sample positions to take data at. + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: init_x_pos + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + agent_stop_sample: + description: Plan to run when the agent is done and would like no more data. + module: __main__ + name: agent_stop_sample + parameters: + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: md + properties: + is_generator: true + alignNewSample: + module: __main__ + name: alignNewSample + parameters: [] + properties: + is_generator: true + align_motor_th: + module: __main__ + name: align_motor_th + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: det + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: mtr + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: start_rel + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: stop_rel + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: step + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exp_time + - default: 'True' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: fine_scan + - default: '0.1' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: mtr_backlash + - default: '0.1' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: mtr_max_velocity + properties: + is_generator: true + align_motor_y: + module: __main__ + name: align_motor_y + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: det + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: mtr + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: start_rel + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: stop_rel + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: step + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exp_time + - default: '0.08' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: mtr_max_velocity + properties: + is_generator: true + align_stub: + module: __main__ + name: align_stub + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: det + - default: '0.3' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exp_time + properties: + is_generator: true + align_test2: + module: __main__ + name: align_test2 + parameters: [] + 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 + changeSample: + module: __main__ + name: changeSample + parameters: [] + 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 + description: The exit status to report in the Stop document + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exit_status + - default: None + description: Long-form description of why the run ended + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: reason + 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 + 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_forever_plan: + module: __main__ + name: count_forever_plan + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: det + properties: + is_generator: true + count_no_save_plan: + module: __main__ + name: count_no_save_plan + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: det + 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 + 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 + expose: + module: __main__ + name: expose + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exposure_time + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: extra + - default: '3' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: verbosity + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: md + properties: + is_generator: true + fake_coordinated_motion: + module: __main__ + name: fake_coordinated_motion + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: mtr1 + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: target1 + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: mtr2 + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: target2 + - default: '1000' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: N + properties: + is_generator: true + fake_coordinated_motionr: + module: __main__ + name: fake_coordinated_motionr + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: mtr1 + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: mtr2 + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: delta + - default: '0.1' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: step + properties: + is_generator: true + fake_fly3: + module: __main__ + name: fake_fly3 + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: det + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: mtr + - 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: step + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exp_time + properties: + is_generator: true + fast_align: + description: Attempt to align the detector. + module: __main__ + name: fast_align + parameters: + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: det + 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 + 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 + 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 + 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 + 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 + measure: + description: Measure data by triggering the area detectors. + module: __main__ + name: measure + parameters: + - description: The sample object to measure. + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: sample + - default: None + description: The list of detectors. + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - default: None + description: How long to collect data + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exposure_time + - default: None + description: 'Extra information about this particular measurement (which is + typically + + included in the savename/filename).' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: extra + - default: '''measure''' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: measure_type + - default: '3' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: verbosity + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: tiling_type + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: md + properties: + is_generator: true + measure_single: + description: Measure data by triggering the area detectors. + module: __main__ + name: measure_single + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: sample + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - default: None + description: How long to collect data + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exposure_time + - default: '''measure''' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: measure_type + - default: '3' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: verbosity + - default: 'True' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: handlefile + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + 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_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_with_laser: + description: Moves the sample x and laserx in sync + module: __main__ + name: move_sample_with_laser + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: xpos + 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 + newSample: + module: __main__ + name: newSample + parameters: [] + 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 + 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 + 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 + pump_chm: + module: __main__ + name: pump_chm + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: onoff + - default: '0' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: q + 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 + rock_motor_per_step: + description: 'rock/swing a motor contineously while taking images + + use ''per_step'' function in scan plan to rock the motor' + module: __main__ + name: rock_motor_per_step + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detector + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: motor + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: step + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: rock_motor + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: rock_motor_limits + properties: + is_generator: true + sam_measure: + module: __main__ + name: sam_measure + parameters: + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: sample + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: exposure_time + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: extra + - default: '''measure''' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: measure_type + - default: '3' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: verbosity + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: tiling + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + 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, stop2,\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_off: + module: __main__ + name: shutter_off + parameters: + - default: '3' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: verbosity + properties: + is_generator: true + shutter_on: + module: __main__ + name: shutter_on + parameters: + - default: '3' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: verbosity + properties: + is_generator: true + shutter_state: + module: __main__ + name: shutter_state + parameters: + - default: '3' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: verbosity + 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 + stage_unstage_forever_plan: + module: __main__ + name: stage_unstage_forever_plan + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: det + properties: + is_generator: true + stage_unstage_once_plan: + module: __main__ + name: stage_unstage_once_plan + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: det + 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 + test_plan: + module: __main__ + name: test_plan + parameters: + - default: None + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detector + properties: + is_generator: true + tiling: + description: 'A helper function that applies tiling to a plan. + + Tiling is used to fill gaps between the detector chips.' + module: __main__ + name: tiling + parameters: + - description: 'The list of detectors used in the plan. + + Detectors in this list that we know how to tiled, will get tiled.' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: detectors + - description: "expected signature:\n\n def plan(detectors, md):\n '''\n\ + \ Parameters\n ----------\n detectors: list\n \ + \ The list of detectors to use in the plan.\n md: dict\n Plan\ + \ metadata.\n '''\n ..." + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: inner_plan + - default: None + description: 'has one of the following values: None, ''xgaps'', ''xygaps''' + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: tiling_type + - default: None + description: Plan metadata. + kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: md + properties: + is_generator: true + tri_plan: + module: __main__ + name: tri_plan + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: tri + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: value + 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 + trigger_forever_plan: + module: __main__ + name: trigger_forever_plan + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: det + 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 + 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/notes b/startup/notes new file mode 100644 index 0000000..ce800a9 --- /dev/null +++ b/startup/notes @@ -0,0 +1,27 @@ +sam.runSpinner +sam.setSpeed +sam.setSpeeds +sam.test_pump +sam.LinkamTensileSeries_step +sam.SR_B1-Spin1500rpm +sam._measure_exttrigger +sample_plan +setAO +setExposure +shutter_on +shutter_off +spinner_test +spinner_test1 +xxx +LTensile._mov +LTensile._setDirection +bp.count +bp.mov +bps.mov +changePV +count +executable.py +nabt +pilatus2m.setExposureTime +pilatus800.setExposureTime +pilatus800s.setExposureTime diff --git a/startup/old_11-motors_utilities.py b/startup/old_11-motors_utilities.py index b7f55e8..1f56102 100644 --- a/startup/old_11-motors_utilities.py +++ b/startup/old_11-motors_utilities.py @@ -1,3 +1,5 @@ +print(f"Loading {__file__!r} ...") + # def wh_all(): # wh_pos([mono_bragg,mono_pitch2,mono_roll2,mono_perp2]) # wh_pos([mir_usx,mir_dsx,mir_usy,mir_dsyi,mir_dsyo,mir_bend]) diff --git a/startup/requirements.txt b/startup/requirements.txt new file mode 100644 index 0000000..e6587f0 --- /dev/null +++ b/startup/requirements.txt @@ -0,0 +1,14 @@ +appdirs==1.4.4 +bluesky==1.10.0 +caproto==1.0.0 +ipython==8.9.0 +lmfit==1.1.0 +msgpack_numpy==0.4.8 +msgpack_python==0.5.6 +nslsii==0.9.0 +ophyd==1.7.0 +pandas==1.5.3 +pyOlog==4.5.0 +requests==2.28.2 +scipy==1.10.0 +zict==2.2.0 diff --git a/startup/user_collection/user_HighVoltage.py b/startup/user_collection/user_HighVoltage.py index 4d24780..3de4b62 100644 --- a/startup/user_collection/user_HighVoltage.py +++ b/startup/user_collection/user_HighVoltage.py @@ -110,12 +110,7 @@ def __init__(self, name, base=None, **md): # self.incident_angles_default = [0.08, 0.12, 0.15, 0.18, 0.20] #for 10kev # self.incident_angles_default = [0.08, 0.12, 0.15, 0.18] #for 10kev LJR # self.incident_angles_default = [0.12, 0.16, 0.20, 0.24] #for 10kev, Perovskites - self.incident_angles_default = [ - 0.12, - 0.16, - 0.20, - 0.24, - ] # for 10kev, Perovskites + self.incident_angles_default = [0.12, 0.16, 0.20, 0.24] # for 10kev, Perovskites # self.incident_angles_default = [0.02, 0.04, 0.05, 0.06, 0.08, 0.09, 0.1, 0.12, 0.15] # self.incident_angles_default = [0.02, 0.04, 0.06, 0.08, 0.1, 0.12, 0.15] # self.incident_angles_default = [0.0] @@ -483,14 +478,7 @@ def alignQuick(self, align_step=8, reflection_angle=0.12, verbosity=3): get_beamline().modeMeasurement() - def align_crazy( - self, - reflection_angle=0.12, - ROI_size=[10, 180], - th_range=0.3, - int_threshold=10, - verbosity=3, - ): + def align_crazy(self, reflection_angle=0.12, ROI_size=[10, 180], th_range=0.3, int_threshold=10, verbosity=3): # def ROI3 in 160pixels with the center located at reflection beam get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2, size=ROI_size) # set ROI3 @@ -596,12 +584,7 @@ def align_custom(self, step=0, reflection_angle=0.08, verbosity=3): # Find the step-edge self.ysearch( - step_size=0.5, - min_step=0.005, - intensity=value, - target=0.5, - verbosity=verbosity, - polarity=-1, + step_size=0.5, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1 ) # Find the peak @@ -706,13 +689,7 @@ def __init__(self, name="OffCenteredHoderCustom", base=None, **kwargs): # if sample.detector=='WAXS': # sample.do_WAXS() - def doSamples( - self, - sequence="Outer", - exposure_WAXS_time=10, - exposure_SAXS_time=60, - verbosity=3, - ): + def doSamples(self, sequence="Outer", exposure_WAXS_time=10, exposure_SAXS_time=60, verbosity=3): if sequence == "Outer": step = 0 elif sequence == "Inner": diff --git a/startup/user_collection/user_InstecStage.py b/startup/user_collection/user_InstecStage.py index 15690ce..9e89a16 100644 --- a/startup/user_collection/user_InstecStage.py +++ b/startup/user_collection/user_InstecStage.py @@ -149,11 +149,7 @@ def __init__(self, name, base=None, **md): # self.incident_angles_default = [0.02, 0.04, 0.06, 0.08, 0.1, 0.12, 0.15] def measure_mesh_scan( - self, - num_spots=50 + 1, - translation_amount_y=0.1, - translation_amount_x=0.1, - exposure_time=3, + self, num_spots=50 + 1, translation_amount_y=0.1, translation_amount_x=0.1, exposure_time=3 ): self.naming_scheme = ["name", "extra", "x", "y", "exposure_time"] @@ -162,9 +158,7 @@ def measure_mesh_scan( self.xabs(-2.5) time.sleep(2) sam.measureSpots( - num_spots=num_spots, - translation_amount=translation_amount_x, - exposure_time=exposure_time, + num_spots=num_spots, translation_amount=translation_amount_x, exposure_time=exposure_time ) def align(self, step=0, reflection_angle=0.08, verbosity=3): @@ -222,12 +216,7 @@ def align(self, step=0, reflection_angle=0.08, verbosity=3): # Find the step-edge self.ysearch( - step_size=0.5, - min_step=0.005, - intensity=value, - target=0.5, - verbosity=verbosity, - polarity=-1, + step_size=0.5, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1 ) # Find the peak @@ -356,13 +345,7 @@ def temperature_cool_series( ## for Instec 402 stage def tscan( - self, - temperature_start, - temperature_final, - num_intervals, - wait_time, - temp_update_time=5, - exposure_time=0, + self, temperature_start, temperature_final, num_intervals, wait_time, temp_update_time=5, exposure_time=0 ): if temperature_start == None or temperature_start < 0.0 or temperature_start >= 250: print("temperature_start must be set between 0 and 250 degC.\n") @@ -405,11 +388,7 @@ def tscan( print("{:.3f} {:.3f}".format(current_time, current_temperature)) # f.write('{:d} {:.3f} {:.3f}\n'.format(RE.md['scan_id'], current_time, current_temperature)) self.tscan_data = self.tscan_data.append( - { - "scan_id": RE.md["scan_id"], - "degC": current_temperature, - "seconds": current_time, - }, + {"scan_id": RE.md["scan_id"], "degC": current_temperature, "seconds": current_time}, ignore_index=True, ) @@ -465,13 +444,7 @@ def __init__(self, name="CapillaryHolder", base=None, **kwargs): self.x_spacing = 0.2 * 25.4 # 0.2" seperation in x def tscan( - self, - temperature_start, - temperature_final, - num_intervals, - wait_time, - temp_update_time=5, - exposure_time=0, + self, temperature_start, temperature_final, num_intervals, wait_time, temp_update_time=5, exposure_time=0 ): if temperature_start == None or temperature_start < 0.0 or temperature_start >= 250: print("temperature_start must be set between 0 and 250 degC.\n") @@ -514,11 +487,7 @@ def tscan( print("{:.3f} {:.3f}".format(current_time, current_temperature)) # f.write('{:d} {:.3f} {:.3f}\n'.format(RE.md['scan_id'], current_time, current_temperature)) self.tscan_data = self.tscan_data.append( - { - "scan_id": RE.md["scan_id"], - "degC": current_temperature, - "seconds": current_time, - }, + {"scan_id": RE.md["scan_id"], "degC": current_temperature, "seconds": current_time}, ignore_index=True, ) diff --git a/startup/user_collection/user_LinkamTensile.py b/startup/user_collection/user_LinkamTensile.py index 3a8b173..732af64 100644 --- a/startup/user_collection/user_LinkamTensile.py +++ b/startup/user_collection/user_LinkamTensile.py @@ -192,12 +192,7 @@ def __init__(self, name, base=None, **md): # self.incident_angles_default = [0.08, 0.12, 0.15, 0.18, 0.20] #for 10kev # self.incident_angles_default = [0.08, 0.12, 0.15, 0.18] #for 10kev LJR # self.incident_angles_default = [0.12, 0.16, 0.20, 0.24] #for 10kev, Perovskites - self.incident_angles_default = [ - 0.12, - 0.16, - 0.20, - 0.24, - ] # for 10kev, Perovskites + self.incident_angles_default = [0.12, 0.16, 0.20, 0.24] # for 10kev, Perovskites # self.incident_angles_default = [0.02, 0.04, 0.05, 0.06, 0.08, 0.09, 0.1, 0.12, 0.15] # self.incident_angles_default = [0.02, 0.04, 0.06, 0.08, 0.1, 0.12, 0.15] # self.incident_angles_default = [0.0] @@ -464,12 +459,7 @@ def LinkamTensile_step_builder(self): return self.LinkamTensile_stages_default def LinkamTensileMeasure_step( - self, - step=0, - maxTime=60 * 60 * 10, - exposure_time=1, - interval=3, - reset_clock=True, + self, step=0, maxTime=60 * 60 * 10, exposure_time=1, interval=3, reset_clock=True ): self.LinkamTensile_stages_default # @@ -493,14 +483,9 @@ def LinkamTensileMeasure_step( # for temperature, rate, wait_time in zip(temp_sequence, rate_sequence, wait_sequence): for stage in range(stages): - ( - stepNo, - temperature, - rate, - wait_time, - position, - velocity, - ) = self.LinkamTensile_stages_default.loc[stage] + stepNo, temperature, rate, wait_time, position, velocity = self.LinkamTensile_stages_default.loc[ + stage + ] print("Stage {} : {}".format(stage, self.LinkamTensile_stages_default.loc[stage])) @@ -615,14 +600,9 @@ def inner(paras, **md): # status = yield from bps.trigger(detector, group='det') for stage in range(stages): - ( - stepNo, - temperature, - rate, - wait_time, - position, - velocity, - ) = self.LinkamTensile_stages_default.loc[stage] + stepNo, temperature, rate, wait_time, position, velocity = self.LinkamTensile_stages_default.loc[ + stage + ] print("Stage {} : {}".format(stage, self.LinkamTensile_stages_default.loc[stage])) diff --git a/startup/user_collection/user_LinkamThermal.py b/startup/user_collection/user_LinkamThermal.py index d5c7cbc..8070313 100644 --- a/startup/user_collection/user_LinkamThermal.py +++ b/startup/user_collection/user_LinkamThermal.py @@ -151,14 +151,7 @@ def __init__(self, name, base=None, **md): # self.naming_scheme = ['name', 'extra', 'th', 'exposure_time'] # self.naming_scheme = ['name', 'extra', 'th', 'exposure_time'] # self.naming_scheme = ['name', 'extra', 'y', 'th', 'clock', 'exposure_time'] - self.naming_scheme = [ - "name", - "extra", - "id", - "clock", - "temperature_Linkam", - "exposure_time", - ] + self.naming_scheme = ["name", "extra", "id", "clock", "temperature_Linkam", "exposure_time"] # self.naming_scheme = ['name', 'extra', 'clock', 'temperature', 'exposure_time'] self._axes["x"].origin = -16.9 @@ -177,12 +170,7 @@ def __init__(self, name, base=None, **md): # self.incident_angles_default = [0.08, 0.12, 0.15, 0.18, 0.20] #for 10kev # self.incident_angles_default = [0.08, 0.12, 0.15, 0.18] #for 10kev LJR # self.incident_angles_default = [0.12, 0.16, 0.20, 0.24] #for 10kev, Perovskites - self.incident_angles_default = [ - 0.12, - 0.16, - 0.20, - 0.24, - ] # for 10kev, Perovskites + self.incident_angles_default = [0.12, 0.16, 0.20, 0.24] # for 10kev, Perovskites # self.incident_angles_default = [0.02, 0.04, 0.05, 0.06, 0.08, 0.09, 0.1, 0.12, 0.15] # self.incident_angles_default = [0.02, 0.04, 0.06, 0.08, 0.1, 0.12, 0.15] # self.incident_angles_default = [0.0] diff --git a/startup/user_collection/user_TSAXSWAXS_stitching.py b/startup/user_collection/user_TSAXSWAXS_stitching.py index 6ef33d0..872cec6 100755 --- a/startup/user_collection/user_TSAXSWAXS_stitching.py +++ b/startup/user_collection/user_TSAXSWAXS_stitching.py @@ -108,12 +108,7 @@ def __init__(self, name, base=None, **md): # self.incident_angles_default = [0.08, 0.12, 0.15, 0.18, 0.20] #for 10kev # self.incident_angles_default = [0.08, 0.12, 0.15, 0.18] #for 10kev LJR # self.incident_angles_default = [0.12, 0.16, 0.20, 0.24] #for 10kev, Perovskites - self.incident_angles_default = [ - 0.12, - 0.16, - 0.20, - 0.24, - ] # for 10kev, Perovskites + self.incident_angles_default = [0.12, 0.16, 0.20, 0.24] # for 10kev, Perovskites # self.incident_angles_default = [0.02, 0.04, 0.05, 0.06, 0.08, 0.09, 0.1, 0.12, 0.15] # self.incident_angles_default = [0.02, 0.04, 0.06, 0.08, 0.1, 0.12, 0.15] # self.incident_angles_default = [0.0] @@ -481,14 +476,7 @@ def alignQuick(self, align_step=8, reflection_angle=0.12, verbosity=3): get_beamline().modeMeasurement() - def align_crazy( - self, - reflection_angle=0.12, - ROI_size=[10, 180], - th_range=0.3, - int_threshold=10, - verbosity=3, - ): + def align_crazy(self, reflection_angle=0.12, ROI_size=[10, 180], th_range=0.3, int_threshold=10, verbosity=3): # def ROI3 in 160pixels with the center located at reflection beam get_beamline().setReflectedBeamROI(total_angle=reflection_angle * 2, size=ROI_size) # set ROI3 @@ -594,12 +582,7 @@ def align_custom(self, step=0, reflection_angle=0.08, verbosity=3): # Find the step-edge self.ysearch( - step_size=0.5, - min_step=0.005, - intensity=value, - target=0.5, - verbosity=verbosity, - polarity=-1, + step_size=0.5, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1 ) # Find the peak @@ -704,13 +687,7 @@ def __init__(self, name="OffCenteredHoderCustom", base=None, **kwargs): # if sample.detector=='WAXS': # sample.do_WAXS() - def doSamples( - self, - sequence="Outer", - exposure_WAXS_time=10, - exposure_SAXS_time=60, - verbosity=3, - ): + def doSamples(self, sequence="Outer", exposure_WAXS_time=10, exposure_SAXS_time=60, verbosity=3): if sequence == "Outer": step = 0 elif sequence == "Inner": diff --git a/startup/user_collection/user_TemperarureRamp.py b/startup/user_collection/user_TemperarureRamp.py index 99bf3e4..1914578 100644 --- a/startup/user_collection/user_TemperarureRamp.py +++ b/startup/user_collection/user_TemperarureRamp.py @@ -258,12 +258,7 @@ def doCustom(self, step=0, exposure_time=1, verbosity=3, **md): # self.thabs(0.0) def alignVeryQuick( - self, - intensity=INTENSITY_EXPECTED_025, - align_step=9, - reflection_angle=0.07, - mode_control=True, - verbosity=3, + self, intensity=INTENSITY_EXPECTED_025, align_step=9, reflection_angle=0.07, mode_control=True, verbosity=3 ): if mode_control: get_beamline().modeAlignment() @@ -318,12 +313,7 @@ def __init__(self, name="CapillaryHolder", base=None, **kwargs): # self.temp_series_heating2 = np.arange(100, 150, 5) # self.temp_series_heating3 = np.arange(150, 235+.1, 2) self.temp_series = np.concatenate( - ( - self.temp_series_heating1, - self.temp_series_heating2, - self.temp_series_heating3, - ), - axis=0, + (self.temp_series_heating1, self.temp_series_heating2, self.temp_series_heating3), axis=0 ) # self.temp_series_cooling = np.arange(230, 100-.1, -5) # self.temp_series = np.concatenate((self.temp_series_heating, self.temp_series_cooling), axis=0) @@ -364,13 +354,7 @@ def doTemperature_cool( ): for sample in self.getSamples(): # sample.incident_angles_default = [0.08, 0.1, 0.12] - sample.naming_scheme = [ - "name", - "extra", - "temperature", - "clock", - "exposure_time", - ] + sample.naming_scheme = ["name", "extra", "temperature", "clock", "exposure_time"] ##run the Bar at RT # if step < 1: @@ -398,8 +382,7 @@ def doTemperature_cool( if verbosity >= 3: print( " setpoint = {:.3f}°C, Temperature = {:.3f}°C \r".format( - self.temperature_setpoint() - 273.15, - self.temperature(verbosity=0), + self.temperature_setpoint() - 273.15, self.temperature(verbosity=0) ), end="", ) @@ -458,13 +441,7 @@ def doTemperature_heat( **md, ): for sample in self.getSamples(): - sample.naming_scheme = [ - "name", - "extra", - "temperature", - "clock", - "exposure_time", - ] + sample.naming_scheme = ["name", "extra", "temperature", "clock", "exposure_time"] # sample.naming_scheme = ['name', 'extra', 'temperature_B', 'clock', 'exposure_time'] # run the Bar at RT @@ -483,8 +460,7 @@ def doTemperature_heat( if verbosity >= 3: print( " setpoint = {:.3f}°C, Temperature = {:.3f}°C \r".format( - self.temperature_setpoint() - 273.15, - self.temperature(verbosity=0), + self.temperature_setpoint() - 273.15, self.temperature(verbosity=0) ), end="", ) @@ -519,13 +495,7 @@ def doTemperature_ramp( **md, ): for sample in self.getSamples(): - sample.naming_scheme = [ - "name", - "extra", - "temperature", - "clock", - "exposure_time", - ] + sample.naming_scheme = ["name", "extra", "temperature", "clock", "exposure_time"] # sample.naming_scheme = ['name', 'extra', 'temperature_B', 'clock', 'exposure_time'] # run the Bar at RT @@ -544,8 +514,7 @@ def doTemperature_ramp( if verbosity >= 3: print( " setpoint = {:.3f}°C, Temperature = {:.3f}°C \r".format( - self.temperature_setpoint() - 273.15, - self.temperature(verbosity=0), + self.temperature_setpoint() - 273.15, self.temperature(verbosity=0) ), end="", ) @@ -581,13 +550,7 @@ def doTemperature_static( ): for sample in self.getSamples(): # sample.incident_angles_default = [0.08, 0.1, 0.12] - sample.naming_scheme = [ - "name", - "extra", - "temperature", - "clock", - "exposure_time", - ] + sample.naming_scheme = ["name", "extra", "temperature", "clock", "exposure_time"] ##run the Bar at RT # if step < 1: @@ -660,14 +623,7 @@ def doTemperature_series( **md, ): self.incident_angles_default = [0.08, 0.1, 0.12] - self.naming_scheme = [ - "name", - "extra", - "temperature", - "th", - "x", - "exposure_time", - ] + self.naming_scheme = ["name", "extra", "temperature", "th", "x", "exposure_time"] # run the sample at RT # if step < 1: @@ -689,8 +645,7 @@ def doTemperature_series( if verbosity >= 3: print( " setpoint = {:.3f}°C, Temperature = {:.3f}°C \r".format( - self.temperature_setpoint() - 273.15, - self.temperature(verbosity=0), + self.temperature_setpoint() - 273.15, self.temperature(verbosity=0) ), end="", ) @@ -751,8 +706,7 @@ def doTemperature_series( if verbosity >= 3: print( " setpoint = {:.3f}°C, Temperature = {:.3f}°C \r".format( - self.temperature_setpoint() - 273.15, - self.temperature(verbosity=0), + self.temperature_setpoint() - 273.15, self.temperature(verbosity=0) ), end="", ) diff --git a/startup/user_collection/user_XR.py b/startup/user_collection/user_XR.py index 52f199b..446a0c9 100644 --- a/startup/user_collection/user_XR.py +++ b/startup/user_collection/user_XR.py @@ -186,12 +186,7 @@ def align(self, step=0, reflection_angle=0.08, verbosity=3): # Find the step-edge self.ysearch( - step_size=0.5, - min_step=0.005, - intensity=value, - target=0.5, - verbosity=verbosity, - polarity=-1, + step_size=0.5, min_step=0.005, intensity=value, target=0.5, verbosity=verbosity, polarity=-1 ) # Find the peak @@ -243,12 +238,7 @@ def align(self, step=0, reflection_angle=0.08, verbosity=3): beam.off() def alignVeryQuick( - self, - intensity=INTENSITY_EXPECTED_025, - align_step=9, - reflection_angle=0.07, - mode_control=True, - verbosity=3, + self, intensity=INTENSITY_EXPECTED_025, align_step=9, reflection_angle=0.07, mode_control=True, verbosity=3 ): if mode_control: get_beamline().modeAlignment() @@ -400,14 +390,7 @@ def doTemperature_series_heat( for sample in self.getSamples(): sample.incident_angles_default = [0.1] - sample.naming_scheme = [ - "name", - "extra", - "temperature", - "th", - "x", - "exposure_time", - ] + sample.naming_scheme = ["name", "extra", "temperature", "th", "x", "exposure_time"] # run the Bar at RT if step < 1: @@ -434,8 +417,7 @@ def doTemperature_series_heat( if verbosity >= 3: print( " setpoint = {:.3f}°C, Temperature = {:.3f}°C \r".format( - self.temperature_setpoint() - 273.15, - self.temperature(verbosity=0), + self.temperature_setpoint() - 273.15, self.temperature(verbosity=0) ), end="", ) diff --git a/startup/user_collection/user_humidity.py b/startup/user_collection/user_humidity.py index 5822aa9..2bc821b 100644 --- a/startup/user_collection/user_humidity.py +++ b/startup/user_collection/user_humidity.py @@ -94,14 +94,7 @@ def __init__(self, name, base=None, **md): # self.naming_scheme = ['name', 'extra', 'th', 'exposure_time'] # self.naming_scheme = ['name', 'extra', 'th', 'exposure_time'] # self.naming_scheme = ['name', 'extra', 'y', 'th', 'clock', 'exposure_time'] - self.naming_scheme = [ - "name", - "extra", - "clock", - "humidity", - "th", - "exposure_time", - ] + self.naming_scheme = ["name", "extra", "clock", "humidity", "th", "exposure_time"] # self.naming_scheme = ['name', 'extra', 'clock', 'temperature', 'exposure_time'] self.md["exposure_time"] = 1 @@ -763,53 +756,19 @@ def swaxs_on(): # compacted.addGaragePosition(-1,-1) oe = -8 hol2.addSampleSlotPosition( - Sample("QF_FS_prinstine_1-1", **md), - 1, - 5 + oe, - "BOTH", - incident_angles=[0.1, 0.12, 0.15], + Sample("QF_FS_prinstine_1-1", **md), 1, 5 + oe, "BOTH", incident_angles=[0.1, 0.12, 0.15] ) hol2.addSampleSlotPosition( - Sample("QF_FS_prinstine_2-1", **md), - 2, - 15 + oe, - "BOTH", - incident_angles=[0.1, 0.12, 0.15], + Sample("QF_FS_prinstine_2-1", **md), 2, 15 + oe, "BOTH", incident_angles=[0.1, 0.12, 0.15] ) hol2.addSampleSlotPosition( - Sample("QF_FS_chloroform-2", **md), - 3, - 25 + oe, - "BOTH", - incident_angles=[0.1, 0.12, 0.15], + Sample("QF_FS_chloroform-2", **md), 3, 25 + oe, "BOTH", incident_angles=[0.1, 0.12, 0.15] ) + hol2.addSampleSlotPosition(Sample("QF_FS_BA-1", **md), 4, 37 + oe, "BOTH", incident_angles=[0.1, 0.12, 0.15]) + hol2.addSampleSlotPosition(Sample("QF_FS_DCM-1", **md), 5, 45 + oe, "BOTH", incident_angles=[0.1, 0.12, 0.15]) + hol2.addSampleSlotPosition(Sample("QF_FS_DMF-2", **md), 6, 55 + oe, "BOTH", incident_angles=[0.1, 0.12, 0.15]) hol2.addSampleSlotPosition( - Sample("QF_FS_BA-1", **md), - 4, - 37 + oe, - "BOTH", - incident_angles=[0.1, 0.12, 0.15], - ) - hol2.addSampleSlotPosition( - Sample("QF_FS_DCM-1", **md), - 5, - 45 + oe, - "BOTH", - incident_angles=[0.1, 0.12, 0.15], - ) - hol2.addSampleSlotPosition( - Sample("QF_FS_DMF-2", **md), - 6, - 55 + oe, - "BOTH", - incident_angles=[0.1, 0.12, 0.15], - ) - hol2.addSampleSlotPosition( - Sample("QF_FS_water-2", **md), - 7, - 65 + oe, - "BOTH", - incident_angles=[0.1, 0.12, 0.15], + Sample("QF_FS_water-2", **md), 7, 65 + oe, "BOTH", incident_angles=[0.1, 0.12, 0.15] ) # hol2 = GIBar_Custom(base=stg) diff --git a/startup/user_group_permissions.yaml b/startup/user_group_permissions.yaml new file mode 100644 index 0000000..8106962 --- /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: + - null # Allow all + forbidden_plans: + - ":^_" # All plans with names starting with '_' + allowed_devices: + - null # Allow all + forbidden_devices: + - ":^_:?.*" # All devices with names starting with '_' and their subdevices + allowed_functions: + - null # Allow all + forbidden_functions: + - ":^_" # All functions with names starting with '_' + primary: + allowed_plans: + - ":^count" # Allow all plan names starting with 'count' + - ":^sleep" + - "sam_measure" + - ":^yolo" + - "test_plan" + - "feedback_plan" + - ":^agent_" + allowed_devices: + - ":^pilatus:?.*" # Allow all devices starting with 'det' and their subdevices + - ":^smy" \ No newline at end of file