Compare commits
1 Commits
refactor/i
...
update_bl_
| Author | SHA1 | Date | |
|---|---|---|---|
| cc2e0ecaa3 |
@@ -1,9 +0,0 @@
|
||||
# Do not edit this file!
|
||||
# It is needed to track the repo template version, and editing may break things.
|
||||
# This file will be overwritten by copier on template updates.
|
||||
|
||||
_commit: v1.0.0
|
||||
_src_path: https://github.com/bec-project/plugin_copier_template.git
|
||||
make_commit: false
|
||||
project_name: csaxs_bec
|
||||
widget_plugins_input: []
|
||||
@@ -1,3 +0,0 @@
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
semantic-release changelog -D version_variable=$SCRIPT_DIR/../../semantic_release/__init__.py:__version__
|
||||
semantic-release version -D version_variable=$SCRIPT_DIR/../../semantic_release/__init__.py:__version__
|
||||
@@ -1,3 +1,2 @@
|
||||
black --line-length=100 $(git diff --cached --name-only --diff-filter=ACM -- '*.py')
|
||||
isort --line-length=100 --profile=black --multi-line=3 --trailing-comma $(git diff --cached --name-only --diff-filter=ACM -- '*.py')
|
||||
git add $(git diff --cached --name-only --diff-filter=ACM -- '*.py')
|
||||
black --line-length=100 $(git diff --cached --name-only --diff-filter=ACM)
|
||||
git add $(git diff --cached --name-only --diff-filter=ACM)
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -8,9 +8,6 @@
|
||||
**/.pytest_cache
|
||||
**/*.egg*
|
||||
|
||||
# recovery_config files
|
||||
recovery_config_*
|
||||
|
||||
# file writer data
|
||||
**.h5
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
include:
|
||||
- project: bec/awi_utils
|
||||
file: /templates/plugin-repo-template.yml
|
||||
inputs:
|
||||
name: "csaxs"
|
||||
target: "csaxs_bec"
|
||||
branch: $CHILD_PIPELINE_BRANCH
|
||||
|
||||
pages:
|
||||
stage: Deploy
|
||||
needs: []
|
||||
variables:
|
||||
TARGET_BRANCH: $CI_COMMIT_REF_NAME
|
||||
rules:
|
||||
- if: "$CI_COMMIT_TAG != null"
|
||||
variables:
|
||||
TARGET_BRANCH: $CI_COMMIT_TAG
|
||||
- if: '$CI_COMMIT_REF_NAME == "main" && $CI_PROJECT_PATH == "bec/csaxs_bec"'
|
||||
script:
|
||||
- curl -X POST -d "branches=$CI_COMMIT_REF_NAME" -d "token=$RTD_TOKEN" https://readthedocs.org/api/v2/webhook/sls-csaxs/270162/
|
||||
@@ -1,29 +0,0 @@
|
||||
# .readthedocs.yaml
|
||||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
version: 2
|
||||
|
||||
# Set the version of Python and other tools you might need
|
||||
build:
|
||||
os: ubuntu-20.04
|
||||
tools:
|
||||
python: "3.10"
|
||||
jobs:
|
||||
pre_install:
|
||||
- pip install .
|
||||
|
||||
|
||||
# Build documentation in the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
configuration: docs/conf.py
|
||||
|
||||
# If using Sphinx, optionally build your docs in additional formats such as PDF
|
||||
# formats:
|
||||
# - pdf
|
||||
|
||||
# Optionally declare the Python requirements required to build your docs
|
||||
python:
|
||||
install:
|
||||
- requirements: docs/requirements.txt
|
||||
|
||||
29
LICENSE
29
LICENSE
@@ -1,29 +0,0 @@
|
||||
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2025, Paul Scherrer Institute
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
69
README.md
69
README.md
@@ -6,12 +6,15 @@ You might want to run cSAXS copy scripts before in case you want to have the for
|
||||
|
||||
## Overview
|
||||
|
||||
- Clone cSAXS BEC repository into e-account (e.g. into ~/Data10/software/.)
|
||||
- Start Epics iocs
|
||||
- Start BEC, BEC server and load/modify the device config with relevant hardware
|
||||
- BEC commands
|
||||
1. Clone cSAXS BEC repository into e-account (e.g. into ~/Data10/software/.)
|
||||
2. Install BEC
|
||||
3. Start Epics iocs
|
||||
4. Start BEC, BEC server and load/modify the device config with relevant hardware
|
||||
5. BEC commands
|
||||
6. Start BEC widgets (GUI for motor control, eiger live plot)
|
||||
7. Troubleshooting and common problems
|
||||
|
||||
## Clone cSAXS BEC repository
|
||||
## 1. Clone cSAXS BEC repository
|
||||
|
||||
Clone the current cSAXS BEC repository from GIT into the new e-account.
|
||||
Create directory
|
||||
@@ -21,9 +24,19 @@ cd ~/Data10/software
|
||||
```
|
||||
Clone repository
|
||||
```bash
|
||||
git clone https://gitlab.psi.ch/bec/csaxs_bec.git
|
||||
git clone https://gitlab.psi.ch/bec/csaxs-bec.git
|
||||
```
|
||||
## Start epics iocs
|
||||
|
||||
## 2. Install BEC
|
||||
|
||||
There is a bash sript in the followin directory.
|
||||
Go to the directory and run the script on pc15543 logged in as the e-account (BEC server):
|
||||
```bash
|
||||
ssh pc15543
|
||||
cd ~/Data10/software/csaxs-bec/bin/
|
||||
./setup_bec.sh
|
||||
```
|
||||
## 3. Start epics iocs
|
||||
|
||||
You can start up the iocs while the *./setup_bec.sh* script is running. Be aware though that the scripts requires you to interact with it.
|
||||
|
||||
@@ -81,7 +94,7 @@ iocsh -7.0.6 startup.script
|
||||
```
|
||||
Be aware -7.0.6 is referring to the current epics version and might change in future (SLS 2.0)
|
||||
|
||||
## Start BEC, BEC server and load device config
|
||||
## 4. Start BEC, BEC server and load device config
|
||||
|
||||
Step 1 needs to have finished for continuing with these steps.
|
||||
What remains now is to start the bec server. Connect to pc15543 and open a new terminal to run:
|
||||
@@ -114,7 +127,7 @@ bec.config.save_current_session('~/Data10/software/current_config.yaml')
|
||||
```
|
||||
The second command is helpful if you adjust limits of motors, which will then be stored in the config and loaded if a reload of the configuration is needed.
|
||||
|
||||
## BEC commands
|
||||
## 5. BEC commands
|
||||
|
||||
A number of commands that are useful:
|
||||
|
||||
@@ -134,3 +147,41 @@ scans.line_scan(dev.samx, -1, 1, dev.samy, -1, 1, steps=20, exp_time=0.5, readou
|
||||
scans.sgalil_grid(start_y = , end_y = , interval_y = , start_x=, end_x=, interval_x =, exp_time=0.5, readout_time=3e-3, relative=True)
|
||||
```
|
||||
|
||||
## 6. Start BEC widgets (GUI for motor control, eiger live plot)
|
||||
|
||||
To start the BEC widgets, the first step is to make the bec_widgets_venv using the start startup script.
|
||||
Follow the commands below:
|
||||
``` bash
|
||||
cd ~/Data10/software/csaxs-bec/bin
|
||||
./setup_bec_widgets.sh
|
||||
```
|
||||
Afterwards, activate the environment on either cons-01 comp-1/2
|
||||
``` bash
|
||||
cd ~/Data10/software/
|
||||
source activate bec_widgets_venv/bin/activate
|
||||
```
|
||||
Each Plot needs their own shell with activate environment
|
||||
|
||||
1. Eiger Plot
|
||||
``` bash
|
||||
cd ~/Data10/software/bec-widgets/bec_widgets/examples/eiger_plot
|
||||
python eiger_plot.py
|
||||
```
|
||||
2. Motor Controller
|
||||
``` bash
|
||||
cd ~/Data10/software/bec-widgets/bec_widgets/examples/motor_movement
|
||||
python motor_example.py --config csaxs_config.yaml
|
||||
```
|
||||
|
||||
## 7. Troubleshooting and common problems
|
||||
|
||||
Sometimes the data backend for the Eiger gets stuck or misses frames, this will result in an error
|
||||
``` python
|
||||
raise EigerTimeoutError(
|
||||
ophyd_devices.epics.devices.eiger9m_csaxs.EigerTimeoutError: Reached timeout with detector state 1, std_daq state FINISHED and received frames of 100 for the file writer)
|
||||
```
|
||||
This happens more likely after CTRL C of a scan. To recover from this more reliably, perform the an acquisition in burst mode with 100 frames, little exposure until no error message is raised after. This can be up to 3 times from former experience.
|
||||
``` bash
|
||||
scans.acquire(exp_time=0.02, frames_per_trigger=100, readout_time= 3e-3)
|
||||
```
|
||||
Afterwards, you should be good to continue with 2D gridscans.
|
||||
|
||||
1
bec_plugins/__init__.py
Normal file
1
bec_plugins/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .bec_client import *
|
||||
1
bec_plugins/bec_client/__init__.py
Normal file
1
bec_plugins/bec_client/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .plugins import *
|
||||
245
bec_plugins/bec_client/high_level_interface/spec_hli.py
Normal file
245
bec_plugins/bec_client/high_level_interface/spec_hli.py
Normal file
@@ -0,0 +1,245 @@
|
||||
from bec_lib.devicemanager import Device
|
||||
from bec_lib.scan_report import ScanReport
|
||||
|
||||
# pylint:disable=undefined-variable
|
||||
# pylint: disable=too-many-arguments
|
||||
|
||||
|
||||
def dscan(
|
||||
motor1: Device, m1_from: float, m1_to: float, steps: int, exp_time: float, **kwargs
|
||||
) -> ScanReport:
|
||||
"""Relative line scan with one device.
|
||||
|
||||
Args:
|
||||
motor1 (Device): Device that should be scanned.
|
||||
m1_from (float): Start position relative to the current position.
|
||||
m1_to (float): End position relative to the current position.
|
||||
steps (int): Number of steps.
|
||||
exp_time (float): Exposure time.
|
||||
|
||||
Returns:
|
||||
ScanReport: Status object.
|
||||
|
||||
Examples:
|
||||
>>> dscan(dev.motor1, -5, 5, 10, 0.1)
|
||||
"""
|
||||
return scans.line_scan(
|
||||
motor1, m1_from, m1_to, steps=steps, exp_time=exp_time, relative=True, **kwargs
|
||||
)
|
||||
|
||||
|
||||
def d2scan(
|
||||
motor1: Device,
|
||||
m1_from: float,
|
||||
m1_to: float,
|
||||
motor2: Device,
|
||||
m2_from: float,
|
||||
m2_to: float,
|
||||
steps: int,
|
||||
exp_time: float,
|
||||
**kwargs
|
||||
) -> ScanReport:
|
||||
"""Relative line scan with two devices.
|
||||
|
||||
Args:
|
||||
motor1 (Device): First device that should be scanned.
|
||||
m1_from (float): Start position of the first device relative to its current position.
|
||||
m1_to (float): End position of the first device relative to its current position.
|
||||
motor2 (Device): Second device that should be scanned.
|
||||
m2_from (float): Start position of the second device relative to its current position.
|
||||
m2_to (float): End position of the second device relative to its current position.
|
||||
steps (int): Number of steps.
|
||||
exp_time (float): Exposure time
|
||||
|
||||
Returns:
|
||||
ScanReport: Status object.
|
||||
|
||||
Examples:
|
||||
>>> d2scan(dev.motor1, -5, 5, dev.motor2, -8, 8, 10, 0.1)
|
||||
"""
|
||||
return scans.line_scan(
|
||||
motor1,
|
||||
m1_from,
|
||||
m1_to,
|
||||
motor2,
|
||||
m2_from,
|
||||
m2_to,
|
||||
steps=steps,
|
||||
exp_time=exp_time,
|
||||
relative=True,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
def ascan(motor1, m1_from, m1_to, steps, exp_time, **kwargs):
|
||||
"""Absolute line scan with one device.
|
||||
|
||||
Args:
|
||||
motor1 (Device): Device that should be scanned.
|
||||
m1_from (float): Start position.
|
||||
m1_to (float): End position.
|
||||
steps (int): Number of steps.
|
||||
exp_time (float): Exposure time.
|
||||
|
||||
Returns:
|
||||
ScanReport: Status object.
|
||||
|
||||
Examples:
|
||||
>>> ascan(dev.motor1, -5, 5, 10, 0.1)
|
||||
"""
|
||||
return scans.line_scan(
|
||||
motor1, m1_from, m1_to, steps=steps, exp_time=exp_time, relative=False, **kwargs
|
||||
)
|
||||
|
||||
|
||||
def a2scan(motor1, m1_from, m1_to, motor2, m2_from, m2_to, steps, exp_time, **kwargs):
|
||||
"""Absolute line scan with two devices.
|
||||
|
||||
Args:
|
||||
motor1 (Device): First device that should be scanned.
|
||||
m1_from (float): Start position of the first device.
|
||||
m1_to (float): End position of the first device.
|
||||
motor2 (Device): Second device that should be scanned.
|
||||
m2_from (float): Start position of the second device.
|
||||
m2_to (float): End position of the second device.
|
||||
steps (int): Number of steps.
|
||||
exp_time (float): Exposure time
|
||||
|
||||
Returns:
|
||||
ScanReport: Status object.
|
||||
|
||||
Examples:
|
||||
>>> a2scan(dev.motor1, -5, 5, dev.motor2, -8, 8, 10, 0.1)
|
||||
"""
|
||||
return scans.line_scan(
|
||||
motor1,
|
||||
m1_from,
|
||||
m1_to,
|
||||
motor2,
|
||||
m2_from,
|
||||
m2_to,
|
||||
steps=steps,
|
||||
exp_time=exp_time,
|
||||
relative=False,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
def dmesh(motor1, m1_from, m1_to, m1_steps, motor2, m2_from, m2_to, m2_steps, exp_time, **kwargs):
|
||||
"""Relative mesh scan (grid scan) with two devices.
|
||||
|
||||
Args:
|
||||
motor1 (Device): First device that should be scanned.
|
||||
m1_from (float): Start position of the first device relative to its current position.
|
||||
m1_to (float): End position of the first device relative to its current position.
|
||||
m1_steps (int): Number of steps for motor1.
|
||||
motor2 (Device): Second device that should be scanned.
|
||||
m2_from (float): Start position of the second device relative to its current position.
|
||||
m2_to (float): End position of the second device relative to its current position.
|
||||
m2_steps (int): Number of steps for motor2.
|
||||
exp_time (float): Exposure time
|
||||
|
||||
Returns:
|
||||
ScanReport: Status object.
|
||||
|
||||
Examples:
|
||||
>>> dmesh(dev.motor1, -5, 5, 10, dev.motor2, -8, 8, 10, 0.1)
|
||||
"""
|
||||
return scans.grid_scan(
|
||||
motor1,
|
||||
m1_from,
|
||||
m1_to,
|
||||
m1_steps,
|
||||
motor2,
|
||||
m2_from,
|
||||
m2_to,
|
||||
m2_steps,
|
||||
exp_time=exp_time,
|
||||
relative=True,
|
||||
)
|
||||
|
||||
|
||||
def amesh(motor1, m1_from, m1_to, m1_steps, motor2, m2_from, m2_to, m2_steps, exp_time, **kwargs):
|
||||
"""Absolute mesh scan (grid scan) with two devices.
|
||||
|
||||
Args:
|
||||
motor1 (Device): First device that should be scanned.
|
||||
m1_from (float): Start position of the first device.
|
||||
m1_to (float): End position of the first device.
|
||||
m1_steps (int): Number of steps for motor1.
|
||||
motor2 (Device): Second device that should be scanned.
|
||||
m2_from (float): Start position of the second device.
|
||||
m2_to (float): End position of the second device.
|
||||
m2_steps (int): Number of steps for motor2.
|
||||
exp_time (float): Exposure time
|
||||
|
||||
Returns:
|
||||
ScanReport: Status object.
|
||||
|
||||
Examples:
|
||||
>>> amesh(dev.motor1, -5, 5, 10, dev.motor2, -8, 8, 10, 0.1)
|
||||
"""
|
||||
return scans.grid_scan(
|
||||
motor1,
|
||||
m1_from,
|
||||
m1_to,
|
||||
m1_steps,
|
||||
motor2,
|
||||
m2_from,
|
||||
m2_to,
|
||||
m2_steps,
|
||||
exp_time=exp_time,
|
||||
relative=False,
|
||||
)
|
||||
|
||||
|
||||
def umv(*args) -> ScanReport:
|
||||
"""Updated absolute move (i.e. blocking) for one or more devices.
|
||||
|
||||
Returns:
|
||||
ScanReport: Status object.
|
||||
|
||||
Examples:
|
||||
>>> umv(dev.samx, 1)
|
||||
>>> umv(dev.samx, 1, dev.samy, 2)
|
||||
"""
|
||||
return scans.umv(*args, relative=False)
|
||||
|
||||
|
||||
def umvr(*args) -> ScanReport:
|
||||
"""Updated relative move (i.e. blocking) for one or more devices.
|
||||
|
||||
Returns:
|
||||
ScanReport: Status object.
|
||||
|
||||
Examples:
|
||||
>>> umvr(dev.samx, 1)
|
||||
>>> umvr(dev.samx, 1, dev.samy, 2)
|
||||
"""
|
||||
return scans.umv(*args, relative=True)
|
||||
|
||||
|
||||
def mv(*args) -> ScanReport:
|
||||
"""Absolute move for one or more devices.
|
||||
|
||||
Returns:
|
||||
ScanReport: Status object.
|
||||
|
||||
Examples:
|
||||
>>> mv(dev.samx, 1)
|
||||
>>> mv(dev.samx, 1, dev.samy, 2)
|
||||
"""
|
||||
return scans.mv(*args, relative=False)
|
||||
|
||||
|
||||
def mvr(*args) -> ScanReport:
|
||||
"""Relative move for one or more devices.
|
||||
|
||||
Returns:
|
||||
ScanReport: Status object.
|
||||
|
||||
Examples:
|
||||
>>> mvr(dev.samx, 1)
|
||||
>>> mvr(dev.samx, 1, dev.samy, 2)
|
||||
"""
|
||||
return scans.mv(*args, relative=True)
|
||||
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
2
bec_plugins/bec_client/plugins/LamNI/__init__.py
Normal file
2
bec_plugins/bec_client/plugins/LamNI/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from .load_additional_correction import lamni_read_additional_correction
|
||||
from .x_ray_eye_align import LamNI, XrayEyeAlign, MagLamNI, DataDrivenLamNI
|
||||
269
bec_plugins/bec_client/plugins/LamNI/bl_show_all.mac
Normal file
269
bec_plugins/bec_client/plugins/LamNI/bl_show_all.mac
Normal file
@@ -0,0 +1,269 @@
|
||||
def bl_show_all '{
|
||||
local gap
|
||||
|
||||
printf("beamline status at %s:\n",date())
|
||||
|
||||
if (!_bl_hall_temperature_ok()) {
|
||||
bl_hall_temperature
|
||||
printf("\n")
|
||||
}
|
||||
|
||||
if (_bl_sls_status_unusual()) {
|
||||
bl_sls_status
|
||||
} else {
|
||||
bl_ring_current
|
||||
}
|
||||
bl_chk_beam _show
|
||||
printf("\n")
|
||||
|
||||
printf("U19 ID gap : ",gap)
|
||||
gap = _id_get_gap_mm()
|
||||
if (gap >= 8) {
|
||||
text_bf
|
||||
}
|
||||
printf("%.3f mm\n",gap)
|
||||
text_non_bf
|
||||
|
||||
if (!_id_loss_rate_ok()) {
|
||||
id_loss_rate
|
||||
}
|
||||
|
||||
bl_shutter_status
|
||||
|
||||
if (_bl_cvd_filter_open()) {
|
||||
text_bf
|
||||
printf("CVD diamond filter : open / out\n")
|
||||
text_non_bf
|
||||
}
|
||||
|
||||
if (!_bl_xbox_valve_es1_open()) {
|
||||
bl_xbox_valve_es1 _show
|
||||
}
|
||||
|
||||
if (_bl_ln2_non_standard()) {
|
||||
text_bf
|
||||
printf("\nNon standard liquid nitrogen cooling-warning parameters occur. Please report this to your local contact.\n")
|
||||
text_non_bf
|
||||
printf("The macro bl_ln2_warn can be used to control this e-mail warning feature.\n")
|
||||
bl_ln2_warn "show"
|
||||
printf("\n")
|
||||
}
|
||||
|
||||
printf("\n")
|
||||
bl_flight_tube_pressure
|
||||
printf("\n")
|
||||
|
||||
bl_attended _show
|
||||
|
||||
_bl_check_alarm_records(1,1)
|
||||
|
||||
printf("\n")
|
||||
bl_op_msg
|
||||
}'
|
||||
|
||||
|
||||
def _bl_hall_temperature_ok() '{
|
||||
local temp_ok
|
||||
local stat
|
||||
|
||||
temp_ok = 1
|
||||
|
||||
# EH T02 average temperature
|
||||
stat = epics_get("ILUUL-02AV:TEMP")
|
||||
if ((stat < 23.0) || (stat > 26.0)) {
|
||||
temp_ok = 0
|
||||
}
|
||||
|
||||
# EH T02 temperature at T0204 axis 16
|
||||
stat = epics_get("ILUUL-0200-EB104:TEMP")
|
||||
if ((stat < 23.0) || (stat > 26.0)) {
|
||||
temp_ok = 0
|
||||
}
|
||||
|
||||
# EH T02 temperature at T0205 axis 18
|
||||
stat = epics_get("ILUUL-0200-EB105:TEMP")
|
||||
if ((stat < 23.0) || (stat > 26.0)) {
|
||||
temp_ok = 0
|
||||
}
|
||||
|
||||
return (temp_ok)
|
||||
}'
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def bl_hall_temperature '{
|
||||
local stat
|
||||
|
||||
stat = epics_get("ILUUL-02AV:TEMP")
|
||||
printf("hall T02 average temperature : ")
|
||||
if ((stat < 23.0) || (stat > 25.0)) {
|
||||
text_bf
|
||||
}
|
||||
printf("%.2f deg.C\n",stat)
|
||||
text_non_bf
|
||||
|
||||
stat = epics_get("ILUUL-0200-EB104:TEMP")
|
||||
printf("hall temperature at T0204 axis 16 : ")
|
||||
if ((stat < 23) || (stat > 25)) {
|
||||
text_bf
|
||||
}
|
||||
printf("%.2f deg.C\n",stat)
|
||||
text_non_bf
|
||||
|
||||
stat = epics_get("ILUUL-0200-EB105:TEMP")
|
||||
printf("hall temperature at T0205 axis 18 : ")
|
||||
if ((stat < 23) || (stat > 25)) {
|
||||
text_bf
|
||||
}
|
||||
printf("%.2f deg.C\n",stat)
|
||||
text_non_bf
|
||||
|
||||
# stat = epics_get("ILUUL-0300-EB102:TEMP")
|
||||
# printf("EH T03 temperature at T0302 axis 21: ")
|
||||
# if ((stat < 23) || (stat > 25)) {
|
||||
# text_bf
|
||||
# }
|
||||
# printf("%.2f deg.C\n",stat)
|
||||
# text_non_bf
|
||||
|
||||
}'
|
||||
|
||||
def _bl_sls_status_unusual() '{
|
||||
local unusual
|
||||
local stat
|
||||
|
||||
unusual = 0
|
||||
|
||||
stat = epics_get("X12SA-SR-VAC:SETPOINT")
|
||||
if (stat != "OK") {
|
||||
unusual = 1
|
||||
}
|
||||
|
||||
stat = epics_get("ACOAU-ACCU:OP-MODE.VAL")
|
||||
if ((stat != "Light Available") && (stat != "Light-Available")) {
|
||||
unusual = 1
|
||||
}
|
||||
|
||||
stat = epics_get("ALIRF-GUN:INJ-MODE")
|
||||
if (stat != "TOP-UP") {
|
||||
unusual = 1
|
||||
}
|
||||
|
||||
# current threshold
|
||||
stat = epics_get("ALIRF-GUN:CUR-LOWLIM")
|
||||
if (stat < 350) {
|
||||
unusual = 1
|
||||
}
|
||||
|
||||
# current deadband
|
||||
stat = epics_get("ALIRF-GUN:CUR-DBAND")
|
||||
if (stat > 2) {
|
||||
unusual = 1
|
||||
}
|
||||
|
||||
# orbit feedback mode
|
||||
stat = epics_get("ARIDI-BPM:OFB-MODE")
|
||||
if (stat != "fast") {
|
||||
unusual = 1
|
||||
}
|
||||
|
||||
# fast orbit feedback
|
||||
stat = epics_get("ARIDI-BPM:FOFBSTATUS-G")
|
||||
if (stat != "running") {
|
||||
unusual = 1
|
||||
}
|
||||
|
||||
return(unusual)
|
||||
}'
|
||||
|
||||
def bl_sls_status '{
|
||||
local stat
|
||||
|
||||
stat = epics_get("ACOAU-ACCU:OP-MODE.VAL")
|
||||
printf("SLS status : ")
|
||||
if ((stat != "Light Available") && (stat != "Light-Available")) {
|
||||
text_bf
|
||||
}
|
||||
printf("%s\n",stat)
|
||||
text_non_bf
|
||||
|
||||
stat = epics_get("ALIRF-GUN:INJ-MODE")
|
||||
printf("SLS injection mode : ")
|
||||
if (stat != "TOP-UP") {
|
||||
text_bf
|
||||
}
|
||||
printf("%s\n",stat)
|
||||
text_non_bf
|
||||
|
||||
stat = epics_get("ALIRF-GUN:CUR-LOWLIM")
|
||||
printf("SLS current threshold : ")
|
||||
if (stat < 350) {
|
||||
text_bf
|
||||
}
|
||||
printf("%7.3f\n",stat)
|
||||
text_non_bf
|
||||
|
||||
stat = epics_get("ALIRF-GUN:CUR-DBAND")
|
||||
printf("SLS current deadband : ")
|
||||
if (stat > 2) {
|
||||
text_bf
|
||||
}
|
||||
printf("%7.3f\n",stat)
|
||||
text_non_bf
|
||||
|
||||
stat = epics_get("ACORF-FILL:PAT-SELECT")
|
||||
printf("SLS filling pattern : ")
|
||||
printf("%s\n",stat)
|
||||
|
||||
bl_ring_current
|
||||
|
||||
stat = epics_get("ARIDI-PCT:TAU-HOUR")
|
||||
printf("SLS filling life time : ")
|
||||
printf("%.2f h\n",stat)
|
||||
|
||||
stat = epics_get("ARIDI-BPM:OFB-MODE")
|
||||
printf("orbit feedback mode : ")
|
||||
if (stat != "fast") {
|
||||
text_bf
|
||||
}
|
||||
printf("%s\n",stat)
|
||||
text_non_bf
|
||||
|
||||
stat = epics_get("ARIDI-BPM:FOFBSTATUS-G")
|
||||
printf("fast orbit feedback : ")
|
||||
if (stat != "running") {
|
||||
text_bf
|
||||
}
|
||||
printf("%s\n",stat)
|
||||
text_non_bf
|
||||
|
||||
}'
|
||||
|
||||
def _bl_get_ring_current() '{
|
||||
return epics_get("ARIDI-PCT:CURRENT")
|
||||
}'
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def _bl_no_ring_current() '{
|
||||
# set an arbitrary current limit of 100mA as no-beam limit
|
||||
if (_bl_get_ring_current() < 100) {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}'
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def bl_ring_current '{
|
||||
local curr
|
||||
|
||||
curr = _bl_get_ring_current()
|
||||
|
||||
if (curr < 300) {
|
||||
text_bf
|
||||
}
|
||||
printf("SLS ring current : %.3f mA\n",curr)
|
||||
text_non_bf
|
||||
}'
|
||||
161
bec_plugins/bec_client/plugins/LamNI/lamni_optics_mixin.py
Normal file
161
bec_plugins/bec_client/plugins/LamNI/lamni_optics_mixin.py
Normal file
@@ -0,0 +1,161 @@
|
||||
import builtins
|
||||
import time
|
||||
|
||||
from rich import box
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
|
||||
from bec_client.plugins.cSAXS import epics_get, epics_put, fshclose
|
||||
|
||||
# import builtins to avoid linter errors
|
||||
dev = builtins.__dict__.get("dev")
|
||||
umv = builtins.__dict__.get("umv")
|
||||
bec = builtins.__dict__.get("bec")
|
||||
|
||||
|
||||
class LamNIOpticsMixin:
|
||||
@staticmethod
|
||||
def _get_user_param_safe(device, var):
|
||||
param = dev[device].user_parameter
|
||||
if not param or param.get(var) is None:
|
||||
raise ValueError(f"Device {device} has no user parameter definition for {var}.")
|
||||
return param.get(var)
|
||||
|
||||
def leye_out(self):
|
||||
self.loptics_in()
|
||||
fshclose()
|
||||
leyey_out = self._get_user_param_safe("leyey", "out")
|
||||
umv(dev.leyey, leyey_out)
|
||||
|
||||
epics_put("XOMNYI-XEYE-ACQ:0", 2)
|
||||
# move rotation stage to zero to avoid problems with wires
|
||||
umv(dev.lsamrot, 0)
|
||||
umv(dev.dttrz, 5854, dev.fttrz, 2395)
|
||||
|
||||
def leye_in(self):
|
||||
bec.queue.next_dataset_number += 1
|
||||
# move rotation stage to zero to avoid problems with wires
|
||||
umv(dev.lsamrot, 0)
|
||||
umv(dev.dttrz, 6419.677, dev.fttrz, 2959.979)
|
||||
while True:
|
||||
moved_out = (input("Did the flight tube move out? (Y/n)") or "y").lower()
|
||||
if moved_out == "y":
|
||||
break
|
||||
if moved_out == "n":
|
||||
return
|
||||
leyex_in = self._get_user_param_safe("leyex", "in")
|
||||
leyey_in = self._get_user_param_safe("leyey", "in")
|
||||
umv(dev.leyex, leyex_in, dev.leyey, leyey_in)
|
||||
self.align.update_frame()
|
||||
|
||||
def _lfzp_in(self):
|
||||
loptx_in = self._get_user_param_safe("loptx", "in")
|
||||
lopty_in = self._get_user_param_safe("lopty", "in")
|
||||
umv(
|
||||
dev.loptx, loptx_in, dev.lopty, lopty_in
|
||||
) # for 7.2567 keV and 150 mu, 60 nm fzp, loptz 83.6000 for propagation 1.4 mm
|
||||
|
||||
def lfzp_in(self):
|
||||
"""
|
||||
move in the lamni zone plate.
|
||||
This will disable rt feedback, move the FZP and re-enabled the feedback.
|
||||
"""
|
||||
if "rtx" in dev and dev.rtx.enabled:
|
||||
dev.rtx.controller.feedback_disable()
|
||||
|
||||
self._lfzp_in()
|
||||
|
||||
if "rtx" in dev and dev.rtx.enabled:
|
||||
dev.rtx.controller.feedback_enable_with_reset()
|
||||
|
||||
def loptics_in(self):
|
||||
"""
|
||||
Move in the lamni optics, including the FZP and the OSA.
|
||||
"""
|
||||
self.lfzp_in()
|
||||
self.losa_in()
|
||||
|
||||
def loptics_out(self):
|
||||
"""Move out the lamni optics"""
|
||||
if "rtx" in dev and dev.rtx.enabled:
|
||||
dev.rtx.controller.feedback_disable()
|
||||
|
||||
# self.lcs_out()
|
||||
self.losa_out()
|
||||
loptx_out = self._get_user_param_safe("loptx", "out")
|
||||
lopty_out = self._get_user_param_safe("lopty", "out")
|
||||
umv(dev.loptx, loptx_out, dev.lopty, lopty_out)
|
||||
|
||||
if "rtx" in dev and dev.rtx.enabled:
|
||||
time.sleep(1)
|
||||
dev.rtx.controller.feedback_enable_with_reset()
|
||||
|
||||
def lcs_in(self):
|
||||
# umv lcsx -1.852 lcsy -0.095
|
||||
pass
|
||||
|
||||
def lcs_out(self):
|
||||
umv(dev.lcsy, 3)
|
||||
|
||||
def losa_in(self):
|
||||
# 6.2 keV, 170 um FZP
|
||||
# umv(dev.losax, -1.4450000, dev.losay, -0.1800)
|
||||
# umv(dev.losaz, -1)
|
||||
# 6.7, 170
|
||||
# umv(dev.losax, -1.4850, dev.losay, -0.1930)
|
||||
# umv(dev.losaz, 1.0000)
|
||||
# 7.2, 150
|
||||
losax_in = self._get_user_param_safe("losax", "in")
|
||||
losay_in = self._get_user_param_safe("losay", "in")
|
||||
losaz_in = self._get_user_param_safe("losaz", "in")
|
||||
umv(dev.losax, losax_in, dev.losay, losay_in)
|
||||
umv(dev.losaz, losaz_in)
|
||||
# 11 kev
|
||||
# umv(dev.losax, -1.161000, dev.losay, -0.196)
|
||||
# umv(dev.losaz, 1.0000)
|
||||
|
||||
def losa_out(self):
|
||||
losay_out = self._get_user_param_safe("losay", "out")
|
||||
losaz_out = self._get_user_param_safe("losaz", "out")
|
||||
umv(dev.losaz, losaz_out)
|
||||
umv(dev.losay, losay_out)
|
||||
|
||||
def lfzp_info(self):
|
||||
loptz_val = dev.loptz.read()["loptz"]["value"]
|
||||
distance = -loptz_val + 85.6 + 52
|
||||
print(f"The sample is in a distance of {distance:.1f} mm from the FZP.")
|
||||
|
||||
diameters = [80e-6, 100e-6, 120e-6, 150e-6, 170e-6, 200e-6, 220e-6, 250e-6]
|
||||
|
||||
mokev_val = dev.mokev.read()["mokev"]["value"]
|
||||
console = Console()
|
||||
table = Table(
|
||||
title=f"At the current energy of {mokev_val:.4f} keV we have following options:",
|
||||
box=box.SQUARE,
|
||||
)
|
||||
table.add_column("Diameter", justify="center")
|
||||
table.add_column("Focal distance", justify="center")
|
||||
table.add_column("Current beam size", justify="center")
|
||||
|
||||
wavelength = 1.2398e-9 / mokev_val
|
||||
|
||||
for diameter in diameters:
|
||||
outermost_zonewidth = 60e-9
|
||||
focal_distance = diameter * outermost_zonewidth / wavelength
|
||||
beam_size = (
|
||||
-diameter / (focal_distance * 1000) * (focal_distance * 1000 - distance) * 1e6
|
||||
)
|
||||
table.add_row(
|
||||
f"{diameter*1e6:.2f} microns",
|
||||
f"{focal_distance:.2f} mm",
|
||||
f"{beam_size:.2f} microns",
|
||||
)
|
||||
|
||||
console.print(table)
|
||||
|
||||
print("OSA Information:")
|
||||
# print(f"Current losaz %.1f\n", A[losaz])
|
||||
# print("The OSA will collide with the sample plane at %.1f\n\n", 89.3-A[loptz])
|
||||
print(
|
||||
"The numbers presented here are for a sample in the plane of the lamni sample holder.\n"
|
||||
)
|
||||
@@ -1,6 +1,7 @@
|
||||
def lamni_read_additional_correction():
|
||||
# "additional_correction_shift"
|
||||
# [0][] x , [1][] y, [2][] angle, [3][0] number of elements
|
||||
import numpy as np
|
||||
|
||||
with open("correction_lamni_um_S01405_.txt", "r") as f:
|
||||
num_elements = f.readline()
|
||||
@@ -9,14 +9,13 @@ from pathlib import Path
|
||||
|
||||
import h5py
|
||||
import numpy as np
|
||||
from bec_client.plugins.cSAXS import epics_get, epics_put, fshclose, fshopen
|
||||
from bec_lib import bec_logger
|
||||
from bec_lib.alarm_handler import AlarmBase
|
||||
from bec_lib.pdf_writer import PDFWriter
|
||||
from typeguard import typechecked
|
||||
|
||||
from csaxs_bec.bec_ipython_client.plugins.cSAXS import epics_get, epics_put, fshopen
|
||||
|
||||
from .lamni_optics_mixin import LaMNIInitStagesMixin, LamNIOpticsMixin
|
||||
from .lamni_optics_mixin import LamNIOpticsMixin
|
||||
|
||||
logger = bec_logger.logger
|
||||
bec = builtins.__dict__.get("bec")
|
||||
@@ -32,7 +31,7 @@ class XrayEyeAlign:
|
||||
self.lamni = lamni
|
||||
self.device_manager = client.device_manager
|
||||
self.scans = client.scans
|
||||
# self.xeye = self.device_manager.devices.xeye
|
||||
self.xeye = self.device_manager.devices.xeye
|
||||
self.alignment_values = defaultdict(list)
|
||||
self._reset_init_values()
|
||||
self.corr_pos_x = []
|
||||
@@ -189,8 +188,7 @@ class XrayEyeAlign:
|
||||
val_y = epics_get(f"XOMNYI-XEYE-YVAL_Y:{k}") * self.PIXEL_CALIBRATION # in mm
|
||||
self.alignment_values[k] = [val_x, val_y]
|
||||
print(
|
||||
f"Clicked position {k}: x {self.alignment_values[k][0]}, y"
|
||||
f" {self.alignment_values[k][1]}"
|
||||
f"Clicked position {k}: x {self.alignment_values[k][0]}, y {self.alignment_values[k][1]}"
|
||||
)
|
||||
|
||||
if k == 0: # received center value of FZP
|
||||
@@ -215,10 +213,7 @@ class XrayEyeAlign:
|
||||
elif (
|
||||
k == 1
|
||||
): # received sample center value at samroy 0 ie the final base shift values
|
||||
msg = (
|
||||
f"Base shift values from movement are x {self.shift_xy[0]}, y"
|
||||
f" {self.shift_xy[1]}"
|
||||
)
|
||||
msg = f"Base shift values from movement are x {self.shift_xy[0]}, y {self.shift_xy[1]}"
|
||||
print(msg)
|
||||
logger.info(msg)
|
||||
self.shift_xy[0] += (
|
||||
@@ -228,12 +223,13 @@ class XrayEyeAlign:
|
||||
self.alignment_values[1][1] - self.alignment_values[0][1]
|
||||
) * 1000
|
||||
print(
|
||||
"Base shift values from movement and clicked position are x"
|
||||
f" {self.shift_xy[0]}, y {self.shift_xy[1]}"
|
||||
f"Base shift values from movement and clicked position are x {self.shift_xy[0]}, y {self.shift_xy[1]}"
|
||||
)
|
||||
|
||||
self.scans.lamni_move_to_scan_center(
|
||||
self.shift_xy[0] / 1000, self.shift_xy[1] / 1000, self.get_tomo_angle()
|
||||
self.shift_xy[0] / 1000,
|
||||
self.shift_xy[1] / 1000,
|
||||
self.get_tomo_angle(),
|
||||
).wait()
|
||||
|
||||
self.send_message("please wait ...")
|
||||
@@ -242,7 +238,9 @@ class XrayEyeAlign:
|
||||
time.sleep(1)
|
||||
|
||||
self.scans.lamni_move_to_scan_center(
|
||||
self.shift_xy[0] / 1000, self.shift_xy[1] / 1000, self.get_tomo_angle()
|
||||
self.shift_xy[0] / 1000,
|
||||
self.shift_xy[1] / 1000,
|
||||
self.get_tomo_angle(),
|
||||
).wait()
|
||||
|
||||
epics_put("XOMNYI-XEYE-ANGLE:0", self.get_tomo_angle())
|
||||
@@ -259,12 +257,16 @@ class XrayEyeAlign:
|
||||
self._disable_rt_feedback()
|
||||
self.tomo_rotate((k - 1) * 45 - 45 / 2)
|
||||
self.scans.lamni_move_to_scan_center(
|
||||
self.shift_xy[0] / 1000, self.shift_xy[1] / 1000, self.get_tomo_angle()
|
||||
self.shift_xy[0] / 1000,
|
||||
self.shift_xy[1] / 1000,
|
||||
self.get_tomo_angle(),
|
||||
).wait()
|
||||
self._disable_rt_feedback()
|
||||
self.tomo_rotate((k - 1) * 45)
|
||||
self.scans.lamni_move_to_scan_center(
|
||||
self.shift_xy[0] / 1000, self.shift_xy[1] / 1000, self.get_tomo_angle()
|
||||
self.shift_xy[0] / 1000,
|
||||
self.shift_xy[1] / 1000,
|
||||
self.get_tomo_angle(),
|
||||
).wait()
|
||||
|
||||
epics_put("XOMNYI-XEYE-ANGLE:0", self.get_tomo_angle())
|
||||
@@ -291,7 +293,9 @@ class XrayEyeAlign:
|
||||
self.shift_xy[0] = self.shift_xy[0] + _xrayeyalignmvx
|
||||
self.shift_xy[1] = self.shift_xy[1] + _xrayeyalignmvy
|
||||
self.scans.lamni_move_to_scan_center(
|
||||
self.shift_xy[0] / 1000, self.shift_xy[1] / 1000, self.get_tomo_angle()
|
||||
self.shift_xy[0] / 1000,
|
||||
self.shift_xy[1] / 1000,
|
||||
self.get_tomo_angle(),
|
||||
).wait()
|
||||
print(
|
||||
f"Current center horizontal {self.shift_xy[0]} vertical {self.shift_xy[1]}"
|
||||
@@ -306,14 +310,12 @@ class XrayEyeAlign:
|
||||
fovx = self._xray_fov_xy[0] * self.PIXEL_CALIBRATION * 1000 / 2
|
||||
fovy = self._xray_fov_xy[1] * self.PIXEL_CALIBRATION * 1000 / 2
|
||||
print(
|
||||
f"The largest field of view from the xrayeyealign was \nfovx = {fovx:.0f} microns, fovy"
|
||||
f" = {fovy:.0f} microns"
|
||||
f"The largest field of view from the xrayeyealign was \nfovx = {fovx:.0f} microns, fovy = {fovy:.0f} microns"
|
||||
)
|
||||
print("Use matlab routine to fit the current alignment...")
|
||||
|
||||
print(
|
||||
"This additional shift is applied to the base shift values\n which are x"
|
||||
f" {self.shift_xy[0]}, y {self.shift_xy[1]}"
|
||||
f"This additional shift is applied to the base shift values\n which are x {self.shift_xy[0]}, y {self.shift_xy[1]}"
|
||||
)
|
||||
|
||||
self._disable_rt_feedback()
|
||||
@@ -321,8 +323,7 @@ class XrayEyeAlign:
|
||||
self.tomo_rotate(0)
|
||||
|
||||
print(
|
||||
"\n\nNEXT LOAD ALIGNMENT PARAMETERS\nby running"
|
||||
" lamni.align.read_xray_eye_correction()\n"
|
||||
"\n\nNEXT LOAD ALIGNMENT PARAMETERS\nby running lamni.align.read_xray_eye_correction()\n"
|
||||
)
|
||||
|
||||
self.client.set_global_var("tomo_fov_offset", self.shift_xy)
|
||||
@@ -331,13 +332,12 @@ class XrayEyeAlign:
|
||||
with open(
|
||||
os.path.expanduser("~/Data10/specES1/internal/xrayeye_alignmentvalues"), "w"
|
||||
) as alignment_values_file:
|
||||
alignment_values_file.write("angle\thorizontal\tvertical\n")
|
||||
alignment_values_file.write(f"angle\thorizontal\tvertical\n")
|
||||
for k in range(2, 11):
|
||||
fovx_offset = (self.alignment_values[0][0] - self.alignment_values[k][0]) * 1000
|
||||
fovy_offset = (self.alignment_values[k][1] - self.alignment_values[0][1]) * 1000
|
||||
print(
|
||||
f"Writing to file new alignment: number {k}, value x {fovx_offset}, y"
|
||||
f" {fovy_offset}"
|
||||
f"Writing to file new alignment: number {k}, value x {fovx_offset}, y {fovy_offset}"
|
||||
)
|
||||
alignment_values_file.write(f"{(k-2)*45}\t{fovx_offset}\t{fovy_offset}\n")
|
||||
|
||||
@@ -422,8 +422,7 @@ class XrayEyeAlign:
|
||||
additional_correction_shift_x = self.corr_pos_x[-1]
|
||||
additional_correction_shift_y = self.corr_pos_y[-1]
|
||||
print(
|
||||
"Additional correction shifts:"
|
||||
f" {additional_correction_shift_x} {additional_correction_shift_y}"
|
||||
f"Additional correction shifts: {additional_correction_shift_x} {additional_correction_shift_y}"
|
||||
)
|
||||
return (additional_correction_shift_x, additional_correction_shift_y)
|
||||
|
||||
@@ -477,8 +476,7 @@ class XrayEyeAlign:
|
||||
additional_correction_shift_x = self.corr_pos_x_2[-1]
|
||||
additional_correction_shift_y = self.corr_pos_y_2[-1]
|
||||
print(
|
||||
"Additional correction shifts 2:"
|
||||
f" {additional_correction_shift_x} {additional_correction_shift_y}"
|
||||
f"Additional correction shifts 2: {additional_correction_shift_x} {additional_correction_shift_y}"
|
||||
)
|
||||
return (additional_correction_shift_x, additional_correction_shift_y)
|
||||
|
||||
@@ -511,7 +509,7 @@ class LamNI(LamNIOpticsMixin):
|
||||
super().__init__()
|
||||
self.client = client
|
||||
self.align = XrayEyeAlign(client, self)
|
||||
self.init = LaMNIInitStagesMixin()
|
||||
|
||||
self.check_shutter = True
|
||||
self.check_light_available = True
|
||||
self.check_fofb = True
|
||||
@@ -527,8 +525,7 @@ class LamNI(LamNIOpticsMixin):
|
||||
|
||||
def get_beamline_checks_enabled(self):
|
||||
print(
|
||||
f"Shutter: {self.check_shutter}\nFOFB: {self.check_fofb}\nLight available:"
|
||||
f" {self.check_light_available}"
|
||||
f"Shutter: {self.check_shutter}\nFOFB: {self.check_fofb}\nLight available: {self.check_light_available}"
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -586,27 +583,6 @@ class LamNI(LamNIOpticsMixin):
|
||||
def tomo_circfov(self, val: float):
|
||||
self.client.set_global_var("tomo_circfov", val)
|
||||
|
||||
@property
|
||||
def tomo_type(self):
|
||||
val = self.client.get_global_var("tomo_type")
|
||||
if val is None:
|
||||
return 1
|
||||
return val
|
||||
|
||||
@tomo_type.setter
|
||||
def tomo_type(self, val: float):
|
||||
if val == 1:
|
||||
# equally spaced tomography with 8 sub tomograms
|
||||
self.client.set_global_var("tomo_type", val)
|
||||
# elif val == 2:
|
||||
# # golden ratio tomography (sorted bunches)
|
||||
# self.client.set_global_var("tomo_type", val)
|
||||
# elif val == 3:
|
||||
# # equally spaced tomography with starting angles shifted by golden ratio
|
||||
# self.client.set_global_var("tomo_type", val)
|
||||
else:
|
||||
raise ValueError("Unknown tomo_type.")
|
||||
|
||||
@property
|
||||
def tomo_countingtime(self):
|
||||
val = self.client.get_global_var("tomo_countingtime")
|
||||
@@ -790,18 +766,13 @@ class LamNI(LamNIOpticsMixin):
|
||||
# pylint: disable=undefined-variable
|
||||
self._current_scan_list.append(bec.queue.next_scan_number)
|
||||
logger.info(
|
||||
f"scans.lamni_fermat_scan(fov_size=[{self.lamni_piezo_range_x},{self.lamni_piezo_range_y}],"
|
||||
f" step={self.tomo_shellstep}, stitch_x={0}, stitch_y={0},"
|
||||
f" stitch_overlap={1},center_x={self.align.tomo_fovx_offset},"
|
||||
f" center_y={self.align.tomo_fovy_offset},"
|
||||
f" shift_x={self.manual_shift_x+correction_xeye_mu[0]-additional_correction[0]-additional_correction_2[0]},"
|
||||
f" shift_y={self.manual_shift_y+correction_xeye_mu[1]-additional_correction[1]-additional_correction_2[1]},"
|
||||
f" fov_circular={self.tomo_circfov}, angle={angle}, scan_type='fly')"
|
||||
)
|
||||
log_message = (
|
||||
f"{str(datetime.datetime.now())}: LamNI scan projection at angle {angle}, scan"
|
||||
f" number {bec.queue.next_scan_number}.\n"
|
||||
f"scans.lamni_fermat_scan(fov_size=[{self.lamni_piezo_range_x},{self.lamni_piezo_range_y}], step={self.tomo_shellstep}, stitch_x={0}, stitch_y={0}, stitch_overlap={1},"
|
||||
f"center_x={self.align.tomo_fovx_offset}, center_y={self.align.tomo_fovy_offset}, "
|
||||
f"shift_x={self.manual_shift_x+correction_xeye_mu[0]-additional_correction[0]-additional_correction_2[0]}, "
|
||||
f"shift_y={self.manual_shift_y+correction_xeye_mu[1]-additional_correction[1]-additional_correction_2[1]}, "
|
||||
f"fov_circular={self.tomo_circfov}, angle={angle}, scan_type='fly')"
|
||||
)
|
||||
log_message = f"{str(datetime.datetime.now())}: LamNI scan projection at angle {angle}, scan number {bec.queue.next_scan_number}.\n"
|
||||
self.write_to_spec_log(log_message)
|
||||
# self.write_to_scilog(log_message, ["BEC_scans", self.sample_name])
|
||||
corridor_size = self.corridor_size if self.corridor_size > 0 else None
|
||||
@@ -843,7 +814,10 @@ class LamNI(LamNIOpticsMixin):
|
||||
msgs.append("Check beam failed: Shutter is closed.")
|
||||
if self.check_light_available:
|
||||
machine_status = dev.sls_machine_status.read(cached=True)
|
||||
if machine_status["value"] not in ["Light Available", "Light-Available"]:
|
||||
if machine_status["value"] not in [
|
||||
"Light Available",
|
||||
"Light-Available",
|
||||
]:
|
||||
self._beam_is_okay = False
|
||||
msgs.append("Check beam failed: Light not available.")
|
||||
if self.check_fofb:
|
||||
@@ -884,8 +858,7 @@ class LamNI(LamNIOpticsMixin):
|
||||
try:
|
||||
msg = bec.logbook.LogbookMessage()
|
||||
msg.add_text(
|
||||
"<p><mark class='pen-red'><strong>Beamline checks failed at"
|
||||
f" {str(datetime.datetime.now())}: {''.join(self._check_msgs)}</strong></mark></p>"
|
||||
f"<p><mark class='pen-red'><strong>Beamline checks failed at {str(datetime.datetime.now())}: {''.join(self._check_msgs)}</strong></mark></p>"
|
||||
).add_tag(["BEC", "beam_check"])
|
||||
self.client.logbook.send_logbook_message(msg)
|
||||
except Exception:
|
||||
@@ -902,20 +875,25 @@ class LamNI(LamNIOpticsMixin):
|
||||
try:
|
||||
msg = bec.logbook.LogbookMessage()
|
||||
msg.add_text(
|
||||
"<p><mark class='pen-red'><strong>Operation resumed at"
|
||||
f" {str(datetime.datetime.now())}.</strong></mark></p>"
|
||||
f"<p><mark class='pen-red'><strong>Operation resumed at {str(datetime.datetime.now())}.</strong></mark></p>"
|
||||
).add_tag(["BEC", "beam_check"])
|
||||
self.client.logbook.send_logbook_message(msg)
|
||||
except Exception:
|
||||
logger.warning("Failed to send update to SciLog.")
|
||||
|
||||
def add_sample_database(
|
||||
self, samplename, date, eaccount, scan_number, setup, sample_additional_info, user
|
||||
self,
|
||||
samplename,
|
||||
date,
|
||||
eaccount,
|
||||
scan_number,
|
||||
setup,
|
||||
sample_additional_info,
|
||||
user,
|
||||
):
|
||||
"""Add a sample to the omny sample database. This also retrieves the tomo id."""
|
||||
subprocess.run(
|
||||
"wget --user=omny --password=samples -q -O /tmp/currsamplesnr.txt"
|
||||
f" 'https://omny.web.psi.ch/samples/newmeasurement.php?sample={samplename}&date={date}&eaccount={eaccount}&scannr={scan_number}&setup={setup}&additional={sample_additional_info}&user={user}'",
|
||||
f"wget --user=omny --password=samples -q -O /tmp/currsamplesnr.txt 'https://omny.web.psi.ch/samples/newmeasurement.php?sample={samplename}&date={date}&eaccount={eaccount}&scannr={scan_number}&setup={setup}&additional={sample_additional_info}&user={user}'",
|
||||
shell=True,
|
||||
)
|
||||
with open("/tmp/currsamplesnr.txt") as tomo_number_file:
|
||||
@@ -969,63 +947,25 @@ class LamNI(LamNIOpticsMixin):
|
||||
# _tomo_shift_angles (potential global variable)
|
||||
_tomo_shift_angles = 0
|
||||
angle_end = start_angle + 360
|
||||
angles = np.linspace(
|
||||
for angle in np.linspace(
|
||||
start_angle + _tomo_shift_angles,
|
||||
angle_end,
|
||||
num=int(360 / self.tomo_angle_stepsize) + 1,
|
||||
endpoint=True,
|
||||
)
|
||||
|
||||
# reverse even sub-tomograms
|
||||
if not (subtomo_number % 2):
|
||||
angles = np.flip(angles)
|
||||
for angle in angles:
|
||||
self.progress["subtomo"] = subtomo_number
|
||||
self.progress["subtomo_projection"] = angles.index(angle)
|
||||
self.progress["subtomo_total_projections"] = 180 / self.tomo_angle_stepsize
|
||||
self.progress["projection"] = (subtomo_number - 1) * self.progress[
|
||||
"subtomo_total_projections"
|
||||
] + self.progress["subtomo_projection"]
|
||||
self.progress["total_projections"] = 180 / self.tomo_angle_stepsize * 8
|
||||
self.progress["angle"] = angle
|
||||
self._tomo_scan_at_angle(angle, subtomo_number)
|
||||
|
||||
def _print_progress(self):
|
||||
print("\x1b[95mProgress report:")
|
||||
print(f"Tomo type: ....................... {self.progress['tomo_type']}")
|
||||
print(f"Projection: ...................... {self.progress['projection']}")
|
||||
print(f"Total projections expected ....... {self.progress['total_projections']}")
|
||||
print(f"Angle: ........................... {self.progress['angle']}")
|
||||
print(f"Current subtomo: ................. {self.progress['subtomo']}")
|
||||
print(f"Current projection within subtomo: {self.progress['subtomo_projection']}\x1b[0m")
|
||||
|
||||
def _tomo_scan_at_angle(self, angle, subtomo_number):
|
||||
successful = False
|
||||
error_caught = False
|
||||
if 0 <= angle < 360.05:
|
||||
print(f"Starting LamNI scan for angle {angle} in subtomo {subtomo_number}")
|
||||
self._print_progress()
|
||||
while not successful:
|
||||
self._start_beam_check()
|
||||
if not self.special_angles:
|
||||
self._current_special_angles = []
|
||||
if self._current_special_angles:
|
||||
next_special_angle = self._current_special_angles[0]
|
||||
if np.isclose(angle, next_special_angle, atol=0.5):
|
||||
self._current_special_angles.pop(0)
|
||||
num_repeats = self.special_angle_repeats
|
||||
else:
|
||||
num_repeats = 1
|
||||
try:
|
||||
start_scan_number = bec.queue.next_scan_number
|
||||
for i in range(num_repeats):
|
||||
self._at_each_angle(angle)
|
||||
error_caught = False
|
||||
except AlarmBase as exc:
|
||||
if exc.alarm_type == "TimeoutError":
|
||||
bec.queue.request_queue_reset()
|
||||
time.sleep(2)
|
||||
error_caught = True
|
||||
):
|
||||
successful = False
|
||||
error_caught = False
|
||||
if 0 <= angle < 360.05:
|
||||
print(f"Starting LamNI scan for angle {angle}")
|
||||
while not successful:
|
||||
self._start_beam_check()
|
||||
if not self.special_angles:
|
||||
self._current_special_angles = []
|
||||
if self._current_special_angles:
|
||||
next_special_angle = self._current_special_angles[0]
|
||||
if np.isclose(angle, next_special_angle, atol=0.5):
|
||||
self._current_special_angles.pop(0)
|
||||
num_repeats = self.special_angle_repeats
|
||||
else:
|
||||
num_repeats = 1
|
||||
try:
|
||||
@@ -1065,7 +1005,7 @@ class LamNI(LamNIOpticsMixin):
|
||||
scans = builtins.__dict__.get("scans")
|
||||
self._current_special_angles = self.special_angles.copy()
|
||||
|
||||
if self.tomo_type == 1 and subtomo_start == 1 and start_angle is None:
|
||||
if subtomo_start == 1 and start_angle is None:
|
||||
# pylint: disable=undefined-variable
|
||||
self.tomo_id = self.add_sample_database(
|
||||
self.sample_name,
|
||||
@@ -1088,16 +1028,14 @@ class LamNI(LamNIOpticsMixin):
|
||||
print(f"Counting time <ctime> = {self.tomo_countingtime} s")
|
||||
print(f"Stepsize microns <step> = {self.tomo_shellstep}")
|
||||
print(
|
||||
f"Piezo range (max 80) <microns> = {self.lamni_piezo_range_x},"
|
||||
f" {self.lamni_piezo_range_y}"
|
||||
f"Piezo range (max 80) <microns> = {self.lamni_piezo_range_x}, {self.lamni_piezo_range_y}"
|
||||
)
|
||||
print(f"Stitching number x,y = {self.lamni_stitch_x}, {self.lamni_stitch_y}")
|
||||
print(f"Stitching overlap = {self.tomo_stitch_overlap}")
|
||||
print(f"Circuilar FOV diam <microns> = {self.tomo_circfov}")
|
||||
print(f"Reconstruction queue name = {self.ptycho_reconstruct_foldername}")
|
||||
print(
|
||||
"For information, fov offset is rotating and finding the ROI, manual shift moves"
|
||||
" rotation center"
|
||||
"For information, fov offset is rotating and finding the ROI, manual shift moves rotation center"
|
||||
)
|
||||
print(f" _tomo_fovx_offset <mm> = {self.align.tomo_fovx_offset}")
|
||||
print(f" _tomo_fovy_offset <mm> = {self.align.tomo_fovy_offset}")
|
||||
@@ -1153,7 +1091,7 @@ class LamNI(LamNIOpticsMixin):
|
||||
with open(ptycho_queue_file, "w") as queue_file:
|
||||
scans = " ".join([str(scan) for scan in self._current_scan_list])
|
||||
queue_file.write(f"p.scan_number {scans}\n")
|
||||
queue_file.write("p.check_nextscan_started 1\n")
|
||||
queue_file.write(f"p.check_nextscan_started 1\n")
|
||||
|
||||
def write_pdf_report(self):
|
||||
"""create and write the pdf report with the current LamNI settings"""
|
||||
@@ -1178,25 +1116,17 @@ class LamNI(LamNIOpticsMixin):
|
||||
f"{'Dataset ID:':<{padding}}{dataset_id:>{padding}}\n",
|
||||
f"{'Sample Info:':<{padding}}{'Sample Info':>{padding}}\n",
|
||||
f"{'e-account:':<{padding}}{str(self.client.username):>{padding}}\n",
|
||||
(
|
||||
f"{'Number of projections:':<{padding}}{int(360 / self.tomo_angle_stepsize * 8):>{padding}}\n"
|
||||
),
|
||||
f"{'Number of projections:':<{padding}}{int(360 / self.tomo_angle_stepsize * 8):>{padding}}\n",
|
||||
f"{'First scan number:':<{padding}}{self.client.queue.next_scan_number:>{padding}}\n",
|
||||
(
|
||||
f"{'Last scan number approx.:':<{padding}}{self.client.queue.next_scan_number + int(360 / self.tomo_angle_stepsize * 8) + 10:>{padding}}\n"
|
||||
),
|
||||
(
|
||||
f"{'Current photon energy:':<{padding}}{dev.mokev.read(cached=True)['value']:>{padding}.4f}\n"
|
||||
),
|
||||
f"{'Last scan number approx.:':<{padding}}{self.client.queue.next_scan_number + int(360 / self.tomo_angle_stepsize * 8) + 10:>{padding}}\n",
|
||||
f"{'Current photon energy:':<{padding}}{dev.mokev.read(cached=True)['value']:>{padding}.4f}\n",
|
||||
f"{'Exposure time:':<{padding}}{self.tomo_countingtime:>{padding}.2f}\n",
|
||||
f"{'Fermat spiral step size:':<{padding}}{self.tomo_shellstep:>{padding}.2f}\n",
|
||||
f"{'Piezo range (FOV sample plane):':<{padding}}{piezo_range:>{padding}}\n",
|
||||
f"{'Restriction to circular FOV:':<{padding}}{self.tomo_circfov:>{padding}.2f}\n",
|
||||
f"{'Stitching:':<{padding}}{stitching:>{padding}}\n",
|
||||
f"{'Number of individual sub-tomograms:':<{padding}}{8:>{padding}}\n",
|
||||
(
|
||||
f"{'Angular step within sub-tomogram:':<{padding}}{self.tomo_angle_stepsize:>{padding}.2f}\n"
|
||||
),
|
||||
f"{'Angular step within sub-tomogram:':<{padding}}{self.tomo_angle_stepsize:>{padding}.2f}\n",
|
||||
]
|
||||
content = "".join(content)
|
||||
user_target = os.path.expanduser(f"~/Data10/documentation/tomo_scan_ID_{self.tomo_id}.pdf")
|
||||
@@ -1204,13 +1134,20 @@ class LamNI(LamNIOpticsMixin):
|
||||
file.write(header)
|
||||
file.write(content)
|
||||
subprocess.run(
|
||||
"xterm /work/sls/spec/local/XOMNY/bin/upload/upload_last_pon.sh &", shell=True
|
||||
"xterm /work/sls/spec/local/XOMNY/bin/upload/upload_last_pon.sh &",
|
||||
shell=True,
|
||||
)
|
||||
# status = subprocess.run(f"cp /tmp/spec-e20131-specES1.pdf {user_target}", shell=True)
|
||||
msg = bec.logbook.LogbookMessage()
|
||||
logo_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "LamNI_logo.png")
|
||||
msg.add_file(logo_path).add_text("".join(content).replace("\n", "</p><p>")).add_tag(
|
||||
["BEC", "tomo_parameters", f"dataset_id_{dataset_id}", "LamNI", self.sample_name]
|
||||
[
|
||||
"BEC",
|
||||
"tomo_parameters",
|
||||
f"dataset_id_{dataset_id}",
|
||||
"LamNI",
|
||||
self.sample_name,
|
||||
]
|
||||
)
|
||||
self.client.logbook.send_logbook_message(msg)
|
||||
|
||||
@@ -1295,12 +1232,16 @@ class DataDrivenLamNI(LamNI):
|
||||
|
||||
def sub_tomo_scan(self):
|
||||
raise NotImplementedError(
|
||||
"Cannot run sub_tomo_scan with data-driven LamNI. Please use"
|
||||
" lamni.tomo_scan(subtomo_start=<START_NUM>) instead."
|
||||
"Cannot run sub_tomo_scan with data-driven LamNI. Please use lamni.tomo_scan(subtomo_start=<START_NUM>) instead."
|
||||
)
|
||||
|
||||
def _at_each_angle(
|
||||
self, angle=None, stepsize=None, loptz_pos=None, manual_shift_x=0, manual_shift_y=0
|
||||
self,
|
||||
angle=None,
|
||||
stepsize=None,
|
||||
loptz_pos=None,
|
||||
manual_shift_x=0,
|
||||
manual_shift_y=0,
|
||||
):
|
||||
# Do something...
|
||||
# self.tomo_parameters
|
||||
3
bec_plugins/bec_client/plugins/__init__.py
Normal file
3
bec_plugins/bec_client/plugins/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from .cSAXS import *
|
||||
|
||||
# from .LamNI import *
|
||||
1
bec_plugins/bec_client/plugins/cSAXS/__init__.py
Normal file
1
bec_plugins/bec_client/plugins/cSAXS/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .cSAXS_beamline import fshopen, fshclose, fshstatus, epics_get, epics_put
|
||||
@@ -1,9 +1,10 @@
|
||||
import builtins
|
||||
|
||||
from bec_ipython_client.beamline_mixin import BeamlineShowInfo
|
||||
from rich import box
|
||||
from rich.table import Table
|
||||
|
||||
from bec_client.beamline_mixin import BeamlineShowInfo
|
||||
|
||||
|
||||
class BeamlineInfo(BeamlineShowInfo):
|
||||
def show(self):
|
||||
76
bec_plugins/bec_client/startup/post_startup.py
Normal file
76
bec_plugins/bec_client/startup/post_startup.py
Normal file
@@ -0,0 +1,76 @@
|
||||
"""
|
||||
Post startup script for the BEC client. This script is executed after the
|
||||
IPython shell is started. It is used to load the beamline specific
|
||||
information and to setup the prompts.
|
||||
|
||||
The script is executed in the global namespace of the IPython shell. This
|
||||
means that all variables defined here are available in the shell.
|
||||
|
||||
If needed, bec command-line arguments can be parsed here. For example, to
|
||||
parse the --session argument, add the following lines to the script:
|
||||
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--session", help="Session name", type=str, default="my_default_session")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.session == "my_session":
|
||||
print("Loading my_session session")
|
||||
from bec_plugins.bec_client.plugins.my_session import *
|
||||
else:
|
||||
print("Loading default session")
|
||||
from bec_plugins.bec_client.plugins.default_session import *
|
||||
"""
|
||||
|
||||
# pylint: disable=invalid-name, unused-import, import-error, undefined-variable, unused-variable, unused-argument, no-name-in-module
|
||||
import argparse
|
||||
|
||||
from bec_lib import bec_logger
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
logger.info("Using the cSAXS startup script.")
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--session", help="Session name", type=str, default="cSAXS")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.session == "LamNI":
|
||||
print("Loading LamNI session")
|
||||
from bec_plugins.bec_client.plugins.cSAXS import *
|
||||
from bec_plugins.bec_client.plugins.LamNI import *
|
||||
|
||||
lamni = LamNI(bec)
|
||||
|
||||
elif args.session == "cSAXS":
|
||||
print("Loading cSAXS session")
|
||||
from bec_plugins.bec_client.plugins.cSAXS import *
|
||||
|
||||
|
||||
# SETUP BEAMLINE INFO
|
||||
from bec_client.plugins.SLS.sls_info import OperatorInfo, SLSInfo
|
||||
|
||||
from bec_plugins.bec_client.plugins.cSAXS.beamline_info import BeamlineInfo
|
||||
|
||||
bec._beamline_mixin._bl_info_register(BeamlineInfo)
|
||||
bec._beamline_mixin._bl_info_register(SLSInfo)
|
||||
bec._beamline_mixin._bl_info_register(OperatorInfo)
|
||||
|
||||
# SETUP PROMPTS
|
||||
bec._ip.prompts.username = args.session
|
||||
bec._ip.prompts.status = 1
|
||||
|
||||
|
||||
# REGISTER BEAMLINE CHECKS
|
||||
from bec_lib.bl_conditions import (
|
||||
FastOrbitFeedbackCondition,
|
||||
LightAvailableCondition,
|
||||
ShutterCondition,
|
||||
)
|
||||
|
||||
# _fast_orbit_feedback_condition = FastOrbitFeedbackCondition(dev.sls_fast_orbit_feedback)
|
||||
_light_available_condition = LightAvailableCondition(dev.sls_machine_status)
|
||||
_shutter_condition = ShutterCondition(dev.x12sa_es1_shutter_status)
|
||||
# bec.bl_checks.register(_fast_orbit_feedback_condition)
|
||||
bec.bl_checks.register(_light_available_condition)
|
||||
bec.bl_checks.register(_shutter_condition)
|
||||
25
bec_plugins/bec_client/startup/pre_startup.py
Normal file
25
bec_plugins/bec_client/startup/pre_startup.py
Normal file
@@ -0,0 +1,25 @@
|
||||
"""
|
||||
Pre-startup script for BEC client. This script is executed before the BEC client
|
||||
is started. It can be used to set up the BEC client configuration. The script is
|
||||
executed in the global namespace of the BEC client. This means that all
|
||||
variables defined here are available in the BEC client.
|
||||
|
||||
To set up the BEC client configuration, use the ServiceConfig class. For example,
|
||||
to set the configuration file path, add the following lines to the script:
|
||||
|
||||
import pathlib
|
||||
from bec_lib import ServiceConfig
|
||||
|
||||
current_path = pathlib.Path(__file__).parent.resolve()
|
||||
CONFIG_PATH = f"{current_path}/<path_to_my_config_file.yaml>"
|
||||
|
||||
config = ServiceConfig(CONFIG_PATH)
|
||||
|
||||
If this startup script defined a ServiceConfig object, the BEC client will use
|
||||
it to configure itself. Otherwise, the BEC client will use the default config.
|
||||
"""
|
||||
|
||||
# example:
|
||||
# current_path = pathlib.Path(__file__).parent.resolve()
|
||||
# CONFIG_PATH = f"{current_path}/../../../bec_config.yaml"
|
||||
# config = ServiceConfig(CONFIG_PATH)
|
||||
2742
bec_plugins/device_configs/bec_device_config_sastt.yaml
Executable file
2742
bec_plugins/device_configs/bec_device_config_sastt.yaml
Executable file
File diff suppressed because it is too large
Load Diff
3027
bec_plugins/device_configs/config_session_start_e20632.yaml
Normal file
3027
bec_plugins/device_configs/config_session_start_e20632.yaml
Normal file
File diff suppressed because it is too large
Load Diff
3056
bec_plugins/device_configs/e21125_lamni_config.yaml
Normal file
3056
bec_plugins/device_configs/e21125_lamni_config.yaml
Normal file
File diff suppressed because it is too large
Load Diff
152
bec_plugins/device_configs/lamni_config.py
Normal file
152
bec_plugins/device_configs/lamni_config.py
Normal file
@@ -0,0 +1,152 @@
|
||||
import yaml
|
||||
|
||||
# TODO: fix imports, those classes are located in .../bec/scibec/init_scibec/configs/config.py
|
||||
# (see also lamni_config.py in bec repository)
|
||||
from .config import DemoConfig, X12SAConfig
|
||||
|
||||
|
||||
class LamNIConfig(DemoConfig, X12SAConfig):
|
||||
def run(self):
|
||||
# self.write_galil_motors()
|
||||
# self.write_rt_motors()
|
||||
# self.write_smaract_motors()
|
||||
# self.write_eiger1p5m()
|
||||
self.write_x12sa_status()
|
||||
self.write_sls_status()
|
||||
self.load_csaxs_config()
|
||||
# self.write_sim_user_motors()
|
||||
# self.write_sim_beamline_motors()
|
||||
# self.write_sim_beamline_monitors()
|
||||
|
||||
def write_galil_motors(self):
|
||||
lamni_galil_motors = [
|
||||
("lsamx", "A", -1, 0.5, {"center": 8.768000}),
|
||||
("lsamy", "B", 1, 0.5, {"center": 10.041000}),
|
||||
("lsamrot", "C", 1, 0.5, {}),
|
||||
("loptz", "D", -1, 0.5, {}),
|
||||
("loptx", "E", 1, 0.5, {"in": -0.8380, "out": -0.699}),
|
||||
("lopty", "F", 1, 0.5, {"in": 3.3540, "out": 3.53}),
|
||||
("leyex", "G", -1, 0.001, {"in": 14.117000}),
|
||||
("leyey", "H", -1, 0.001, {"in": 48.069000, "out": 0.5}),
|
||||
]
|
||||
out = {}
|
||||
for m in lamni_galil_motors:
|
||||
out[m[0]] = dict(
|
||||
{
|
||||
"status": {"enabled": True, "enabled_set": True},
|
||||
"deviceClass": "GalilMotor",
|
||||
"deviceConfig": {
|
||||
"axis_Id": m[1],
|
||||
"name": m[0],
|
||||
"labels": m[0],
|
||||
"host": "mpc2680.psi.ch",
|
||||
"port": 8081,
|
||||
"sign": m[2],
|
||||
"limits": [0, 0],
|
||||
"tolerance": m[3],
|
||||
"device_access": True,
|
||||
"device_mapping": {"rt": "rtx"},
|
||||
},
|
||||
"acquisitionConfig": {
|
||||
"schedule": "sync",
|
||||
"acquisitionGroup": "motor",
|
||||
"readoutPriority": "baseline",
|
||||
},
|
||||
"deviceTags": ["lamni"],
|
||||
}
|
||||
)
|
||||
if m[4]:
|
||||
out[m[0]]["userParameter"] = m[4]
|
||||
self.write_section(out, "LamNI Galil motors")
|
||||
|
||||
def write_rt_motors(self):
|
||||
lamni_rt_motors = [
|
||||
("rtx", "A", 1),
|
||||
("rty", "B", 1),
|
||||
]
|
||||
out = dict()
|
||||
for m in lamni_rt_motors:
|
||||
out[m[0]] = dict(
|
||||
{
|
||||
"status": {"enabled": True, "enabled_set": True},
|
||||
"deviceClass": "RtLamniMotor",
|
||||
"deviceConfig": {
|
||||
"axis_Id": m[1],
|
||||
"name": m[0],
|
||||
"labels": m[0],
|
||||
"host": "mpc2680.psi.ch",
|
||||
"port": 3333,
|
||||
"limits": [0, 0],
|
||||
"sign": m[2],
|
||||
"device_access": True,
|
||||
},
|
||||
"acquisitionConfig": {
|
||||
"schedule": "sync",
|
||||
"acquisitionGroup": "motor",
|
||||
"readoutPriority": "baseline",
|
||||
},
|
||||
"deviceTags": ["lamni"],
|
||||
}
|
||||
)
|
||||
self.write_section(out, "LamNI RT")
|
||||
|
||||
def write_smaract_motors(self):
|
||||
lamni_smaract_motors = [
|
||||
("losax", "A", -1, {"in": -0.848000}),
|
||||
("losay", "B", -1, {"in": 0.135000, "out": 3.8}),
|
||||
("losaz", "C", 1, {"in": -1, "out": -3}),
|
||||
("lcsx", "D", -1, {}),
|
||||
("lcsy", "E", -1, {}),
|
||||
]
|
||||
out = dict()
|
||||
for m in lamni_smaract_motors:
|
||||
out[m[0]] = dict(
|
||||
{
|
||||
"status": {"enabled": True, "enabled_set": True},
|
||||
"deviceClass": "SmaractMotor",
|
||||
"deviceConfig": {
|
||||
"axis_Id": m[1],
|
||||
"name": m[0],
|
||||
"labels": m[0],
|
||||
"host": "mpc2680.psi.ch",
|
||||
"port": 8085,
|
||||
"limits": [0, 0],
|
||||
"sign": m[2],
|
||||
"tolerance": 0.05,
|
||||
},
|
||||
"acquisitionConfig": {
|
||||
"schedule": "sync",
|
||||
"acquisitionGroup": "motor",
|
||||
"readoutPriority": "baseline",
|
||||
},
|
||||
"deviceTags": ["lamni"],
|
||||
}
|
||||
)
|
||||
if m[3]:
|
||||
out[m[0]]["userParameter"] = m[3]
|
||||
self.write_section(out, "LamNI SmarAct motors")
|
||||
|
||||
def write_eiger1p5m(self):
|
||||
out = {
|
||||
"eiger1p5m": {
|
||||
"description": "Eiger 1.5M in vacuum detector, in-house developed, PSI",
|
||||
"status": {"enabled": True, "enabled_set": True},
|
||||
"deviceClass": "Eiger1p5MDetector",
|
||||
"deviceConfig": {"device_access": True, "name": "eiger1p5m"},
|
||||
"acquisitionConfig": {
|
||||
"schedule": "sync",
|
||||
"acquisitionGroup": "detector",
|
||||
"readoutPriority": "monitored",
|
||||
},
|
||||
"deviceTags": ["detector"],
|
||||
}
|
||||
}
|
||||
self.write_section(out, "LamNI Eiger 1.5M in vacuum")
|
||||
|
||||
def load_csaxs_config(self):
|
||||
CONFIG_PATH = "./init_scibec/configs/test_config_cSAXS.yaml"
|
||||
content = {}
|
||||
with open(CONFIG_PATH, "r") as csaxs_config_file:
|
||||
content = yaml.safe_load(csaxs_config_file.read())
|
||||
|
||||
self.write_section(content, "Default cSAXS config")
|
||||
2326
bec_plugins/device_configs/test_config_cSAXS.yaml
Normal file
2326
bec_plugins/device_configs/test_config_cSAXS.yaml
Normal file
File diff suppressed because it is too large
Load Diff
11
bec_plugins/device_server/startup.py
Normal file
11
bec_plugins/device_server/startup.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import os
|
||||
|
||||
|
||||
def setup_epics_ca():
|
||||
os.environ["EPICS_CA_AUTO_ADDR_LIST"] = "NO"
|
||||
os.environ["EPICS_CA_ADDR_LIST"] = "129.129.122.255 sls-x12sa-cagw.psi.ch:5836"
|
||||
os.environ["PYTHONIOENCODING"] = "latin1"
|
||||
|
||||
|
||||
def run():
|
||||
setup_epics_ca()
|
||||
@@ -23,10 +23,9 @@ but they are executed in a specific order:
|
||||
import time
|
||||
|
||||
import numpy as np
|
||||
from bec_lib import bec_logger
|
||||
from bec_lib.endpoints import MessageEndpoints
|
||||
from bec_server.scan_server.errors import ScanAbortion
|
||||
from bec_server.scan_server.scans import RequestBase, ScanArgType, ScanBase
|
||||
from bec_lib import MessageEndpoints, bec_logger, messages
|
||||
from scan_server.errors import ScanAbortion
|
||||
from scan_server.scans import RequestBase, ScanArgType, ScanBase
|
||||
|
||||
MOVEMENT_SCALE_X = np.sin(np.radians(15)) * np.cos(np.radians(30))
|
||||
MOVEMENT_SCALE_Y = np.cos(np.radians(15))
|
||||
@@ -97,8 +96,8 @@ class LamNIMixin:
|
||||
coarse_move_req_x = np.abs(lsamx_current - move_x)
|
||||
coarse_move_req_y = np.abs(lsamy_current - move_y)
|
||||
|
||||
self.device_manager.devices.lsamx.read_only = False
|
||||
self.device_manager.devices.lsamy.read_only = False
|
||||
self.device_manager.devices.lsamx.enabled_set = True
|
||||
self.device_manager.devices.lsamy.enabled_set = True
|
||||
|
||||
if (
|
||||
np.abs(y_drift) > 150
|
||||
@@ -110,8 +109,9 @@ class LamNIMixin:
|
||||
logger.info(
|
||||
f"Compensating {[val/1000 for val in lamni_to_stage_coordinates(x_drift,y_drift)]}"
|
||||
)
|
||||
yield from self.stubs.set(device="lsamx", value=move_x)
|
||||
yield from self.stubs.set(device="lsamy", value=move_y)
|
||||
yield from self.stubs.set_and_wait(
|
||||
device=["lsamx", "lsamy"], positions=[move_x, move_y]
|
||||
)
|
||||
|
||||
time.sleep(0.01)
|
||||
rtx_current = yield from self.stubs.send_rpc_and_wait("rtx", "readback.get")
|
||||
@@ -126,14 +126,12 @@ class LamNIMixin:
|
||||
x_drift2 = x_center_expect * 1000 - rtx_current
|
||||
y_drift2 = y_center_expect * 1000 - rty_current
|
||||
logger.info(
|
||||
f"Uncompensated drift of setup after first iteration is x={x_drift2:.3f},"
|
||||
f" y={y_drift2:.3f}"
|
||||
f"Uncompensated drift of setup after first iteration is x={x_drift2:.3f}, y={y_drift2:.3f}"
|
||||
)
|
||||
|
||||
if np.abs(x_drift2) > 5 or np.abs(y_drift2) > 5:
|
||||
logger.info(
|
||||
"Compensating second iteration"
|
||||
f" {[val/1000 for val in lamni_to_stage_coordinates(x_drift2,y_drift2)]}"
|
||||
f"Compensating second iteration {[val/1000 for val in lamni_to_stage_coordinates(x_drift2,y_drift2)]}"
|
||||
)
|
||||
move_x = (
|
||||
x_stage
|
||||
@@ -147,28 +145,26 @@ class LamNIMixin:
|
||||
+ lamni_to_stage_coordinates(x_drift, y_drift)[1] / 1000
|
||||
+ lamni_to_stage_coordinates(x_drift2, y_drift2)[1] / 1000
|
||||
)
|
||||
yield from self.stubs.set(device="lsamx", value=move_x)
|
||||
yield from self.stubs.set(device="lsamy", value=move_y)
|
||||
|
||||
yield from self.stubs.set_and_wait(
|
||||
device=["lsamx", "lsamy"], positions=[move_x, move_y]
|
||||
)
|
||||
time.sleep(0.01)
|
||||
rtx_current = yield from self.stubs.send_rpc_and_wait("rtx", "readback.get")
|
||||
rty_current = yield from self.stubs.send_rpc_and_wait("rty", "readback.get")
|
||||
|
||||
logger.info(
|
||||
f"New scan center interferometer after second iteration {rtx_current:.3f},"
|
||||
f" {rty_current:.3f} microns"
|
||||
f"New scan center interferometer after second iteration {rtx_current:.3f}, {rty_current:.3f} microns"
|
||||
)
|
||||
x_drift2 = x_center_expect * 1000 - rtx_current
|
||||
y_drift2 = y_center_expect * 1000 - rty_current
|
||||
logger.info(
|
||||
f"Uncompensated drift of setup after second iteration is x={x_drift2:.3f},"
|
||||
f" y={y_drift2:.3f}"
|
||||
f"Uncompensated drift of setup after second iteration is x={x_drift2:.3f}, y={y_drift2:.3f}"
|
||||
)
|
||||
else:
|
||||
logger.info("No second iteration required")
|
||||
|
||||
self.device_manager.devices.lsamx.read_only = True
|
||||
self.device_manager.devices.lsamy.read_only = True
|
||||
self.device_manager.devices.lsamx.enabled_set = False
|
||||
self.device_manager.devices.lsamy.enabled_set = False
|
||||
|
||||
yield from self.stubs.send_rpc_and_wait("rtx", "controller.feedback_enable_without_reset")
|
||||
|
||||
@@ -178,12 +174,8 @@ class LamNIMoveToScanCenter(RequestBase, LamNIMixin):
|
||||
scan_report_hint = None
|
||||
scan_type = "step"
|
||||
required_kwargs = []
|
||||
arg_input = {
|
||||
"shift_x": ScanArgType.FLOAT,
|
||||
"shift_y": ScanArgType.FLOAT,
|
||||
"angle": ScanArgType.FLOAT,
|
||||
}
|
||||
arg_bundle_size = {"bundle": len(arg_input), "min": 1, "max": 1}
|
||||
arg_input = [ScanArgType.FLOAT, ScanArgType.FLOAT, ScanArgType.FLOAT]
|
||||
arg_bundle_size = None
|
||||
|
||||
def __init__(self, *args, parameter=None, **kwargs):
|
||||
"""
|
||||
@@ -207,10 +199,10 @@ class LamNIFermatScan(ScanBase, LamNIMixin):
|
||||
scan_report_hint = "table"
|
||||
scan_type = "step"
|
||||
required_kwargs = ["fov_size", "exp_time", "step", "angle"]
|
||||
arg_input = {}
|
||||
arg_bundle_size = {"bundle": len(arg_input), "min": None, "max": None}
|
||||
arg_input = []
|
||||
arg_bundle_size = None
|
||||
|
||||
def __init__(self, *args, parameter: dict = None, **kwargs):
|
||||
def __init__(self, *args, parameter=None, **kwargs):
|
||||
"""
|
||||
A LamNI scan following Fermat's spiral.
|
||||
|
||||
@@ -365,8 +357,7 @@ class LamNIFermatScan(ScanBase, LamNIMixin):
|
||||
self.stitch_x, self.stitch_y, self.angle
|
||||
)
|
||||
logger.info(
|
||||
f"Total shift [mm] {_shfitx+x_stitch_shift/1000+self.shift_x},"
|
||||
f" {_shfity+y_stitch_shift/1000+self.shift_y}"
|
||||
f"Total shift [mm] {_shfitx+x_stitch_shift/1000+self.shift_x}, {_shfity+y_stitch_shift/1000+self.shift_y}"
|
||||
)
|
||||
return (
|
||||
_shfitx + x_stitch_shift / 1000 + self.shift_x,
|
||||
@@ -443,7 +434,7 @@ class LamNIFermatScan(ScanBase, LamNIMixin):
|
||||
}
|
||||
}
|
||||
)
|
||||
yield from self.stubs.set(device="lsamrot", value=angle)
|
||||
yield from self.stubs.set_and_wait(device=["lsamrot"], positions=[angle])
|
||||
|
||||
def scan_core(self):
|
||||
if self.scan_type == "step":
|
||||
@@ -456,18 +447,17 @@ class LamNIFermatScan(ScanBase, LamNIMixin):
|
||||
# scan ID before sending the message to the device server
|
||||
yield from self.stubs.kickoff(device="rtx")
|
||||
while True:
|
||||
yield from self.stubs.read(group="monitored")
|
||||
msg = self.device_manager.connector.get(MessageEndpoints.device_status("rt_scan"))
|
||||
yield from self.stubs.read_and_wait(group="primary", wait_group="readout_primary")
|
||||
msg = self.device_manager.producer.get(MessageEndpoints.device_status("rt_scan"))
|
||||
if msg:
|
||||
status = msg
|
||||
status = messages.DeviceStatusMessage.loads(msg)
|
||||
status_id = status.content.get("status", 1)
|
||||
request_id = status.metadata.get("RID")
|
||||
if status_id == 0 and self.metadata.get("RID") == request_id:
|
||||
break
|
||||
if status_id == 2 and self.metadata.get("RID") == request_id:
|
||||
raise ScanAbortion(
|
||||
"An error occured during the LamNI readout:"
|
||||
f" {status.metadata.get('error')}"
|
||||
f"An error occured during the LamNI readout: {status.metadata.get('error')}"
|
||||
)
|
||||
|
||||
time.sleep(1)
|
||||
@@ -25,9 +25,8 @@ but they are executed in a specific order:
|
||||
|
||||
# import numpy as np
|
||||
|
||||
# from bec_lib import bec_logger, messages
|
||||
# from bec_lib.endpoints import MessageEndpoints
|
||||
# from bec_server.scan_server.errors import ScanAbortion
|
||||
# from bec_server.scan_server.scans import FlyScanBase, RequestBase, ScanArgType, ScanBase
|
||||
# from bec_lib import MessageEndpoints, bec_logger, messages
|
||||
# from scan_server.errors import ScanAbortion
|
||||
# from scan_server.scans import FlyScanBase, RequestBase, ScanArgType, ScanBase
|
||||
|
||||
# logger = bec_logger.logger
|
||||
182
bec_plugins/utils/csaxs_post_archive.py
Executable file
182
bec_plugins/utils/csaxs_post_archive.py
Executable file
@@ -0,0 +1,182 @@
|
||||
import os
|
||||
import json
|
||||
import subprocess
|
||||
import requests
|
||||
|
||||
from bec_lib.file_utils import FileWriterMixin
|
||||
#from bec_lib.bec_service import SERVICE_CONFIG
|
||||
|
||||
|
||||
class csaxs_archiver:
|
||||
"""Class to archive data from a beamtime.
|
||||
To run this script from a shell, go to discovery.psi.ch and copy your token.
|
||||
Complement the information in user_input below in the if __name__ == __main__ part of the script.
|
||||
Afterwards, get a Keberos token (kinit) for yourself in the shell.
|
||||
Activate the bec_venv by doing "source bec_venv/bin/activate" and then run this code via python $filename.
|
||||
As a last step, adjust the dictionary below in if __name__ == '__main__' with your token as well as information about the experiment
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
start_scan: int,
|
||||
stop_scan: int,
|
||||
base_path: str,
|
||||
log_path: str,
|
||||
eacc: str,
|
||||
pi: str,
|
||||
pi_email: str,
|
||||
token: str,
|
||||
type: str = "raw",
|
||||
overwrite: bool = False,
|
||||
online: bool = True,
|
||||
):
|
||||
self.start_scan = start_scan
|
||||
self.stop_scan = stop_scan
|
||||
self.log_path = os.path.expanduser(log_path)
|
||||
self.eacc = eacc
|
||||
self.pi = pi
|
||||
self.pi_email = pi_email
|
||||
self.token = token
|
||||
self.type = type
|
||||
self.overwrite = overwrite
|
||||
self.online = online
|
||||
|
||||
#from bec_lib.bec_service import SERVICE_CONFIG
|
||||
#SERVICE_CONFIG.config["service_config"]["file_writer"]
|
||||
self._load_datacatalogue_module()
|
||||
self._create_directory(base_path)
|
||||
self._disable_mail_confirmation()
|
||||
|
||||
self.service_cfg = {'base_path' : f'{self.base_path}'}
|
||||
|
||||
self.file_writer = FileWriterMixin(self.service_cfg)
|
||||
|
||||
def _disable_mail_confirmation(self):
|
||||
# Define the URL and payload
|
||||
url = "https://dacat.psi.ch/api/v3/Policies/updatewhere"
|
||||
payload = {
|
||||
"ownerGroupList": f'p{self.eacc[1:]}',
|
||||
"data": '{"archiveEmailNotification": false, "accessGroups": ["slscsaxs"]}'
|
||||
}
|
||||
|
||||
# Define headers
|
||||
headers = {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"Accept": "application/json",
|
||||
}
|
||||
|
||||
# Add the access_token to the URL
|
||||
url += "?access_token=" + self.token
|
||||
|
||||
# Make a POST request
|
||||
print(url, payload, headers)
|
||||
response = requests.post(url, data=payload, headers=headers)
|
||||
|
||||
# Check the response
|
||||
if response.status_code == 200:
|
||||
print("Request was successful.")
|
||||
print(response.json())
|
||||
else:
|
||||
print("Request failed with status code:", response.status_code)
|
||||
print(response.text)
|
||||
|
||||
def _create_directory(self, base_path: str) -> None:
|
||||
if self.online:
|
||||
self.base_path = os.path.expanduser("~/Data10")
|
||||
else:
|
||||
self.base_path = base_path
|
||||
|
||||
if not os.path.exists(self.log_path):
|
||||
os.makedirs(self.log_path)
|
||||
|
||||
def _load_datacatalogue_module(self):
|
||||
command = 'module add datacatalog/1.1.9'
|
||||
os.popen(command)
|
||||
# result = subprocess.run(
|
||||
# command,
|
||||
# shell=False,
|
||||
# stdout=subprocess.PIPE,
|
||||
# stderr=subprocess.PIPE,
|
||||
# universal_newlines=True,
|
||||
# )
|
||||
# if result.returncode == 0:
|
||||
# print(f"Command {command} was succesful")
|
||||
# else:
|
||||
# print(f"Failed to run command {command} with return message {result.returncode}")
|
||||
|
||||
def prep_metadata(self, scannr: int) -> dict:
|
||||
user_metadata = {}
|
||||
user_metadata.update(
|
||||
{
|
||||
"principalInvestigator": self.pi_email,
|
||||
"owner": self.pi,
|
||||
"ownerEmail": self.pi_email,
|
||||
"sourceFolder": self.base_path,
|
||||
"creationLocation": "/PSI/SLS/CSAXS",
|
||||
"type": "raw",
|
||||
"ownerGroup": f"p{self.eacc.strip('e')}",
|
||||
"datasetName": f"S{scannr:05d}",
|
||||
}
|
||||
)
|
||||
return user_metadata
|
||||
|
||||
def _write_ingestion_log(self, scannr: int) -> None:
|
||||
...
|
||||
|
||||
def run_for_all_scans(self):
|
||||
for scan in range(self.start_scan, self.stop_scan + 1):
|
||||
print(f"Start ingestion for scan {scan}")
|
||||
fname = os.path.join(os.path.expanduser(self.log_path), f"ingestion_log_S{scan:05d}")
|
||||
self.datafile_name = f"{fname}.txt"
|
||||
if os.path.isfile(self.datafile_name) and not self.overwrite == True:
|
||||
print(
|
||||
f"Skipping scan {scan}, already ingested due to logs, moving on to next scan {scan+1}"
|
||||
)
|
||||
continue
|
||||
|
||||
user_metadata = self.prep_metadata(scan)
|
||||
|
||||
# Write metadata file in json file
|
||||
self.metadata_file = f"{fname}.json"
|
||||
with open(self.metadata_file, "w") as file:
|
||||
json.dump(user_metadata, file)
|
||||
|
||||
# Compile datapath based on structure a cSAXS
|
||||
datadir_path = os.path.join('data', self.file_writer.get_scan_directory(scan, 1000, 5))
|
||||
print(f"Archiving directory {datadir_path}")
|
||||
if not os.path.isdir(os.path.join(self.base_path, datadir_path)):
|
||||
print(f"Did not find directory {datadir_path}, skipping scan {scan}")
|
||||
continue
|
||||
|
||||
# Create datafile path for archiving
|
||||
with open(self.datafile_name, "w") as file:
|
||||
file.write(datadir_path)
|
||||
|
||||
print(f"Starting ingestion for S#{scan}")
|
||||
command = f'datasetIngestor -allowexistingsource -ingest -autoarchive -noninteractive -token {self.token} {self.metadata_file} {self.datafile_name}'
|
||||
rtr = os.popen(command)
|
||||
|
||||
#with open(os.path.join(fname,'_log.txt'), "w") as file:
|
||||
# print(f'Writing reponse to file')
|
||||
# file.write(rtr.read())
|
||||
# result = subprocess.run(command, shell=False, stdout = subprocess.PIPE, stderr = subprocess.PIPE, universal_newlines=True)
|
||||
# if result.returncode == 0:
|
||||
# print(f"Command {command} was succesful")
|
||||
# else:
|
||||
# print(f"Failed to run command {command} with return message {result.returncode}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Generate dictionary with user input.
|
||||
user_input = {
|
||||
"base_path": "~/Data10",
|
||||
"eacc": "e20638",
|
||||
"pi": "Emma Sparr",
|
||||
"pi_email": "emma.sparr@fkem1.lu.se",
|
||||
'log_path' : '~/Data10/documentation/ingestion_logs/',
|
||||
'token' : 'YK8gkmQmEVxVxjiA57D6tVmpBVs7T235nWEuBT0behN9BPM2BdWARWPPgEsQVrPe',
|
||||
'start_scan' : 1,
|
||||
'stop_scan' : 450,
|
||||
}
|
||||
archiver = csaxs_archiver(**user_input)
|
||||
archiver.run_for_all_scans()
|
||||
88
bec_plugins/utils/saxs_params.py
Executable file
88
bec_plugins/utils/saxs_params.py
Executable file
@@ -0,0 +1,88 @@
|
||||
import csv
|
||||
import os
|
||||
from collections import defaultdict
|
||||
from collections.abc import Callable
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
class ScanItem:
|
||||
def __init__(self, offset_xy: Callable) -> None:
|
||||
self.start_entry = None
|
||||
self.end_entry = None
|
||||
self.offset_xy = offset_xy
|
||||
|
||||
def to_scan_params(self) -> dict:
|
||||
scan_params = {
|
||||
"start_x": float(self.start_entry["X"]) + self.offset_xy()[0],
|
||||
"start_y": float(self.start_entry["Y"]) + self.offset_xy()[1],
|
||||
"end_x": float(self.end_entry["X"]) + self.offset_xy()[0],
|
||||
"end_y": float(self.end_entry["Y"]) + self.offset_xy()[1],
|
||||
"interval_x": int(
|
||||
np.round(
|
||||
np.abs(float(self.start_entry["X"]) - float(self.end_entry["X"]))
|
||||
/ (float(self.start_entry["step_x [mu]"]) * 1e-3)
|
||||
)
|
||||
),
|
||||
"interval_y": int(
|
||||
np.round(
|
||||
np.abs(float(self.start_entry["Y"]) - float(self.end_entry["Y"]))
|
||||
/ (float(self.start_entry["step_y [mu]"]) * 1e-3)
|
||||
)
|
||||
),
|
||||
"exp_time": float(self.start_entry["exp_time [s]"]),
|
||||
"readout_time": 3e-3,
|
||||
"md": {"sample_name": self.start_entry["sample name"]},
|
||||
}
|
||||
if scan_params["interval_x"] < 1 or scan_params["interval_x"] < 1:
|
||||
raise ValueError("Bugger off...")
|
||||
return scan_params
|
||||
|
||||
|
||||
class SAXSParams:
|
||||
def __init__(self, offset: Callable):
|
||||
self.offset_xy = offset
|
||||
self.data = defaultdict(lambda: ScanItem(offset))
|
||||
|
||||
def load_from_csv(self, file_path: str) -> None:
|
||||
"""
|
||||
Load the acquisition parameter from a csv file.
|
||||
"""
|
||||
|
||||
if not os.path.exists(file_path):
|
||||
raise FileNotFoundError(
|
||||
f"The specified CSV file could not be found. Please check that the given path is correct: {file_path}."
|
||||
)
|
||||
|
||||
data_transposed = defaultdict(lambda: [])
|
||||
with open(os.path.expanduser(file_path), "r") as file:
|
||||
csv_reader = csv.DictReader(file)
|
||||
for row in csv_reader:
|
||||
for key, val in row.items():
|
||||
data_transposed[key].append(val)
|
||||
if int(row["start"]):
|
||||
self.data[row["sample name"]].start_entry = row
|
||||
else:
|
||||
self.data[row["sample name"]].end_entry = row
|
||||
self._check_params(dict(data_transposed))
|
||||
|
||||
def _check_params(self, data_transposed: dict) -> dict:
|
||||
sample_names = set(data_transposed["sample name"])
|
||||
if len(data_transposed["start"]) != len(sample_names) * 2:
|
||||
raise ValueError(
|
||||
f"The given params file does not provide N*2 start/stop positions. Found {len(sample_names)} samples and {len(data_transposed['start'])} start/stop positions."
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from pprint import pprint
|
||||
|
||||
INPUT_FILE = "/sls/X12SA/data/e21206/Data10/software/test_script.csv"
|
||||
|
||||
def my_offset():
|
||||
return [0, 0]
|
||||
|
||||
params = SAXSParams(my_offset)
|
||||
params.load_from_csv(INPUT_FILE)
|
||||
for key in params.data:
|
||||
pprint(params.data[key].to_scan_params())
|
||||
@@ -1,7 +1,3 @@
|
||||
""" Script used for parsing scan parameters from a CSV file as created by the motormap GUI.
|
||||
This needs to be reviewed and tested during the deployment phase."""
|
||||
|
||||
# pylint: skip-file
|
||||
import csv
|
||||
import os
|
||||
from collections import defaultdict
|
||||
13
bec_plugins/utils/service_config.py
Executable file
13
bec_plugins/utils/service_config.py
Executable file
@@ -0,0 +1,13 @@
|
||||
import yaml
|
||||
|
||||
CONFIG_PATH = "/sls/X12SA/data/gac-x12saop/bec/config/bec_service_config.yaml"
|
||||
|
||||
|
||||
def load_service_config() -> dict:
|
||||
"""Load the service configuration from the YAML file."""
|
||||
with open(CONFIG_PATH, "r", encoding="utf-8") as stream:
|
||||
try:
|
||||
config = yaml.safe_load(stream)
|
||||
except yaml.YAMLError as exc:
|
||||
print(exc)
|
||||
return config
|
||||
1
bin/.gitignore
vendored
1
bin/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
# Add anything you don't want to check in to git, e.g. very large files
|
||||
@@ -3,9 +3,8 @@ from __future__ import annotations
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from bec_lib import bec_logger, messages
|
||||
from bec_lib.endpoints import MessageEndpoints
|
||||
from bec_lib.redis_connector import MessageObject, RedisConnector
|
||||
from bec_lib import MessageEndpoints, RedisConnector, bec_logger, messages
|
||||
from bec_lib.redis_connector import MessageObject
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
@@ -13,6 +12,7 @@ logger = bec_logger.logger
|
||||
class PilatusConverter:
|
||||
def __init__(self, host: str, port: int) -> None:
|
||||
self._connector = RedisConnector(f"{host}:{port}")
|
||||
self._producer = self._connector.producer()
|
||||
|
||||
def start(self) -> None:
|
||||
"""start the consumer"""
|
||||
@@ -27,7 +27,7 @@ class PilatusConverter:
|
||||
message (MessageObject): Message object
|
||||
parent (PilatusConverter): Parent object
|
||||
"""
|
||||
msg = message.value
|
||||
msg = messages.MessageReader.loads(message.value)
|
||||
print(msg)
|
||||
if not msg:
|
||||
return
|
||||
@@ -56,9 +56,10 @@ class PilatusConverter:
|
||||
"""
|
||||
Start the consumer.
|
||||
"""
|
||||
self._connector.register(
|
||||
file_consumer = self._connector.consumer(
|
||||
MessageEndpoints.file_event("pilatus_2"), cb=self.on_new_message, parent=self
|
||||
)
|
||||
file_consumer.start()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
5
bin/open_tunnel.sh
Executable file
5
bin/open_tunnel.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
|
||||
for i in `seq 1 8`
|
||||
do
|
||||
ssh -N -R 6379:localhost:6379 x12sa-cn-$i &
|
||||
done
|
||||
48
bin/setup_bec.sh
Executable file
48
bin/setup_bec.sh
Executable file
@@ -0,0 +1,48 @@
|
||||
|
||||
if [ "pc15543.psi.ch" != "$(hostname)" ]; then
|
||||
echo "Please run this script on pc15543"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
module use unstable
|
||||
module add psi-python311/2024.02
|
||||
echo module add tmux/3.2 >> ~/.bashrc
|
||||
echo module add redis/7.0.12 >> ~/.bashrc
|
||||
|
||||
source ~/.bashrc
|
||||
|
||||
cd ~/Data10
|
||||
mkdir -p software/
|
||||
mkdir -p ~/bec/scripts
|
||||
cd software
|
||||
|
||||
git clone https://gitlab.psi.ch/bec/bec.git
|
||||
git clone https://gitlab.psi.ch/bec/ophyd_devices.git
|
||||
git clone https://gitlab.psi.ch/bec/bec-widgets.git
|
||||
|
||||
python -m venv ./bec_venv
|
||||
source ./bec_venv/bin/activate
|
||||
|
||||
cd bec
|
||||
git checkout sastt-online-changes
|
||||
pip install -e ./bec_server[dev]
|
||||
|
||||
cd ../csaxs-bec
|
||||
pip install -e .[dev]
|
||||
|
||||
#redis-server --protected-mode no &
|
||||
|
||||
read -p "Do you want to set the current BEC account to $(whoami)? (yes/no) " yn
|
||||
|
||||
val=$(whoami)
|
||||
|
||||
case $yn in
|
||||
yes ) echo ok, setting account to $val;
|
||||
redis-cli SET internal/account:val $val;;
|
||||
no ) echo ;;
|
||||
* ) echo invalid response;
|
||||
exit 1;;
|
||||
esac
|
||||
|
||||
|
||||
$(pwd)/open_tunnel.sh
|
||||
17
bin/setup_bec_widgets.sh
Executable file
17
bin/setup_bec_widgets.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
module use unstable
|
||||
module add psi-python311/2024.02
|
||||
|
||||
cd ~/Data10/software
|
||||
python -m venv ./bec_widgets_venv
|
||||
source ./bec_widgets_venv/bin/activate
|
||||
pip install --upgrade pip
|
||||
cd ~/Data10/software/bec/bec_lib
|
||||
pip install -e .
|
||||
|
||||
cd ~/Data10/software/csaxs-bec
|
||||
pip install -e .
|
||||
|
||||
cd ~/Data10/software/bec-widgets
|
||||
pip install -e .
|
||||
|
||||
echo "For the moment widgets only run on beamline consoles comp1/2 and cons1"
|
||||
@@ -1,2 +0,0 @@
|
||||
from .load_additional_correction import lamni_read_additional_correction
|
||||
from .x_ray_eye_align import DataDrivenLamNI, LamNI, MagLamNI, XrayEyeAlign
|
||||
@@ -1,329 +0,0 @@
|
||||
import builtins
|
||||
import time
|
||||
|
||||
from rich import box
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
|
||||
from csaxs_bec.bec_ipython_client.plugins.cSAXS import epics_put, fshclose
|
||||
|
||||
# import builtins to avoid linter errors
|
||||
dev = builtins.__dict__.get("dev")
|
||||
umv = builtins.__dict__.get("umv")
|
||||
bec = builtins.__dict__.get("bec")
|
||||
|
||||
|
||||
class LamNIInitError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class LaMNIInitStagesMixin:
|
||||
def lamni_init_stages(self):
|
||||
user_input = input("Starting initialization of LamNI stages. OK? [y/n]")
|
||||
if user_input == "y":
|
||||
print("staring...")
|
||||
dev.lsamrot.enabled = True
|
||||
else:
|
||||
return
|
||||
|
||||
if self.check_all_axes_of_lamni_referenced():
|
||||
user_input = input("Continue anyways? [y/n]")
|
||||
if user_input == "y":
|
||||
print("ok then...")
|
||||
else:
|
||||
return
|
||||
|
||||
axis_id_lsamrot = dev.lsamrot._config["deviceConfig"].get("axis_Id")
|
||||
if dev.lsamrot.controller.get_motor_limit_switch(axis_id_lsamrot)[1] == False:
|
||||
user_input = input("The rotation stage will be moved to one limit [y/n]")
|
||||
if user_input == "y":
|
||||
print("starting...")
|
||||
else:
|
||||
return
|
||||
|
||||
self.drive_axis_to_limit(dev.lsamrot, "forward")
|
||||
dev.lsamrot.enabled = False
|
||||
print("Now hard reboot the controller and run the initialization routine again.")
|
||||
print("The controller will be disabled in bec. To enable dev.lsamrot.enabled=True")
|
||||
return
|
||||
|
||||
user_input = input(
|
||||
"Init of loptz. Can the stage move to the upstream limit without collision?? [y/n]"
|
||||
)
|
||||
if user_input == "y":
|
||||
print("ok then...")
|
||||
else:
|
||||
return
|
||||
|
||||
print("Referencing loptz")
|
||||
self.drive_axis_to_limit(dev.loptz, "forward")
|
||||
self.find_reference_mark(dev.loptz)
|
||||
|
||||
print("Referencing loptx")
|
||||
self.drive_axis_to_limit(dev.loptx, "reverse")
|
||||
self.find_reference_mark(dev.loptx)
|
||||
|
||||
print("Referencing lopty")
|
||||
self.drive_axis_to_limit(dev.lopty, "forward")
|
||||
self.find_reference_mark(dev.lopty)
|
||||
|
||||
print("Referencing lsamx")
|
||||
self.drive_axis_to_limit(dev.lsamx, "forward")
|
||||
self.find_reference_mark(dev.lsamx)
|
||||
|
||||
print("Referencing lsamy")
|
||||
self.drive_axis_to_limit(dev.lsamy, "reverse")
|
||||
self.find_reference_mark(dev.lsamy)
|
||||
|
||||
# the dual encoder requires the reference mark to pass on both encoders
|
||||
print("Referencing lsamrot")
|
||||
self.drive_axis_to_limit(dev.lsamrot, "reverse")
|
||||
time.sleep(0.1)
|
||||
self.find_reference_mark(dev.lsamrot)
|
||||
|
||||
user_input = input("Init of leye. Can the stage move to -x limit without collision? [y/n]")
|
||||
if user_input == "y":
|
||||
print("starting...")
|
||||
else:
|
||||
return
|
||||
|
||||
print("Referencing leyex")
|
||||
self.drive_axis_to_limit(dev.leyex, "forward")
|
||||
print("Referencing leyey")
|
||||
self.drive_axis_to_limit(dev.leyey, "forward")
|
||||
|
||||
# set_lm lsamx 6 14
|
||||
# set_lm lsamy 6 14
|
||||
# set_lm lsamrot -3 362
|
||||
# set_lm loptx -1 -0.2
|
||||
# set_lm lopty 3.0 3.6
|
||||
# set_lm loptz 82 87
|
||||
# set_lm leyex 0 25
|
||||
# set_lm leyey 0.5 50
|
||||
|
||||
print("Init of Smaract stages")
|
||||
dev.losax.controller.find_reference_mark(2, 0, 1000, 1)
|
||||
time.sleep(1)
|
||||
dev.losax.controller.find_reference_mark(0, 0, 1000, 1)
|
||||
time.sleep(1)
|
||||
dev.losax.controller.find_reference_mark(1, 0, 1000, 1)
|
||||
time.sleep(1)
|
||||
# dev.losax.controller.find_reference_mark(3, 1, 1000, 1)
|
||||
# time.sleep(1)
|
||||
# dev.losax.controller.find_reference_mark(4, 1, 1000, 1)
|
||||
# time.sleep(1)
|
||||
|
||||
# set_lm losax -1.5 0.25
|
||||
# set_lm losay -2.5 4.1
|
||||
# set_lm losaz -4.1 -0.5
|
||||
# set_lm lcsy -1.5 5
|
||||
|
||||
self._align_setup()
|
||||
|
||||
def find_reference_mark(self, device):
|
||||
axis_id = device._config["deviceConfig"].get("axis_Id")
|
||||
axis_id_numeric = self.axis_id_to_numeric(axis_id)
|
||||
device.controller.find_reference(axis_id_numeric)
|
||||
|
||||
def drive_axis_to_limit(self, device, direction):
|
||||
axis_id = device._config["deviceConfig"].get("axis_Id")
|
||||
axis_id_numeric = self.axis_id_to_numeric(axis_id)
|
||||
device.controller.drive_axis_to_limit(axis_id_numeric, direction)
|
||||
|
||||
def axis_id_to_numeric(self, axis_id) -> int:
|
||||
return ord(axis_id.lower()) - 97
|
||||
|
||||
def _align_setup(self):
|
||||
user_input = input("Start moving stages to default initial positions? [y/n]")
|
||||
if user_input == "y":
|
||||
print("Start moving stages...")
|
||||
else:
|
||||
print("Stopping.")
|
||||
return
|
||||
|
||||
lsamx_center = dev.lsamx.user_parameter.get("center")
|
||||
if lsamx_center is None:
|
||||
raise LamNIInitError(
|
||||
"Could not find a lsamx center position. Please check your device config."
|
||||
)
|
||||
lsamy_center = dev.lsamy.user_parameter.get("center")
|
||||
if lsamy_center is None:
|
||||
raise LamNIInitError(
|
||||
"Could not find a lsamy center position. Please check your device config."
|
||||
)
|
||||
umv(dev.lsamx, lsamx_center, dev.lsamy, lsamy_center, dev.loptx, -0.3, dev.lopty, 0)
|
||||
umv(dev.losax, -1)
|
||||
umv(dev.loptz, 82.25)
|
||||
umv(dev.lsamrot, -1)
|
||||
umv(dev.lsamrot, 0)
|
||||
|
||||
time.sleep(2)
|
||||
dev.rtx.controller.feedback_disable_and_even_reset_lamni_angle_interferometer()
|
||||
|
||||
def check_all_axes_of_lamni_referenced(self):
|
||||
if (
|
||||
dev.losax.controller.axis_is_referenced(0)
|
||||
& dev.losax.controller.axis_is_referenced(1)
|
||||
& dev.losax.controller.axis_is_referenced(2)
|
||||
& dev.lsamx.controller.all_axes_referenced()
|
||||
):
|
||||
print("All axes of LamNI are referenced.")
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class LamNIOpticsMixin:
|
||||
@staticmethod
|
||||
def _get_user_param_safe(device, var):
|
||||
param = dev[device].user_parameter
|
||||
if not param or param.get(var) is None:
|
||||
raise ValueError(f"Device {device} has no user parameter definition for {var}.")
|
||||
return param.get(var)
|
||||
|
||||
def leye_out(self):
|
||||
self.loptics_in()
|
||||
fshclose()
|
||||
leyey_out = self._get_user_param_safe("leyey", "out")
|
||||
umv(dev.leyey, leyey_out)
|
||||
|
||||
epics_put("XOMNYI-XEYE-ACQ:0", 2)
|
||||
# move rotation stage to zero to avoid problems with wires
|
||||
umv(dev.lsamrot, 0)
|
||||
umv(dev.dttrz, 5854, dev.fttrz, 2395)
|
||||
|
||||
def leye_in(self):
|
||||
bec.queue.next_dataset_number += 1
|
||||
# move rotation stage to zero to avoid problems with wires
|
||||
umv(dev.lsamrot, 0)
|
||||
umv(dev.dttrz, 6419.677, dev.fttrz, 2959.979)
|
||||
while True:
|
||||
moved_out = (input("Did the flight tube move out? (Y/n)") or "y").lower()
|
||||
if moved_out == "y":
|
||||
break
|
||||
if moved_out == "n":
|
||||
return
|
||||
leyex_in = self._get_user_param_safe("leyex", "in")
|
||||
leyey_in = self._get_user_param_safe("leyey", "in")
|
||||
umv(dev.leyex, leyex_in, dev.leyey, leyey_in)
|
||||
self.align.update_frame()
|
||||
|
||||
def _lfzp_in(self):
|
||||
loptx_in = self._get_user_param_safe("loptx", "in")
|
||||
lopty_in = self._get_user_param_safe("lopty", "in")
|
||||
umv(
|
||||
dev.loptx, loptx_in, dev.lopty, lopty_in
|
||||
) # for 7.2567 keV and 150 mu, 60 nm fzp, loptz 83.6000 for propagation 1.4 mm
|
||||
|
||||
def lfzp_in(self):
|
||||
"""
|
||||
move in the lamni zone plate.
|
||||
This will disable rt feedback, move the FZP and re-enabled the feedback.
|
||||
"""
|
||||
if "rtx" in dev and dev.rtx.enabled:
|
||||
dev.rtx.controller.feedback_disable()
|
||||
|
||||
self._lfzp_in()
|
||||
|
||||
if "rtx" in dev and dev.rtx.enabled:
|
||||
dev.rtx.controller.feedback_enable_with_reset()
|
||||
|
||||
def loptics_in(self):
|
||||
"""
|
||||
Move in the lamni optics, including the FZP and the OSA.
|
||||
"""
|
||||
self.lfzp_in()
|
||||
self.losa_in()
|
||||
|
||||
def loptics_out(self):
|
||||
"""Move out the lamni optics"""
|
||||
if "rtx" in dev and dev.rtx.enabled:
|
||||
dev.rtx.controller.feedback_disable()
|
||||
|
||||
# self.lcs_out()
|
||||
self.losa_out()
|
||||
loptx_out = self._get_user_param_safe("loptx", "out")
|
||||
lopty_out = self._get_user_param_safe("lopty", "out")
|
||||
umv(dev.loptx, loptx_out, dev.lopty, lopty_out)
|
||||
|
||||
if "rtx" in dev and dev.rtx.enabled:
|
||||
time.sleep(1)
|
||||
dev.rtx.controller.feedback_enable_with_reset()
|
||||
|
||||
def lcs_in(self):
|
||||
# umv lcsx -1.852 lcsy -0.095
|
||||
pass
|
||||
|
||||
def lcs_out(self):
|
||||
umv(dev.lcsy, 3)
|
||||
|
||||
def losa_in(self):
|
||||
# 6.2 keV, 170 um FZP
|
||||
# umv(dev.losax, -1.4450000, dev.losay, -0.1800)
|
||||
# umv(dev.losaz, -1)
|
||||
# 6.7, 170
|
||||
# umv(dev.losax, -1.4850, dev.losay, -0.1930)
|
||||
# umv(dev.losaz, 1.0000)
|
||||
# 7.2, 150
|
||||
losax_in = self._get_user_param_safe("losax", "in")
|
||||
losay_in = self._get_user_param_safe("losay", "in")
|
||||
losaz_in = self._get_user_param_safe("losaz", "in")
|
||||
umv(dev.losax, losax_in, dev.losay, losay_in)
|
||||
umv(dev.losaz, losaz_in)
|
||||
# 11 kev
|
||||
# umv(dev.losax, -1.161000, dev.losay, -0.196)
|
||||
# umv(dev.losaz, 1.0000)
|
||||
|
||||
def losa_out(self):
|
||||
losay_out = self._get_user_param_safe("losay", "out")
|
||||
losaz_out = self._get_user_param_safe("losaz", "out")
|
||||
umv(dev.losaz, losaz_out)
|
||||
umv(dev.losay, losay_out)
|
||||
|
||||
def lfzp_info(self, mokev_val=-1):
|
||||
|
||||
if mokev_val == -1:
|
||||
try:
|
||||
mokev_val = dev.mokev.readback.get()
|
||||
except:
|
||||
print(
|
||||
"Device mokev does not exist. You can specify the energy in keV as an argument instead."
|
||||
)
|
||||
return
|
||||
loptz_val = dev.loptz.read()["loptz"]["value"]
|
||||
distance = -loptz_val + 85.6 + 52
|
||||
print(f"The sample is in a distance of {distance:.1f} mm from the FZP.")
|
||||
|
||||
diameters = [80e-6, 100e-6, 120e-6, 150e-6, 170e-6, 200e-6, 220e-6, 250e-6]
|
||||
|
||||
console = Console()
|
||||
table = Table(
|
||||
title=f"At the current energy of {mokev_val:.4f} keV we have following options:",
|
||||
box=box.SQUARE,
|
||||
)
|
||||
table.add_column("Diameter", justify="center")
|
||||
table.add_column("Focal distance", justify="center")
|
||||
table.add_column("Current beam size", justify="center")
|
||||
|
||||
wavelength = 1.2398e-9 / mokev_val
|
||||
|
||||
for diameter in diameters:
|
||||
outermost_zonewidth = 60e-9
|
||||
focal_distance = diameter * outermost_zonewidth / wavelength
|
||||
beam_size = (
|
||||
-diameter / (focal_distance * 1000) * (focal_distance * 1000 - distance) * 1e6
|
||||
)
|
||||
table.add_row(
|
||||
f"{diameter*1e6:.2f} microns",
|
||||
f"{focal_distance:.2f} mm",
|
||||
f"{beam_size:.2f} microns",
|
||||
)
|
||||
|
||||
console.print(table)
|
||||
|
||||
print("OSA Information:")
|
||||
# print(f"Current losaz %.1f\n", A[losaz])
|
||||
# print("The OSA will collide with the sample plane at %.1f\n\n", 89.3-A[loptz])
|
||||
print(
|
||||
"The numbers presented here are for a sample in the plane of the lamni sample holder.\n"
|
||||
)
|
||||
@@ -1,2 +0,0 @@
|
||||
from .cSAXS_beamline import epics_get, epics_put, fshclose, fshopen, fshstatus
|
||||
from .csaxs_bl_checks import cSAXSBeamlineChecks
|
||||
@@ -1,122 +0,0 @@
|
||||
import builtins
|
||||
import datetime
|
||||
import threading
|
||||
import time
|
||||
|
||||
from bec_lib import bec_logger
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
if builtins.__dict__.get("bec"):
|
||||
bec = builtins.__dict__.get("bec")
|
||||
|
||||
|
||||
class cSAXSBeamlineChecks:
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.check_shutter = True
|
||||
self.check_light_available = True
|
||||
self.check_fofb = True
|
||||
self._check_msgs = []
|
||||
self._beam_is_okay = True
|
||||
self._stop_beam_check_event = None
|
||||
self.beam_check_thread = None
|
||||
|
||||
def get_beamline_checks_enabled(self):
|
||||
print(
|
||||
f"Shutter: {self.check_shutter}\nFOFB: {self.check_fofb}\nLight available:"
|
||||
f" {self.check_light_available}"
|
||||
)
|
||||
|
||||
@property
|
||||
def beamline_checks_enabled(self):
|
||||
return {
|
||||
"shutter": self.check_shutter,
|
||||
"fofb": self.check_fofb,
|
||||
"light available": self.check_light_available,
|
||||
}
|
||||
|
||||
@beamline_checks_enabled.setter
|
||||
def beamline_checks_enabled(self, val: bool):
|
||||
self.check_shutter = val
|
||||
self.check_light_available = val
|
||||
self.check_fofb = val
|
||||
self.get_beamline_checks_enabled()
|
||||
|
||||
def _run_beamline_checks(self):
|
||||
msgs = []
|
||||
dev = builtins.__dict__.get("dev")
|
||||
try:
|
||||
if self.check_shutter:
|
||||
shutter_val = dev.x12sa_es1_shutter_status.read(cached=True)
|
||||
if shutter_val["value"].lower() != "open":
|
||||
self._beam_is_okay = False
|
||||
msgs.append("Check beam failed: Shutter is closed.")
|
||||
if self.check_light_available:
|
||||
machine_status = dev.sls_machine_status.read(cached=True)
|
||||
if machine_status["value"] not in ["Light Available", "Light-Available"]:
|
||||
self._beam_is_okay = False
|
||||
msgs.append("Check beam failed: Light not available.")
|
||||
if self.check_fofb:
|
||||
fast_orbit_feedback = dev.sls_fast_orbit_feedback.read(cached=True)
|
||||
if fast_orbit_feedback["value"] != "running":
|
||||
self._beam_is_okay = False
|
||||
msgs.append("Check beam failed: Fast orbit feedback is not running.")
|
||||
except Exception:
|
||||
logger.warning("Failed to check beam.")
|
||||
return msgs
|
||||
|
||||
def _check_beam(self):
|
||||
while not self._stop_beam_check_event.is_set():
|
||||
self._check_msgs = self._run_beamline_checks()
|
||||
|
||||
if not self._beam_is_okay:
|
||||
self._stop_beam_check_event.set()
|
||||
time.sleep(1)
|
||||
|
||||
def _start_beam_check(self):
|
||||
self._beam_is_okay = True
|
||||
self._stop_beam_check_event = threading.Event()
|
||||
|
||||
self.beam_check_thread = threading.Thread(target=self._check_beam, daemon=True)
|
||||
self.beam_check_thread.start()
|
||||
|
||||
def _was_beam_okay(self):
|
||||
self._stop_beam_check_event.set()
|
||||
self.beam_check_thread.join()
|
||||
return self._beam_is_okay
|
||||
|
||||
def _print_beamline_checks(self):
|
||||
for msg in self._check_msgs:
|
||||
logger.warning(msg)
|
||||
|
||||
def _wait_for_beamline_checks(self):
|
||||
self._print_beamline_checks()
|
||||
try:
|
||||
msg = bec.logbook.LogbookMessage()
|
||||
msg.add_text(
|
||||
"<p><mark class='pen-red'><strong>Beamline checks failed at"
|
||||
f" {str(datetime.datetime.now())}: {''.join(self._check_msgs)}</strong></mark></p>"
|
||||
).add_tag(["BEC", "beam_check"])
|
||||
bec.logbook.send_logbook_message(msg)
|
||||
except Exception:
|
||||
logger.warning("Failed to send update to SciLog.")
|
||||
|
||||
while True:
|
||||
self._beam_is_okay = True
|
||||
self._check_msgs = self._run_beamline_checks()
|
||||
if self._beam_is_okay:
|
||||
break
|
||||
self._print_beamline_checks()
|
||||
time.sleep(1)
|
||||
|
||||
try:
|
||||
msg = bec.logbook.LogbookMessage()
|
||||
msg.add_text(
|
||||
"<p><mark class='pen-red'><strong>Operation resumed at"
|
||||
f" {str(datetime.datetime.now())}.</strong></mark></p>"
|
||||
).add_tag(["BEC", "beam_check"])
|
||||
bec.logbook.send_logbook_message(msg)
|
||||
except Exception:
|
||||
logger.warning("Failed to send update to SciLog.")
|
||||
@@ -1 +0,0 @@
|
||||
from .flomni import Flomni
|
||||
@@ -1,351 +0,0 @@
|
||||
corr_elements = 175
|
||||
corr_angle[0] = 0.100000
|
||||
corr_angle[1] = 1.001000
|
||||
corr_angle[2] = 1.902000
|
||||
corr_angle[3] = 2.798000
|
||||
corr_angle[4] = 7.305000
|
||||
corr_angle[5] = 8.204000
|
||||
corr_angle[6] = 9.104000
|
||||
corr_angle[7] = 10.005000
|
||||
corr_angle[8] = 14.504000
|
||||
corr_angle[9] = 15.404000
|
||||
corr_angle[10] = 16.304000
|
||||
corr_angle[11] = 17.204000
|
||||
corr_angle[12] = 21.704000
|
||||
corr_angle[13] = 22.604000
|
||||
corr_angle[14] = 23.504000
|
||||
corr_angle[15] = 24.404000
|
||||
corr_angle[16] = 28.904000
|
||||
corr_angle[17] = 29.804000
|
||||
corr_angle[18] = 30.704000
|
||||
corr_angle[19] = 31.604000
|
||||
corr_angle[20] = 36.104000
|
||||
corr_angle[21] = 37.004000
|
||||
corr_angle[22] = 37.904000
|
||||
corr_angle[23] = 38.804000
|
||||
corr_angle[24] = 43.305000
|
||||
corr_angle[25] = 44.205000
|
||||
corr_angle[26] = 45.104000
|
||||
corr_angle[27] = 46.005000
|
||||
corr_angle[28] = 50.504000
|
||||
corr_angle[29] = 51.404000
|
||||
corr_angle[30] = 52.305000
|
||||
corr_angle[31] = 53.205000
|
||||
corr_angle[32] = 57.705000
|
||||
corr_angle[33] = 58.605000
|
||||
corr_angle[34] = 59.505000
|
||||
corr_angle[35] = 60.405000
|
||||
corr_angle[36] = 64.904000
|
||||
corr_angle[37] = 65.804000
|
||||
corr_angle[38] = 66.704000
|
||||
corr_angle[39] = 67.604000
|
||||
corr_angle[40] = 72.104000
|
||||
corr_angle[41] = 73.004000
|
||||
corr_angle[42] = 73.904000
|
||||
corr_angle[43] = 74.804000
|
||||
corr_angle[44] = 79.304000
|
||||
corr_angle[45] = 80.204000
|
||||
corr_angle[46] = 81.104000
|
||||
corr_angle[47] = 82.005000
|
||||
corr_angle[48] = 86.505000
|
||||
corr_angle[49] = 87.404000
|
||||
corr_angle[50] = 88.304000
|
||||
corr_angle[51] = 89.205000
|
||||
corr_angle[52] = 93.704000
|
||||
corr_angle[53] = 94.604000
|
||||
corr_angle[54] = 95.505000
|
||||
corr_angle[55] = 96.404000
|
||||
corr_angle[56] = 100.904000
|
||||
corr_angle[57] = 101.804000
|
||||
corr_angle[58] = 102.704000
|
||||
corr_angle[59] = 103.604000
|
||||
corr_angle[60] = 108.104000
|
||||
corr_angle[61] = 109.004000
|
||||
corr_angle[62] = 109.904000
|
||||
corr_angle[63] = 110.804000
|
||||
corr_angle[64] = 115.304000
|
||||
corr_angle[65] = 116.204000
|
||||
corr_angle[66] = 117.104000
|
||||
corr_angle[67] = 118.004000
|
||||
corr_angle[68] = 122.504000
|
||||
corr_angle[69] = 123.404000
|
||||
corr_angle[70] = 124.304000
|
||||
corr_angle[71] = 125.204000
|
||||
corr_angle[72] = 129.704000
|
||||
corr_angle[73] = 130.604000
|
||||
corr_angle[74] = 131.504000
|
||||
corr_angle[75] = 132.404000
|
||||
corr_angle[76] = 136.904000
|
||||
corr_angle[77] = 137.804000
|
||||
corr_angle[78] = 138.701000
|
||||
corr_angle[79] = 139.604000
|
||||
corr_angle[80] = 144.104000
|
||||
corr_angle[81] = 145.004000
|
||||
corr_angle[82] = 145.904000
|
||||
corr_angle[83] = 146.804000
|
||||
corr_angle[84] = 151.304000
|
||||
corr_angle[85] = 152.204000
|
||||
corr_angle[86] = 153.104000
|
||||
corr_angle[87] = 154.004000
|
||||
corr_angle[88] = 158.504000
|
||||
corr_angle[89] = 159.404000
|
||||
corr_angle[90] = 160.304000
|
||||
corr_angle[91] = 161.204000
|
||||
corr_angle[92] = 165.704000
|
||||
corr_angle[93] = 166.604000
|
||||
corr_angle[94] = 167.504000
|
||||
corr_angle[95] = 168.404000
|
||||
corr_angle[96] = 172.904000
|
||||
corr_angle[97] = 173.805000
|
||||
corr_angle[98] = 174.704000
|
||||
corr_angle[99] = 180.104000
|
||||
corr_angle[100] = 183.704000
|
||||
corr_angle[101] = 184.603000
|
||||
corr_angle[102] = 185.504000
|
||||
corr_angle[103] = 190.904000
|
||||
corr_angle[104] = 191.805000
|
||||
corr_angle[105] = 192.704000
|
||||
corr_angle[106] = 198.104000
|
||||
corr_angle[107] = 199.004000
|
||||
corr_angle[108] = 199.904000
|
||||
corr_angle[109] = 205.304000
|
||||
corr_angle[110] = 206.204000
|
||||
corr_angle[111] = 207.104000
|
||||
corr_angle[112] = 212.504000
|
||||
corr_angle[113] = 213.404000
|
||||
corr_angle[114] = 214.304000
|
||||
corr_angle[115] = 219.704000
|
||||
corr_angle[116] = 220.604000
|
||||
corr_angle[117] = 221.504000
|
||||
corr_angle[118] = 226.904000
|
||||
corr_angle[119] = 227.804000
|
||||
corr_angle[120] = 228.704000
|
||||
corr_angle[121] = 234.104000
|
||||
corr_angle[122] = 235.004000
|
||||
corr_angle[123] = 235.904000
|
||||
corr_angle[124] = 241.304000
|
||||
corr_angle[125] = 242.204000
|
||||
corr_angle[126] = 243.104000
|
||||
corr_angle[127] = 248.504000
|
||||
corr_angle[128] = 249.404000
|
||||
corr_angle[129] = 250.304000
|
||||
corr_angle[130] = 255.704000
|
||||
corr_angle[131] = 256.604000
|
||||
corr_angle[132] = 257.504000
|
||||
corr_angle[133] = 262.904000
|
||||
corr_angle[134] = 263.804000
|
||||
corr_angle[135] = 264.704000
|
||||
corr_angle[136] = 270.104000
|
||||
corr_angle[137] = 271.004000
|
||||
corr_angle[138] = 271.904000
|
||||
corr_angle[139] = 277.304000
|
||||
corr_angle[140] = 278.205000
|
||||
corr_angle[141] = 279.104000
|
||||
corr_angle[142] = 284.504000
|
||||
corr_angle[143] = 285.405000
|
||||
corr_angle[144] = 286.304000
|
||||
corr_angle[145] = 291.703000
|
||||
corr_angle[146] = 292.604000
|
||||
corr_angle[147] = 293.504000
|
||||
corr_angle[148] = 298.904000
|
||||
corr_angle[149] = 299.804000
|
||||
corr_angle[150] = 300.704000
|
||||
corr_angle[151] = 306.104000
|
||||
corr_angle[152] = 307.004000
|
||||
corr_angle[153] = 307.904000
|
||||
corr_angle[154] = 313.304000
|
||||
corr_angle[155] = 314.204000
|
||||
corr_angle[156] = 315.104000
|
||||
corr_angle[157] = 320.504000
|
||||
corr_angle[158] = 321.404000
|
||||
corr_angle[159] = 322.304000
|
||||
corr_angle[160] = 327.704000
|
||||
corr_angle[161] = 328.605000
|
||||
corr_angle[162] = 329.504000
|
||||
corr_angle[163] = 334.904000
|
||||
corr_angle[164] = 335.804000
|
||||
corr_angle[165] = 336.705000
|
||||
corr_angle[166] = 342.104000
|
||||
corr_angle[167] = 343.004000
|
||||
corr_angle[168] = 343.904000
|
||||
corr_angle[169] = 349.304000
|
||||
corr_angle[170] = 350.204000
|
||||
corr_angle[171] = 351.104000
|
||||
corr_angle[172] = 356.504000
|
||||
corr_angle[173] = 357.404000
|
||||
corr_angle[174] = 358.304000
|
||||
corr_pos[0] = 0.012330
|
||||
corr_pos[1] = 0.024870
|
||||
corr_pos[2] = 0.037262
|
||||
corr_pos[3] = 0.049438
|
||||
corr_pos[4] = 0.108462
|
||||
corr_pos[5] = 0.119791
|
||||
corr_pos[6] = 0.130986
|
||||
corr_pos[7] = 0.142044
|
||||
corr_pos[8] = 0.195045
|
||||
corr_pos[9] = 0.205834
|
||||
corr_pos[10] = 0.216589
|
||||
corr_pos[11] = 0.226402
|
||||
corr_pos[12] = 0.271931
|
||||
corr_pos[13] = 0.281684
|
||||
corr_pos[14] = 0.290769
|
||||
corr_pos[15] = 0.299392
|
||||
corr_pos[16] = 0.337986
|
||||
corr_pos[17] = 0.345178
|
||||
corr_pos[18] = 0.352253
|
||||
corr_pos[19] = 0.358528
|
||||
corr_pos[20] = 0.379520
|
||||
corr_pos[21] = 0.382947
|
||||
corr_pos[22] = 0.386110
|
||||
corr_pos[23] = 0.388887
|
||||
corr_pos[24] = 0.395645
|
||||
corr_pos[25] = 0.396154
|
||||
corr_pos[26] = 0.396679
|
||||
corr_pos[27] = 0.396367
|
||||
corr_pos[28] = 0.392400
|
||||
corr_pos[29] = 0.392530
|
||||
corr_pos[30] = 0.391826
|
||||
corr_pos[31] = 0.391325
|
||||
corr_pos[32] = 0.379188
|
||||
corr_pos[33] = 0.376449
|
||||
corr_pos[34] = 0.373195
|
||||
corr_pos[35] = 0.369588
|
||||
corr_pos[36] = 0.343021
|
||||
corr_pos[37] = 0.336754
|
||||
corr_pos[38] = 0.330310
|
||||
corr_pos[39] = 0.323447
|
||||
corr_pos[40] = 0.281171
|
||||
corr_pos[41] = 0.272735
|
||||
corr_pos[42] = 0.263888
|
||||
corr_pos[43] = 0.254469
|
||||
corr_pos[44] = 0.203024
|
||||
corr_pos[45] = 0.192980
|
||||
corr_pos[46] = 0.182359
|
||||
corr_pos[47] = 0.170780
|
||||
corr_pos[48] = 0.111580
|
||||
corr_pos[49] = 0.101222
|
||||
corr_pos[50] = 0.090051
|
||||
corr_pos[51] = 0.077918
|
||||
corr_pos[52] = 0.015225
|
||||
corr_pos[53] = 0.003876
|
||||
corr_pos[54] = -0.007756
|
||||
corr_pos[55] = -0.020383
|
||||
corr_pos[56] = -0.084910
|
||||
corr_pos[57] = -0.096848
|
||||
corr_pos[58] = -0.108732
|
||||
corr_pos[59] = -0.121432
|
||||
corr_pos[60] = -0.184349
|
||||
corr_pos[61] = -0.195904
|
||||
corr_pos[62] = -0.207113
|
||||
corr_pos[63] = -0.219319
|
||||
corr_pos[64] = -0.274799
|
||||
corr_pos[65] = -0.284942
|
||||
corr_pos[66] = -0.294809
|
||||
corr_pos[67] = -0.305437
|
||||
corr_pos[68] = -0.352114
|
||||
corr_pos[69] = -0.359689
|
||||
corr_pos[70] = -0.367451
|
||||
corr_pos[71] = -0.375629
|
||||
corr_pos[72] = -0.404347
|
||||
corr_pos[73] = -0.407683
|
||||
corr_pos[74] = -0.410857
|
||||
corr_pos[75] = -0.414904
|
||||
corr_pos[76] = -0.424625
|
||||
corr_pos[77] = -0.424357
|
||||
corr_pos[78] = -0.424411
|
||||
corr_pos[79] = -0.424615
|
||||
corr_pos[80] = -0.421392
|
||||
corr_pos[81] = -0.419977
|
||||
corr_pos[82] = -0.417860
|
||||
corr_pos[83] = -0.416400
|
||||
corr_pos[84] = -0.398108
|
||||
corr_pos[85] = -0.392613
|
||||
corr_pos[86] = -0.386455
|
||||
corr_pos[87] = -0.380338
|
||||
corr_pos[88] = -0.341288
|
||||
corr_pos[89] = -0.332298
|
||||
corr_pos[90] = -0.322767
|
||||
corr_pos[91] = -0.311630
|
||||
corr_pos[92] = -0.256798
|
||||
corr_pos[93] = -0.244808
|
||||
corr_pos[94] = -0.232932
|
||||
corr_pos[95] = -0.219785
|
||||
corr_pos[96] = -0.158685
|
||||
corr_pos[97] = -0.146198
|
||||
corr_pos[98] = -0.130743
|
||||
corr_pos[99] = -0.054066
|
||||
corr_pos[100] = -0.001498
|
||||
corr_pos[101] = 0.012010
|
||||
corr_pos[102] = 0.025195
|
||||
corr_pos[103] = 0.094982
|
||||
corr_pos[104] = 0.109235
|
||||
corr_pos[105] = 0.120813
|
||||
corr_pos[106] = 0.179893
|
||||
corr_pos[107] = 0.192147
|
||||
corr_pos[108] = 0.201902
|
||||
corr_pos[109] = 0.245092
|
||||
corr_pos[110] = 0.250501
|
||||
corr_pos[111] = 0.255536
|
||||
corr_pos[112] = 0.280598
|
||||
corr_pos[113] = 0.280673
|
||||
corr_pos[114] = 0.282529
|
||||
corr_pos[115] = 0.293286
|
||||
corr_pos[116] = 0.292713
|
||||
corr_pos[117] = 0.291123
|
||||
corr_pos[118] = 0.288721
|
||||
corr_pos[119] = 0.288260
|
||||
corr_pos[120] = 0.286480
|
||||
corr_pos[121] = 0.271630
|
||||
corr_pos[122] = 0.268004
|
||||
corr_pos[123] = 0.265418
|
||||
corr_pos[124] = 0.239187
|
||||
corr_pos[125] = 0.233224
|
||||
corr_pos[126] = 0.226652
|
||||
corr_pos[127] = 0.189034
|
||||
corr_pos[128] = 0.180302
|
||||
corr_pos[129] = 0.170931
|
||||
corr_pos[130] = 0.125760
|
||||
corr_pos[131] = 0.116433
|
||||
corr_pos[132] = 0.106845
|
||||
corr_pos[133] = 0.057551
|
||||
corr_pos[134] = 0.048531
|
||||
corr_pos[135] = 0.038276
|
||||
corr_pos[136] = -0.012292
|
||||
corr_pos[137] = -0.021223
|
||||
corr_pos[138] = -0.030046
|
||||
corr_pos[139] = -0.077647
|
||||
corr_pos[140] = -0.085863
|
||||
corr_pos[141] = -0.093816
|
||||
corr_pos[142] = -0.138532
|
||||
corr_pos[143] = -0.145584
|
||||
corr_pos[144] = -0.152699
|
||||
corr_pos[145] = -0.192594
|
||||
corr_pos[146] = -0.200980
|
||||
corr_pos[147] = -0.208816
|
||||
corr_pos[148] = -0.241983
|
||||
corr_pos[149] = -0.248319
|
||||
corr_pos[150] = -0.253789
|
||||
corr_pos[151] = -0.276869
|
||||
corr_pos[152] = -0.279240
|
||||
corr_pos[153] = -0.281538
|
||||
corr_pos[154] = -0.294317
|
||||
corr_pos[155] = -0.295586
|
||||
corr_pos[156] = -0.296029
|
||||
corr_pos[157] = -0.297443
|
||||
corr_pos[158] = -0.297185
|
||||
corr_pos[159] = -0.295946
|
||||
corr_pos[160] = -0.284463
|
||||
corr_pos[161] = -0.282598
|
||||
corr_pos[162] = -0.281260
|
||||
corr_pos[163] = -0.256509
|
||||
corr_pos[164] = -0.250326
|
||||
corr_pos[165] = -0.244372
|
||||
corr_pos[166] = -0.204043
|
||||
corr_pos[167] = -0.196147
|
||||
corr_pos[168] = -0.187928
|
||||
corr_pos[169] = -0.131831
|
||||
corr_pos[170] = -0.121351
|
||||
corr_pos[171] = -0.110548
|
||||
corr_pos[172] = -0.038951
|
||||
corr_pos[173] = -0.025887
|
||||
corr_pos[174] = -0.012501
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,177 +0,0 @@
|
||||
import time
|
||||
|
||||
from rich import box
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
|
||||
from csaxs_bec.bec_ipython_client.plugins.cSAXS import epics_put, fshclose
|
||||
|
||||
|
||||
class FlomniOpticsMixin:
|
||||
@staticmethod
|
||||
def _get_user_param_safe(device, var):
|
||||
param = dev[device].user_parameter
|
||||
if not param or param.get(var) is None:
|
||||
raise ValueError(f"Device {device} has no user parameter definition for {var}.")
|
||||
return param.get(var)
|
||||
|
||||
def feye_out(self):
|
||||
fshclose()
|
||||
self.foptics_in()
|
||||
feyex_out = self._get_user_param_safe("feyex", "out")
|
||||
umv(dev.feyex, feyex_out)
|
||||
|
||||
epics_put("XOMNYI-XEYE-ACQ:0", 2)
|
||||
# move rotation stage to zero to avoid problems with wires
|
||||
umv(dev.fsamroy, 0)
|
||||
# umv(dev.fttrx1, 9.2)
|
||||
|
||||
def feye_in(self):
|
||||
bec.queue.next_dataset_number += 1
|
||||
# umv(dev.fttrx1, -17)
|
||||
|
||||
feyex_in = self._get_user_param_safe("feyex", "in")
|
||||
feyey_in = self._get_user_param_safe("feyey", "in")
|
||||
umv(dev.feyex, feyex_in, dev.feyey, feyey_in)
|
||||
self.align.update_frame()
|
||||
|
||||
def _ffzp_in(self):
|
||||
foptx_in = self._get_user_param_safe("foptx", "in")
|
||||
fopty_in = self._get_user_param_safe("fopty", "in")
|
||||
umv(dev.foptx, foptx_in)
|
||||
umv(
|
||||
dev.fopty, fopty_in
|
||||
) # for 7.2567 keV and 150 mu, 60 nm fzp, loptz 83.6000 for propagation 1.4 mm
|
||||
|
||||
def ffzp_in(self):
|
||||
"""
|
||||
move in the flomni zone plate.
|
||||
This will disable rt feedback, move the FZP and re-enabled the feedback.
|
||||
"""
|
||||
if "rtx" in dev and dev.rtx.enabled:
|
||||
dev.rtx.controller.feedback_disable()
|
||||
|
||||
self._ffzp_in()
|
||||
|
||||
if "rtx" in dev and dev.rtx.enabled:
|
||||
dev.rtx.controller.feedback_enable_with_reset()
|
||||
|
||||
def foptics_in(self):
|
||||
"""
|
||||
Move in the flomni optics, including the FZP and the OSA.
|
||||
"""
|
||||
self.ffzp_in()
|
||||
self.fosa_in()
|
||||
|
||||
def foptics_out(self):
|
||||
"""Move out the flomni optics"""
|
||||
if "rtx" in dev and dev.rtx.enabled:
|
||||
dev.rtx.controller.feedback_disable()
|
||||
|
||||
self.fosa_out()
|
||||
fopty_out = self._get_user_param_safe("fopty", "out")
|
||||
umv(dev.fopty, fopty_out)
|
||||
|
||||
if "rtx" in dev and dev.rtx.enabled:
|
||||
time.sleep(1)
|
||||
dev.rtx.controller.feedback_enable_with_reset()
|
||||
|
||||
def fosa_in(self):
|
||||
# 6.2 keV, 170 um FZP
|
||||
# umv(dev.losax, -1.4450000, dev.losay, -0.1800)
|
||||
# umv(dev.losaz, -1)
|
||||
# 6.7, 170
|
||||
# umv(dev.losax, -1.4850, dev.losay, -0.1930)
|
||||
# umv(dev.losaz, 1.0000)
|
||||
# 7.2, 150
|
||||
fosax_in = self._get_user_param_safe("fosax", "in")
|
||||
fosay_in = self._get_user_param_safe("fosay", "in")
|
||||
fosaz_in = self._get_user_param_safe("fosaz", "in")
|
||||
dev.fosax.limits = [fosax_in - 0.1, fosax_in + 0.1]
|
||||
dev.fosay.limits = [fosay_in - 0.1, fosay_in + 0.1]
|
||||
dev.fosaz.limits = [fosaz_in - 0.1, fosaz_in + 0.1]
|
||||
umv(dev.fosax, fosax_in, dev.fosay, fosay_in)
|
||||
umv(dev.fosaz, fosaz_in)
|
||||
|
||||
# 11 kev
|
||||
# umv(dev.losax, -1.161000, dev.losay, -0.196)
|
||||
# umv(dev.losaz, 1.0000)
|
||||
|
||||
def fosa_out(self):
|
||||
self.ensure_fheater_up()
|
||||
curtain_is_triggered = dev.foptz.controller.fosaz_light_curtain_is_triggered()
|
||||
if not curtain_is_triggered:
|
||||
fosaz_out = self._get_user_param_safe("fosaz", "out")
|
||||
dev.fosaz.limits = [fosaz_out - 0.1, fosaz_out + 0.1]
|
||||
umv(dev.fosaz, fosaz_out)
|
||||
fosax_out = self._get_user_param_safe("fosax", "out")
|
||||
dev.fosax.limits = [fosax_out - 0.1, fosax_out + 0.1]
|
||||
umv(dev.fosax, fosax_out)
|
||||
|
||||
def ffzp_info(self, mokev_val=-1):
|
||||
|
||||
if mokev_val == -1:
|
||||
try:
|
||||
mokev_val = dev.mokev.readback.get()
|
||||
except:
|
||||
print(
|
||||
"Device mokev does not exist. You can specify the energy in keV as an argument instead."
|
||||
)
|
||||
return
|
||||
foptz_val = dev.foptz.readback.get()
|
||||
distance = -foptz_val + 43.15 + 36.7
|
||||
print(f"\nThe sample is in a distance of \033[1m{distance:.1f} mm\033[0m from the FZP.\n")
|
||||
print(f"At the current energy of {mokev_val:.4f} keV we have following options:\n")
|
||||
|
||||
diameters = [80e-6, 100e-6, 120e-6, 150e-6, 170e-6, 200e-6, 220e-6, 250e-6]
|
||||
|
||||
console = Console()
|
||||
table = Table(title="Outermost zone width \033[1m60 nm\033[0m", box=box.SQUARE)
|
||||
table.add_column("Diameter", justify="center")
|
||||
table.add_column("Focal distance", justify="center")
|
||||
table.add_column("Current beam size", justify="center")
|
||||
|
||||
wavelength = 1.2398e-9 / mokev_val
|
||||
|
||||
for diameter in diameters:
|
||||
outermost_zonewidth = 60e-9
|
||||
focal_distance = diameter * outermost_zonewidth / wavelength * 1000
|
||||
beam_size = -diameter / (focal_distance * 1000) * (focal_distance - distance) * 1e9
|
||||
table.add_row(
|
||||
f"{diameter*1e6:.2f} microns",
|
||||
f"{focal_distance:.2f} mm",
|
||||
f"{beam_size:.2f} microns",
|
||||
)
|
||||
|
||||
console.print(table)
|
||||
|
||||
diameters = [150e-6, 250e-6]
|
||||
|
||||
console = Console()
|
||||
table = Table(title="Outermost zone width \033[1m30 nm\033[0m", box=box.SQUARE)
|
||||
table.add_column("Diameter", justify="center")
|
||||
table.add_column("Focal distance", justify="center")
|
||||
table.add_column("Current beam size", justify="center")
|
||||
|
||||
wavelength = 1.2398e-9 / mokev_val
|
||||
|
||||
for diameter in diameters:
|
||||
outermost_zonewidth = 30e-9
|
||||
focal_distance = diameter * outermost_zonewidth / wavelength * 1000
|
||||
beam_size = -diameter / (focal_distance * 1000) * (focal_distance - distance) * 1e9
|
||||
table.add_row(
|
||||
f"{diameter*1e6:.2f} microns",
|
||||
f"{focal_distance:.2f} mm",
|
||||
f"{beam_size:.2f} microns",
|
||||
)
|
||||
|
||||
console.print(table)
|
||||
|
||||
fosaz_val = dev.fosaz.readback.get()
|
||||
|
||||
print("\nOSA Information:")
|
||||
print(f" Current fosaz {fosaz_val:.1f}")
|
||||
print(
|
||||
f" The OSA will collide with a normal OMNY pin at fosaz \033[1m{(33-fosaz_val):.1f}\033[0m"
|
||||
)
|
||||
print(f" Remaining space: \033[1m{-fosaz_val+(33-foptz_val):.1f}\033[0m")
|
||||
@@ -1,244 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import builtins
|
||||
import os
|
||||
import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from bec_lib import bec_logger
|
||||
|
||||
from csaxs_bec.bec_ipython_client.plugins.cSAXS import epics_get, epics_put, fshopen
|
||||
|
||||
logger = bec_logger.logger
|
||||
# import builtins to avoid linter errors
|
||||
bec = builtins.__dict__.get("bec")
|
||||
dev = builtins.__dict__.get("dev")
|
||||
umv = builtins.__dict__.get("umv")
|
||||
umvr = builtins.__dict__.get("umvr")
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bec_ipython_client.plugins.flomni import Flomni
|
||||
|
||||
|
||||
class XrayEyeAlign:
|
||||
# pixel calibration, multiply to get mm
|
||||
PIXEL_CALIBRATION = 0.1 / 113 # .2 with binning
|
||||
|
||||
def __init__(self, client, flomni: Flomni) -> None:
|
||||
self.client = client
|
||||
self.flomni = flomni
|
||||
self.device_manager = client.device_manager
|
||||
self.scans = client.scans
|
||||
self.alignment_values = {}
|
||||
self.flomni.reset_correction()
|
||||
self.flomni.reset_tomo_alignment_fit()
|
||||
|
||||
def _reset_init_values(self):
|
||||
self.shift_xy = [0, 0]
|
||||
self._xray_fov_xy = [0, 0]
|
||||
|
||||
def save_frame(self):
|
||||
epics_put("XOMNYI-XEYE-SAVFRAME:0", 1)
|
||||
|
||||
def update_frame(self):
|
||||
epics_put("XOMNYI-XEYE-ACQDONE:0", 0)
|
||||
# start live
|
||||
epics_put("XOMNYI-XEYE-ACQ:0", 1)
|
||||
# wait for start live
|
||||
while epics_get("XOMNYI-XEYE-ACQDONE:0") == 0:
|
||||
time.sleep(0.5)
|
||||
print("waiting for live view to start...")
|
||||
fshopen()
|
||||
|
||||
epics_put("XOMNYI-XEYE-ACQDONE:0", 0)
|
||||
|
||||
while epics_get("XOMNYI-XEYE-ACQDONE:0") == 0:
|
||||
print("waiting for new frame...")
|
||||
time.sleep(0.5)
|
||||
|
||||
time.sleep(0.5)
|
||||
# stop live view
|
||||
epics_put("XOMNYI-XEYE-ACQ:0", 0)
|
||||
time.sleep(1)
|
||||
# fshclose
|
||||
print("got new frame")
|
||||
|
||||
def tomo_rotate(self, val: float):
|
||||
# pylint: disable=undefined-variable
|
||||
umv(self.device_manager.devices.fsamroy, val)
|
||||
|
||||
def get_tomo_angle(self):
|
||||
return self.device_manager.devices.fsamroy.readback.get()
|
||||
|
||||
def update_fov(self, k: int):
|
||||
self._xray_fov_xy[0] = max(epics_get(f"XOMNYI-XEYE-XWIDTH_X:{k}"), self._xray_fov_xy[0])
|
||||
self._xray_fov_xy[1] = max(0, self._xray_fov_xy[0])
|
||||
|
||||
@property
|
||||
def movement_buttons_enabled(self):
|
||||
return [epics_get("XOMNYI-XEYE-ENAMVX:0"), epics_get("XOMNYI-XEYE-ENAMVY:0")]
|
||||
|
||||
@movement_buttons_enabled.setter
|
||||
def movement_buttons_enabled(self, enabled: bool):
|
||||
enabled = int(enabled)
|
||||
epics_put("XOMNYI-XEYE-ENAMVX:0", enabled)
|
||||
epics_put("XOMNYI-XEYE-ENAMVY:0", enabled)
|
||||
|
||||
def send_message(self, msg: str):
|
||||
epics_put("XOMNYI-XEYE-MESSAGE:0.DESC", msg)
|
||||
|
||||
def align(self):
|
||||
# reset shift xy and fov params
|
||||
self._reset_init_values()
|
||||
|
||||
self.flomni.lights_off()
|
||||
|
||||
self.tomo_rotate(0)
|
||||
epics_put("XOMNYI-XEYE-ANGLE:0", 0)
|
||||
|
||||
self.flomni.feye_in()
|
||||
|
||||
self.flomni.laser_tracker_on()
|
||||
|
||||
self.flomni.feedback_enable_with_reset()
|
||||
|
||||
# disable movement buttons
|
||||
self.movement_buttons_enabled = False
|
||||
|
||||
sample_name = self.flomni.sample_get_name(0)
|
||||
epics_put("XOMNYI-XEYE-SAMPLENAME:0.DESC", sample_name)
|
||||
|
||||
# this makes sure we are in a defined state
|
||||
self.flomni.feedback_disable()
|
||||
|
||||
epics_put("XOMNYI-XEYE-PIXELSIZE:0", self.PIXEL_CALIBRATION)
|
||||
|
||||
self.flomni.fosa_out()
|
||||
|
||||
fsamx_in = self.flomni._get_user_param_safe("fsamx", "in")
|
||||
umv(dev.fsamx, fsamx_in - 0.25)
|
||||
|
||||
self.flomni.ffzp_in()
|
||||
self.update_frame()
|
||||
|
||||
# enable submit buttons
|
||||
self.movement_buttons_enabled = False
|
||||
epics_put("XOMNYI-XEYE-SUBMIT:0", 0)
|
||||
epics_put("XOMNYI-XEYE-STEP:0", 0)
|
||||
self.send_message("Submit center value of FZP.")
|
||||
|
||||
k = 0
|
||||
while True:
|
||||
if epics_get("XOMNYI-XEYE-SUBMIT:0") == 1:
|
||||
val_x = epics_get(f"XOMNYI-XEYE-XVAL_X:{k}") / 2 * self.PIXEL_CALIBRATION # in mm
|
||||
self.alignment_values[k] = val_x
|
||||
print(f"Clicked position {k}: x {self.alignment_values[k]}")
|
||||
rtx_position = dev.rtx.readback.get() / 1000
|
||||
print(f"Current rtx position {rtx_position}")
|
||||
self.alignment_values[k] -= rtx_position
|
||||
print(f"Corrected position {k}: x {self.alignment_values[k]}")
|
||||
|
||||
if k == 0: # received center value of FZP
|
||||
self.send_message("please wait ...")
|
||||
self.movement_buttons_enabled = False
|
||||
epics_put("XOMNYI-XEYE-SUBMIT:0", -1) # disable submit button
|
||||
|
||||
self.flomni.feedback_disable()
|
||||
fsamx_in = self.flomni._get_user_param_safe("fsamx", "in")
|
||||
umv(dev.fsamx, fsamx_in)
|
||||
|
||||
self.flomni.foptics_out()
|
||||
|
||||
self.flomni.feedback_disable()
|
||||
umv(dev.fsamx, fsamx_in - 0.25)
|
||||
|
||||
self.update_frame()
|
||||
epics_put("XOMNYI-XEYE-RECBG:0", 1)
|
||||
while epics_get("XOMNYI-XEYE-RECBG:0") == 1:
|
||||
time.sleep(0.5)
|
||||
print("waiting for background frame...")
|
||||
|
||||
umv(dev.fsamx, fsamx_in)
|
||||
time.sleep(0.5)
|
||||
self.flomni.feedback_enable_with_reset()
|
||||
|
||||
self.update_frame()
|
||||
self.send_message("Adjust sample height and submit center")
|
||||
epics_put("XOMNYI-XEYE-SUBMIT:0", 0)
|
||||
self.movement_buttons_enabled = True
|
||||
|
||||
elif 1 <= k < 5: # received sample center value at samroy 0 ... 315
|
||||
self.send_message("please wait ...")
|
||||
epics_put("XOMNYI-XEYE-SUBMIT:0", -1)
|
||||
self.movement_buttons_enabled = False
|
||||
|
||||
umv(dev.rtx, 0)
|
||||
self.tomo_rotate(k * 45)
|
||||
epics_put("XOMNYI-XEYE-ANGLE:0", self.get_tomo_angle())
|
||||
self.update_frame()
|
||||
self.send_message("Submit sample center")
|
||||
epics_put("XOMNYI-XEYE-SUBMIT:0", 0)
|
||||
epics_put("XOMNYI-XEYE-ENAMVX:0", 1)
|
||||
self.update_fov(k)
|
||||
|
||||
elif k == 5: # received sample center value at samroy 270 and done
|
||||
self.send_message("done...")
|
||||
epics_put("XOMNYI-XEYE-SUBMIT:0", -1) # disable submit button
|
||||
self.movement_buttons_enabled = False
|
||||
self.update_fov(k)
|
||||
break
|
||||
|
||||
k += 1
|
||||
epics_put("XOMNYI-XEYE-STEP:0", k)
|
||||
|
||||
_xrayeyalignmvx = epics_get("XOMNYI-XEYE-MVX:0")
|
||||
if _xrayeyalignmvx != 0:
|
||||
umvr(dev.rtx, _xrayeyalignmvx)
|
||||
print(f"Current rtx position {dev.rtx.readback.get() / 1000}")
|
||||
epics_put("XOMNYI-XEYE-MVX:0", 0)
|
||||
if k > 0:
|
||||
epics_put(f"XOMNYI-XEYE-STAGEPOSX:{k}", dev.rtx.readback.get() / 1000)
|
||||
time.sleep(3)
|
||||
self.update_frame()
|
||||
|
||||
if k < 2:
|
||||
# allow movements, store movements to calculate center
|
||||
_xrayeyalignmvy = epics_get("XOMNYI-XEYE-MVY:0")
|
||||
if _xrayeyalignmvy != 0:
|
||||
self.flomni.feedback_disable()
|
||||
umvr(dev.fsamy, _xrayeyalignmvy / 1000)
|
||||
time.sleep(2)
|
||||
epics_put("XOMNYI-XEYE-MVY:0", 0)
|
||||
self.flomni.feedback_enable_with_reset()
|
||||
self.update_frame()
|
||||
time.sleep(0.2)
|
||||
|
||||
self.write_output()
|
||||
fovx = self._xray_fov_xy[0] * self.PIXEL_CALIBRATION * 1000 / 2
|
||||
fovy = self._xray_fov_xy[1] * self.PIXEL_CALIBRATION * 1000 / 2
|
||||
|
||||
self.tomo_rotate(0)
|
||||
|
||||
umv(dev.rtx, 0)
|
||||
|
||||
# free camera
|
||||
epics_put("XOMNYI-XEYE-ACQ:0", 2)
|
||||
|
||||
print(
|
||||
f"The largest field of view from the xrayeyealign was \nfovx = {fovx:.0f} microns, fovy"
|
||||
f" = {fovy:.0f} microns"
|
||||
)
|
||||
print("Use the matlab routine to FIT the current alignment...")
|
||||
|
||||
print("Then LOAD ALIGNMENT PARAMETERS by running flomni.read_alignment_offset()\n")
|
||||
|
||||
def write_output(self):
|
||||
file = os.path.expanduser("~/Data10/specES1/internal/xrayeye_alignmentvalues")
|
||||
if not os.path.exists(file):
|
||||
os.makedirs(os.path.dirname(file), exist_ok=True)
|
||||
with open(file, "w") as alignment_values_file:
|
||||
alignment_values_file.write("angle\thorizontal\n")
|
||||
for k in range(1, 6):
|
||||
fovx_offset = self.alignment_values[0] - self.alignment_values[k]
|
||||
print(f"Writing to file new alignment: number {k}, value x {fovx_offset}")
|
||||
alignment_values_file.write(f"{(k-1)*45}\t{fovx_offset*1000}\n")
|
||||
@@ -1 +0,0 @@
|
||||
from .omny import OMNY
|
||||
@@ -1,715 +0,0 @@
|
||||
corr_elements = 357
|
||||
corr_angle[0] = 0.097400
|
||||
corr_angle[1] = 0.603500
|
||||
corr_angle[2] = 1.134200
|
||||
corr_angle[3] = 1.625000
|
||||
corr_angle[4] = 2.162200
|
||||
corr_angle[5] = 2.700100
|
||||
corr_angle[6] = 3.191600
|
||||
corr_angle[7] = 3.714300
|
||||
corr_angle[8] = 4.223200
|
||||
corr_angle[9] = 4.730900
|
||||
corr_angle[10] = 5.253300
|
||||
corr_angle[11] = 5.743300
|
||||
corr_angle[12] = 6.279200
|
||||
corr_angle[13] = 6.782900
|
||||
corr_angle[14] = 7.301200
|
||||
corr_angle[15] = 7.808100
|
||||
corr_angle[16] = 8.325300
|
||||
corr_angle[17] = 8.859400
|
||||
corr_angle[18] = 9.359400
|
||||
corr_angle[19] = 9.887900
|
||||
corr_angle[20] = 10.395400
|
||||
corr_angle[21] = 10.930700
|
||||
corr_angle[22] = 11.415400
|
||||
corr_angle[23] = 11.928900
|
||||
corr_angle[24] = 12.456900
|
||||
corr_angle[25] = 12.955900
|
||||
corr_angle[26] = 13.479000
|
||||
corr_angle[27] = 13.982700
|
||||
corr_angle[28] = 14.500900
|
||||
corr_angle[29] = 15.016200
|
||||
corr_angle[30] = 15.528000
|
||||
corr_angle[31] = 16.053800
|
||||
corr_angle[32] = 16.562800
|
||||
corr_angle[33] = 17.076600
|
||||
corr_angle[34] = 17.592400
|
||||
corr_angle[35] = 18.094100
|
||||
corr_angle[36] = 18.623800
|
||||
corr_angle[37] = 19.118400
|
||||
corr_angle[38] = 19.655000
|
||||
corr_angle[39] = 20.143900
|
||||
corr_angle[40] = 20.672200
|
||||
corr_angle[41] = 21.171500
|
||||
corr_angle[42] = 21.696300
|
||||
corr_angle[43] = 22.215900
|
||||
corr_angle[44] = 22.728900
|
||||
corr_angle[45] = 23.233100
|
||||
corr_angle[46] = 23.760000
|
||||
corr_angle[47] = 24.267700
|
||||
corr_angle[48] = 24.792100
|
||||
corr_angle[49] = 25.287900
|
||||
corr_angle[50] = 25.824600
|
||||
corr_angle[51] = 26.321900
|
||||
corr_angle[52] = 26.842600
|
||||
corr_angle[53] = 27.337200
|
||||
corr_angle[54] = 27.873500
|
||||
corr_angle[55] = 28.373900
|
||||
corr_angle[56] = 28.895900
|
||||
corr_angle[57] = 29.404900
|
||||
corr_angle[58] = 29.926700
|
||||
corr_angle[59] = 30.439300
|
||||
corr_angle[60] = 30.963700
|
||||
corr_angle[61] = 31.460000
|
||||
corr_angle[62] = 31.989500
|
||||
corr_angle[63] = 32.489700
|
||||
corr_angle[64] = 33.026400
|
||||
corr_angle[65] = 33.516500
|
||||
corr_angle[66] = 34.044000
|
||||
corr_angle[67] = 34.547700
|
||||
corr_angle[68] = 35.070800
|
||||
corr_angle[69] = 35.578400
|
||||
corr_angle[70] = 36.103200
|
||||
corr_angle[71] = 36.603200
|
||||
corr_angle[72] = 37.128200
|
||||
corr_angle[73] = 37.645200
|
||||
corr_angle[74] = 38.164300
|
||||
corr_angle[75] = 38.662100
|
||||
corr_angle[76] = 39.191000
|
||||
corr_angle[77] = 39.693400
|
||||
corr_angle[78] = 40.222500
|
||||
corr_angle[79] = 40.719500
|
||||
corr_angle[80] = 41.247000
|
||||
corr_angle[81] = 41.755700
|
||||
corr_angle[82] = 42.271300
|
||||
corr_angle[83] = 42.767600
|
||||
corr_angle[84] = 43.302200
|
||||
corr_angle[85] = 43.818700
|
||||
corr_angle[86] = 44.330000
|
||||
corr_angle[87] = 44.835300
|
||||
corr_angle[88] = 45.359800
|
||||
corr_angle[89] = 45.867200
|
||||
corr_angle[90] = 46.396200
|
||||
corr_angle[91] = 46.895000
|
||||
corr_angle[92] = 47.411500
|
||||
corr_angle[93] = 47.915200
|
||||
corr_angle[94] = 48.436600
|
||||
corr_angle[95] = 48.946100
|
||||
corr_angle[96] = 49.472300
|
||||
corr_angle[97] = 49.979800
|
||||
corr_angle[98] = 50.503300
|
||||
corr_angle[99] = 51.008700
|
||||
corr_angle[100] = 51.535000
|
||||
corr_angle[101] = 52.036700
|
||||
corr_angle[102] = 52.563700
|
||||
corr_angle[103] = 53.063600
|
||||
corr_angle[104] = 53.591700
|
||||
corr_angle[105] = 54.091200
|
||||
corr_angle[106] = 54.618900
|
||||
corr_angle[107] = 55.116900
|
||||
corr_angle[108] = 55.636100
|
||||
corr_angle[109] = 56.143100
|
||||
corr_angle[110] = 56.672200
|
||||
corr_angle[111] = 57.172900
|
||||
corr_angle[112] = 57.704600
|
||||
corr_angle[113] = 58.204800
|
||||
corr_angle[114] = 58.728600
|
||||
corr_angle[115] = 59.239500
|
||||
corr_angle[116] = 59.768400
|
||||
corr_angle[117] = 60.268300
|
||||
corr_angle[118] = 60.788800
|
||||
corr_angle[119] = 61.289300
|
||||
corr_angle[120] = 61.813300
|
||||
corr_angle[121] = 62.310800
|
||||
corr_angle[122] = 62.836700
|
||||
corr_angle[123] = 63.353700
|
||||
corr_angle[124] = 63.866600
|
||||
corr_angle[125] = 64.377200
|
||||
corr_angle[126] = 64.906600
|
||||
corr_angle[127] = 65.414000
|
||||
corr_angle[128] = 65.937100
|
||||
corr_angle[129] = 66.429400
|
||||
corr_angle[130] = 66.970000
|
||||
corr_angle[131] = 67.459200
|
||||
corr_angle[132] = 67.996400
|
||||
corr_angle[133] = 68.499800
|
||||
corr_angle[134] = 69.014500
|
||||
corr_angle[135] = 69.509500
|
||||
corr_angle[136] = 70.044000
|
||||
corr_angle[137] = 70.543200
|
||||
corr_angle[138] = 71.079400
|
||||
corr_angle[139] = 71.579300
|
||||
corr_angle[140] = 72.103500
|
||||
corr_angle[141] = 72.607000
|
||||
corr_angle[142] = 73.137100
|
||||
corr_angle[143] = 73.633000
|
||||
corr_angle[144] = 74.164500
|
||||
corr_angle[145] = 74.660200
|
||||
corr_angle[146] = 75.180600
|
||||
corr_angle[147] = 75.674200
|
||||
corr_angle[148] = 76.215400
|
||||
corr_angle[149] = 76.718900
|
||||
corr_angle[150] = 77.242300
|
||||
corr_angle[151] = 77.752000
|
||||
corr_angle[152] = 78.279300
|
||||
corr_angle[153] = 78.780500
|
||||
corr_angle[154] = 79.314900
|
||||
corr_angle[155] = 79.424500
|
||||
corr_angle[156] = 79.807000
|
||||
corr_angle[157] = 80.336500
|
||||
corr_angle[158] = 80.338700
|
||||
corr_angle[159] = 80.835300
|
||||
corr_angle[160] = 81.367100
|
||||
corr_angle[161] = 81.376100
|
||||
corr_angle[162] = 81.859000
|
||||
corr_angle[163] = 82.382300
|
||||
corr_angle[164] = 82.384000
|
||||
corr_angle[165] = 82.881100
|
||||
corr_angle[166] = 83.415000
|
||||
corr_angle[167] = 83.421600
|
||||
corr_angle[168] = 83.917100
|
||||
corr_angle[169] = 84.439200
|
||||
corr_angle[170] = 84.439300
|
||||
corr_angle[171] = 84.947400
|
||||
corr_angle[172] = 85.472700
|
||||
corr_angle[173] = 85.987700
|
||||
corr_angle[174] = 86.512400
|
||||
corr_angle[175] = 87.009500
|
||||
corr_angle[176] = 87.536500
|
||||
corr_angle[177] = 88.035600
|
||||
corr_angle[178] = 88.560100
|
||||
corr_angle[179] = 89.057600
|
||||
corr_angle[180] = 89.583200
|
||||
corr_angle[181] = 90.090500
|
||||
corr_angle[182] = 90.614600
|
||||
corr_angle[183] = 91.119900
|
||||
corr_angle[184] = 91.638300
|
||||
corr_angle[185] = 92.153300
|
||||
corr_angle[186] = 92.681600
|
||||
corr_angle[187] = 93.181800
|
||||
corr_angle[188] = 93.710900
|
||||
corr_angle[189] = 94.206100
|
||||
corr_angle[190] = 94.732700
|
||||
corr_angle[191] = 95.226600
|
||||
corr_angle[192] = 95.766400
|
||||
corr_angle[193] = 96.259000
|
||||
corr_angle[194] = 96.783400
|
||||
corr_angle[195] = 97.283100
|
||||
corr_angle[196] = 97.811500
|
||||
corr_angle[197] = 98.323600
|
||||
corr_angle[198] = 98.839400
|
||||
corr_angle[199] = 99.350700
|
||||
corr_angle[200] = 99.880200
|
||||
corr_angle[201] = 100.378100
|
||||
corr_angle[202] = 100.913300
|
||||
corr_angle[203] = 101.405000
|
||||
corr_angle[204] = 101.935700
|
||||
corr_angle[205] = 102.426300
|
||||
corr_angle[206] = 102.957300
|
||||
corr_angle[207] = 103.456500
|
||||
corr_angle[208] = 103.985100
|
||||
corr_angle[209] = 104.490300
|
||||
corr_angle[210] = 105.015100
|
||||
corr_angle[211] = 105.518400
|
||||
corr_angle[212] = 106.047400
|
||||
corr_angle[213] = 106.551100
|
||||
corr_angle[214] = 107.077100
|
||||
corr_angle[215] = 107.575800
|
||||
corr_angle[216] = 108.115200
|
||||
corr_angle[217] = 108.598800
|
||||
corr_angle[218] = 109.129100
|
||||
corr_angle[219] = 109.626200
|
||||
corr_angle[220] = 110.158400
|
||||
corr_angle[221] = 110.661700
|
||||
corr_angle[222] = 111.188600
|
||||
corr_angle[223] = 111.695000
|
||||
corr_angle[224] = 112.216400
|
||||
corr_angle[225] = 112.720000
|
||||
corr_angle[226] = 113.246200
|
||||
corr_angle[227] = 113.757100
|
||||
corr_angle[228] = 114.281900
|
||||
corr_angle[229] = 114.780000
|
||||
corr_angle[230] = 115.306800
|
||||
corr_angle[231] = 115.799800
|
||||
corr_angle[232] = 116.328400
|
||||
corr_angle[233] = 116.829900
|
||||
corr_angle[234] = 117.355400
|
||||
corr_angle[235] = 117.858200
|
||||
corr_angle[236] = 118.380600
|
||||
corr_angle[237] = 118.893200
|
||||
corr_angle[238] = 119.418200
|
||||
corr_angle[239] = 119.921000
|
||||
corr_angle[240] = 120.446100
|
||||
corr_angle[241] = 120.953800
|
||||
corr_angle[242] = 121.480300
|
||||
corr_angle[243] = 121.977600
|
||||
corr_angle[244] = 122.507100
|
||||
corr_angle[245] = 122.996200
|
||||
corr_angle[246] = 123.529600
|
||||
corr_angle[247] = 124.032200
|
||||
corr_angle[248] = 124.554800
|
||||
corr_angle[249] = 125.057800
|
||||
corr_angle[250] = 125.580800
|
||||
corr_angle[251] = 126.090000
|
||||
corr_angle[252] = 126.611600
|
||||
corr_angle[253] = 127.127000
|
||||
corr_angle[254] = 127.650900
|
||||
corr_angle[255] = 128.153700
|
||||
corr_angle[256] = 128.677200
|
||||
corr_angle[257] = 129.170800
|
||||
corr_angle[258] = 129.703000
|
||||
corr_angle[259] = 130.194900
|
||||
corr_angle[260] = 130.733600
|
||||
corr_angle[261] = 131.228300
|
||||
corr_angle[262] = 131.756900
|
||||
corr_angle[263] = 132.263200
|
||||
corr_angle[264] = 132.784700
|
||||
corr_angle[265] = 133.296300
|
||||
corr_angle[266] = 133.818800
|
||||
corr_angle[267] = 134.318900
|
||||
corr_angle[268] = 134.846800
|
||||
corr_angle[269] = 135.344800
|
||||
corr_angle[270] = 135.876000
|
||||
corr_angle[271] = 136.372600
|
||||
corr_angle[272] = 136.902700
|
||||
corr_angle[273] = 137.397800
|
||||
corr_angle[274] = 137.926800
|
||||
corr_angle[275] = 138.428000
|
||||
corr_angle[276] = 138.953700
|
||||
corr_angle[277] = 139.461300
|
||||
corr_angle[278] = 139.987800
|
||||
corr_angle[279] = 140.492600
|
||||
corr_angle[280] = 141.017900
|
||||
corr_angle[281] = 141.524000
|
||||
corr_angle[282] = 142.061200
|
||||
corr_angle[283] = 142.545400
|
||||
corr_angle[284] = 143.069900
|
||||
corr_angle[285] = 143.568700
|
||||
corr_angle[286] = 144.102200
|
||||
corr_angle[287] = 144.596200
|
||||
corr_angle[288] = 145.126400
|
||||
corr_angle[289] = 145.626900
|
||||
corr_angle[290] = 146.158700
|
||||
corr_angle[291] = 146.662200
|
||||
corr_angle[292] = 147.184700
|
||||
corr_angle[293] = 147.692300
|
||||
corr_angle[294] = 148.225900
|
||||
corr_angle[295] = 148.716000
|
||||
corr_angle[296] = 149.243400
|
||||
corr_angle[297] = 149.739400
|
||||
corr_angle[298] = 150.272400
|
||||
corr_angle[299] = 150.762100
|
||||
corr_angle[300] = 151.301800
|
||||
corr_angle[301] = 151.796300
|
||||
corr_angle[302] = 152.333500
|
||||
corr_angle[303] = 152.833100
|
||||
corr_angle[304] = 153.363600
|
||||
corr_angle[305] = 153.862900
|
||||
corr_angle[306] = 154.396100
|
||||
corr_angle[307] = 154.895400
|
||||
corr_angle[308] = 155.417700
|
||||
corr_angle[309] = 155.916900
|
||||
corr_angle[310] = 156.451600
|
||||
corr_angle[311] = 156.942700
|
||||
corr_angle[312] = 157.467600
|
||||
corr_angle[313] = 157.970900
|
||||
corr_angle[314] = 158.501100
|
||||
corr_angle[315] = 158.999600
|
||||
corr_angle[316] = 159.526100
|
||||
corr_angle[317] = 160.028100
|
||||
corr_angle[318] = 160.555800
|
||||
corr_angle[319] = 161.067700
|
||||
corr_angle[320] = 161.597300
|
||||
corr_angle[321] = 162.091300
|
||||
corr_angle[322] = 162.616600
|
||||
corr_angle[323] = 163.107400
|
||||
corr_angle[324] = 163.639100
|
||||
corr_angle[325] = 164.139700
|
||||
corr_angle[326] = 164.672500
|
||||
corr_angle[327] = 165.176800
|
||||
corr_angle[328] = 165.698600
|
||||
corr_angle[329] = 166.205400
|
||||
corr_angle[330] = 166.727300
|
||||
corr_angle[331] = 167.238600
|
||||
corr_angle[332] = 167.771500
|
||||
corr_angle[333] = 168.265000
|
||||
corr_angle[334] = 168.794800
|
||||
corr_angle[335] = 169.293800
|
||||
corr_angle[336] = 169.813300
|
||||
corr_angle[337] = 170.320200
|
||||
corr_angle[338] = 170.845100
|
||||
corr_angle[339] = 171.344000
|
||||
corr_angle[340] = 171.866200
|
||||
corr_angle[341] = 172.375300
|
||||
corr_angle[342] = 172.899400
|
||||
corr_angle[343] = 173.404400
|
||||
corr_angle[344] = 173.928500
|
||||
corr_angle[345] = 174.430800
|
||||
corr_angle[346] = 174.827800
|
||||
corr_angle[347] = 175.460400
|
||||
corr_angle[348] = 175.993100
|
||||
corr_angle[349] = 176.492100
|
||||
corr_angle[350] = 177.014200
|
||||
corr_angle[351] = 177.512100
|
||||
corr_angle[352] = 178.044200
|
||||
corr_angle[353] = 178.643800
|
||||
corr_angle[354] = 179.067200
|
||||
corr_angle[355] = 179.571600
|
||||
corr_angle[356] = 180.093700
|
||||
corr_pos[0] = -0.814519
|
||||
corr_pos[1] = -0.810675
|
||||
corr_pos[2] = -0.806338
|
||||
corr_pos[3] = -0.802047
|
||||
corr_pos[4] = -0.797044
|
||||
corr_pos[5] = -0.791712
|
||||
corr_pos[6] = -0.786558
|
||||
corr_pos[7] = -0.780781
|
||||
corr_pos[8] = -0.774864
|
||||
corr_pos[9] = -0.768674
|
||||
corr_pos[10] = -0.762005
|
||||
corr_pos[11] = -0.755474
|
||||
corr_pos[12] = -0.748024
|
||||
corr_pos[13] = -0.740730
|
||||
corr_pos[14] = -0.732929
|
||||
corr_pos[15] = -0.725011
|
||||
corr_pos[16] = -0.716637
|
||||
corr_pos[17] = -0.707676
|
||||
corr_pos[18] = -0.698861
|
||||
corr_pos[19] = -0.686245
|
||||
corr_pos[20] = -0.676596
|
||||
corr_pos[21] = -0.663643
|
||||
corr_pos[22] = -0.655664
|
||||
corr_pos[23] = -0.642249
|
||||
corr_pos[24] = -0.633516
|
||||
corr_pos[25] = -0.621402
|
||||
corr_pos[26] = -0.612846
|
||||
corr_pos[27] = -0.599978
|
||||
corr_pos[28] = -0.592135
|
||||
corr_pos[29] = -0.577949
|
||||
corr_pos[30] = -0.570695
|
||||
corr_pos[31] = -0.555560
|
||||
corr_pos[32] = -0.549015
|
||||
corr_pos[33] = -0.532162
|
||||
corr_pos[34] = -0.524479
|
||||
corr_pos[35] = -0.507848
|
||||
corr_pos[36] = -0.500301
|
||||
corr_pos[37] = -0.484361
|
||||
corr_pos[38] = -0.477365
|
||||
corr_pos[39] = -0.461751
|
||||
corr_pos[40] = -0.455963
|
||||
corr_pos[41] = -0.439438
|
||||
corr_pos[42] = -0.436103
|
||||
corr_pos[43] = -0.420587
|
||||
corr_pos[44] = -0.417361
|
||||
corr_pos[45] = -0.402270
|
||||
corr_pos[46] = -0.400459
|
||||
corr_pos[47] = -0.384745
|
||||
corr_pos[48] = -0.385280
|
||||
corr_pos[49] = -0.371217
|
||||
corr_pos[50] = -0.373612
|
||||
corr_pos[51] = -0.361838
|
||||
corr_pos[52] = -0.365771
|
||||
corr_pos[53] = -0.354641
|
||||
corr_pos[54] = -0.360647
|
||||
corr_pos[55] = -0.351446
|
||||
corr_pos[56] = -0.359147
|
||||
corr_pos[57] = -0.348696
|
||||
corr_pos[58] = -0.359348
|
||||
corr_pos[59] = -0.349962
|
||||
corr_pos[60] = -0.360782
|
||||
corr_pos[61] = -0.355040
|
||||
corr_pos[62] = -0.367441
|
||||
corr_pos[63] = -0.360511
|
||||
corr_pos[64] = -0.372617
|
||||
corr_pos[65] = -0.366120
|
||||
corr_pos[66] = -0.377568
|
||||
corr_pos[67] = -0.370362
|
||||
corr_pos[68] = -0.380918
|
||||
corr_pos[69] = -0.372553
|
||||
corr_pos[70] = -0.381460
|
||||
corr_pos[71] = -0.371828
|
||||
corr_pos[72] = -0.379428
|
||||
corr_pos[73] = -0.368465
|
||||
corr_pos[74] = -0.374297
|
||||
corr_pos[75] = -0.360340
|
||||
corr_pos[76] = -0.365429
|
||||
corr_pos[77] = -0.349168
|
||||
corr_pos[78] = -0.351544
|
||||
corr_pos[79] = -0.332514
|
||||
corr_pos[80] = -0.333505
|
||||
corr_pos[81] = -0.313316
|
||||
corr_pos[82] = -0.313014
|
||||
corr_pos[83] = -0.291107
|
||||
corr_pos[84] = -0.287807
|
||||
corr_pos[85] = -0.264483
|
||||
corr_pos[86] = -0.260891
|
||||
corr_pos[87] = -0.236646
|
||||
corr_pos[88] = -0.231362
|
||||
corr_pos[89] = -0.205833
|
||||
corr_pos[90] = -0.200663
|
||||
corr_pos[91] = -0.174834
|
||||
corr_pos[92] = -0.171662
|
||||
corr_pos[93] = -0.146200
|
||||
corr_pos[94] = -0.142890
|
||||
corr_pos[95] = -0.118389
|
||||
corr_pos[96] = -0.112895
|
||||
corr_pos[97] = -0.088879
|
||||
corr_pos[98] = -0.084146
|
||||
corr_pos[99] = -0.061625
|
||||
corr_pos[100] = -0.054742
|
||||
corr_pos[101] = -0.032741
|
||||
corr_pos[102] = -0.026725
|
||||
corr_pos[103] = -0.004827
|
||||
corr_pos[104] = 0.002678
|
||||
corr_pos[105] = 0.024418
|
||||
corr_pos[106] = 0.031105
|
||||
corr_pos[107] = 0.052334
|
||||
corr_pos[108] = 0.060072
|
||||
corr_pos[109] = 0.081470
|
||||
corr_pos[110] = 0.088550
|
||||
corr_pos[111] = 0.109685
|
||||
corr_pos[112] = 0.116675
|
||||
corr_pos[113] = 0.136298
|
||||
corr_pos[114] = 0.142152
|
||||
corr_pos[115] = 0.161986
|
||||
corr_pos[116] = 0.166996
|
||||
corr_pos[117] = 0.186466
|
||||
corr_pos[118] = 0.190874
|
||||
corr_pos[119] = 0.208729
|
||||
corr_pos[120] = 0.212714
|
||||
corr_pos[121] = 0.229992
|
||||
corr_pos[122] = 0.232685
|
||||
corr_pos[123] = 0.248748
|
||||
corr_pos[124] = 0.249688
|
||||
corr_pos[125] = 0.264768
|
||||
corr_pos[126] = 0.264432
|
||||
corr_pos[127] = 0.278801
|
||||
corr_pos[128] = 0.278424
|
||||
corr_pos[129] = 0.289656
|
||||
corr_pos[130] = 0.289612
|
||||
corr_pos[131] = 0.299899
|
||||
corr_pos[132] = 0.299782
|
||||
corr_pos[133] = 0.307473
|
||||
corr_pos[134] = 0.309489
|
||||
corr_pos[135] = 0.315999
|
||||
corr_pos[136] = 0.317413
|
||||
corr_pos[137] = 0.325060
|
||||
corr_pos[138] = 0.325931
|
||||
corr_pos[139] = 0.332544
|
||||
corr_pos[140] = 0.332095
|
||||
corr_pos[141] = 0.338738
|
||||
corr_pos[142] = 0.337864
|
||||
corr_pos[143] = 0.343909
|
||||
corr_pos[144] = 0.342973
|
||||
corr_pos[145] = 0.348449
|
||||
corr_pos[146] = 0.346060
|
||||
corr_pos[147] = 0.351949
|
||||
corr_pos[148] = 0.349873
|
||||
corr_pos[149] = 0.354969
|
||||
corr_pos[150] = 0.352375
|
||||
corr_pos[151] = 0.358388
|
||||
corr_pos[152] = 0.354736
|
||||
corr_pos[153] = 0.359539
|
||||
corr_pos[154] = 0.354369
|
||||
corr_pos[155] = 0.358549
|
||||
corr_pos[156] = 0.353217
|
||||
corr_pos[157] = 0.355795
|
||||
corr_pos[158] = 0.351299
|
||||
corr_pos[159] = 0.352922
|
||||
corr_pos[160] = 0.346933
|
||||
corr_pos[161] = 0.350201
|
||||
corr_pos[162] = 0.343937
|
||||
corr_pos[163] = 0.349304
|
||||
corr_pos[164] = 0.344857
|
||||
corr_pos[165] = 0.347471
|
||||
corr_pos[166] = 0.335793
|
||||
corr_pos[167] = 0.341109
|
||||
corr_pos[168] = 0.330453
|
||||
corr_pos[169] = 0.326576
|
||||
corr_pos[170] = 0.320299
|
||||
corr_pos[171] = 0.315348
|
||||
corr_pos[172] = 0.300744
|
||||
corr_pos[173] = 0.294366
|
||||
corr_pos[174] = 0.280438
|
||||
corr_pos[175] = 0.273618
|
||||
corr_pos[176] = 0.259335
|
||||
corr_pos[177] = 0.251464
|
||||
corr_pos[178] = 0.237247
|
||||
corr_pos[179] = 0.229092
|
||||
corr_pos[180] = 0.214882
|
||||
corr_pos[181] = 0.207363
|
||||
corr_pos[182] = 0.193246
|
||||
corr_pos[183] = 0.185868
|
||||
corr_pos[184] = 0.173256
|
||||
corr_pos[185] = 0.165378
|
||||
corr_pos[186] = 0.153853
|
||||
corr_pos[187] = 0.147031
|
||||
corr_pos[188] = 0.135535
|
||||
corr_pos[189] = 0.129435
|
||||
corr_pos[190] = 0.119843
|
||||
corr_pos[191] = 0.115062
|
||||
corr_pos[192] = 0.107115
|
||||
corr_pos[193] = 0.105182
|
||||
corr_pos[194] = 0.099647
|
||||
corr_pos[195] = 0.098162
|
||||
corr_pos[196] = 0.094628
|
||||
corr_pos[197] = 0.095257
|
||||
corr_pos[198] = 0.084490
|
||||
corr_pos[199] = 0.085389
|
||||
corr_pos[200] = 0.074302
|
||||
corr_pos[201] = 0.075265
|
||||
corr_pos[202] = 0.063623
|
||||
corr_pos[203] = 0.064487
|
||||
corr_pos[204] = 0.052841
|
||||
corr_pos[205] = 0.053559
|
||||
corr_pos[206] = 0.042022
|
||||
corr_pos[207] = 0.043321
|
||||
corr_pos[208] = 0.032826
|
||||
corr_pos[209] = 0.032277
|
||||
corr_pos[210] = 0.022169
|
||||
corr_pos[211] = 0.020740
|
||||
corr_pos[212] = 0.010378
|
||||
corr_pos[213] = 0.008668
|
||||
corr_pos[214] = -0.001930
|
||||
corr_pos[215] = -0.003882
|
||||
corr_pos[216] = -0.014694
|
||||
corr_pos[217] = -0.016629
|
||||
corr_pos[218] = -0.026380
|
||||
corr_pos[219] = -0.028069
|
||||
corr_pos[220] = -0.037125
|
||||
corr_pos[221] = -0.039429
|
||||
corr_pos[222] = -0.047773
|
||||
corr_pos[223] = -0.049261
|
||||
corr_pos[224] = -0.056872
|
||||
corr_pos[225] = -0.058756
|
||||
corr_pos[226] = -0.065279
|
||||
corr_pos[227] = -0.066859
|
||||
corr_pos[228] = -0.073027
|
||||
corr_pos[229] = -0.074253
|
||||
corr_pos[230] = -0.079062
|
||||
corr_pos[231] = -0.079800
|
||||
corr_pos[232] = -0.084350
|
||||
corr_pos[233] = -0.084805
|
||||
corr_pos[234] = -0.088621
|
||||
corr_pos[235] = -0.088437
|
||||
corr_pos[236] = -0.092166
|
||||
corr_pos[237] = -0.090769
|
||||
corr_pos[238] = -0.093820
|
||||
corr_pos[239] = -0.091724
|
||||
corr_pos[240] = -0.094152
|
||||
corr_pos[241] = -0.090866
|
||||
corr_pos[242] = -0.092575
|
||||
corr_pos[243] = -0.089239
|
||||
corr_pos[244] = -0.089666
|
||||
corr_pos[245] = -0.086864
|
||||
corr_pos[246] = -0.087183
|
||||
corr_pos[247] = -0.083974
|
||||
corr_pos[248] = -0.083709
|
||||
corr_pos[249] = -0.079848
|
||||
corr_pos[250] = -0.078494
|
||||
corr_pos[251] = -0.072782
|
||||
corr_pos[252] = -0.069638
|
||||
corr_pos[253] = -0.063004
|
||||
corr_pos[254] = -0.058599
|
||||
corr_pos[255] = -0.051737
|
||||
corr_pos[256] = -0.046451
|
||||
corr_pos[257] = -0.040238
|
||||
corr_pos[258] = -0.034071
|
||||
corr_pos[259] = -0.028578
|
||||
corr_pos[260] = -0.021481
|
||||
corr_pos[261] = -0.016346
|
||||
corr_pos[262] = -0.009475
|
||||
corr_pos[263] = -0.004141
|
||||
corr_pos[264] = 0.002780
|
||||
corr_pos[265] = 0.008455
|
||||
corr_pos[266] = 0.015507
|
||||
corr_pos[267] = 0.021672
|
||||
corr_pos[268] = 0.029704
|
||||
corr_pos[269] = 0.036662
|
||||
corr_pos[270] = 0.044794
|
||||
corr_pos[271] = 0.052031
|
||||
corr_pos[272] = 0.061478
|
||||
corr_pos[273] = 0.069150
|
||||
corr_pos[274] = 0.078715
|
||||
corr_pos[275] = 0.087785
|
||||
corr_pos[276] = 0.098593
|
||||
corr_pos[277] = 0.107863
|
||||
corr_pos[278] = 0.118256
|
||||
corr_pos[279] = 0.127631
|
||||
corr_pos[280] = 0.139011
|
||||
corr_pos[281] = 0.150077
|
||||
corr_pos[282] = 0.162154
|
||||
corr_pos[283] = 0.173758
|
||||
corr_pos[284] = 0.186998
|
||||
corr_pos[285] = 0.200111
|
||||
corr_pos[286] = 0.214116
|
||||
corr_pos[287] = 0.227291
|
||||
corr_pos[288] = 0.240662
|
||||
corr_pos[289] = 0.252955
|
||||
corr_pos[290] = 0.265359
|
||||
corr_pos[291] = 0.275995
|
||||
corr_pos[292] = 0.287613
|
||||
corr_pos[293] = 0.295789
|
||||
corr_pos[294] = 0.306424
|
||||
corr_pos[295] = 0.313027
|
||||
corr_pos[296] = 0.322181
|
||||
corr_pos[297] = 0.329313
|
||||
corr_pos[298] = 0.338191
|
||||
corr_pos[299] = 0.345243
|
||||
corr_pos[300] = 0.353316
|
||||
corr_pos[301] = 0.360491
|
||||
corr_pos[302] = 0.367891
|
||||
corr_pos[303] = 0.375027
|
||||
corr_pos[304] = 0.380865
|
||||
corr_pos[305] = 0.388354
|
||||
corr_pos[306] = 0.395257
|
||||
corr_pos[307] = 0.401478
|
||||
corr_pos[308] = 0.408087
|
||||
corr_pos[309] = 0.414083
|
||||
corr_pos[310] = 0.420361
|
||||
corr_pos[311] = 0.424284
|
||||
corr_pos[312] = 0.429614
|
||||
corr_pos[313] = 0.433888
|
||||
corr_pos[314] = 0.438529
|
||||
corr_pos[315] = 0.442302
|
||||
corr_pos[316] = 0.445899
|
||||
corr_pos[317] = 0.449014
|
||||
corr_pos[318] = 0.451693
|
||||
corr_pos[319] = 0.453795
|
||||
corr_pos[320] = 0.455132
|
||||
corr_pos[321] = 0.455438
|
||||
corr_pos[322] = 0.455334
|
||||
corr_pos[323] = 0.454055
|
||||
corr_pos[324] = 0.451146
|
||||
corr_pos[325] = 0.447259
|
||||
corr_pos[326] = 0.442478
|
||||
corr_pos[327] = 0.437520
|
||||
corr_pos[328] = 0.432297
|
||||
corr_pos[329] = 0.426442
|
||||
corr_pos[330] = 0.418918
|
||||
corr_pos[331] = 0.411040
|
||||
corr_pos[332] = 0.402610
|
||||
corr_pos[333] = 0.394491
|
||||
corr_pos[334] = 0.383925
|
||||
corr_pos[335] = 0.374590
|
||||
corr_pos[336] = 0.363650
|
||||
corr_pos[337] = 0.353143
|
||||
corr_pos[338] = 0.339756
|
||||
corr_pos[339] = 0.328074
|
||||
corr_pos[340] = 0.315463
|
||||
corr_pos[341] = 0.302641
|
||||
corr_pos[342] = 0.288898
|
||||
corr_pos[343] = 0.275134
|
||||
corr_pos[344] = 0.260308
|
||||
corr_pos[345] = 0.245582
|
||||
corr_pos[346] = 0.233584
|
||||
corr_pos[347] = 0.213812
|
||||
corr_pos[348] = 0.196540
|
||||
corr_pos[349] = 0.179844
|
||||
corr_pos[350] = 0.161839
|
||||
corr_pos[351] = 0.144160
|
||||
corr_pos[352] = 0.124715
|
||||
corr_pos[353] = 0.102123
|
||||
corr_pos[354] = 0.085736
|
||||
corr_pos[355] = 0.065743
|
||||
corr_pos[356] = 0.044511
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,171 +0,0 @@
|
||||
import builtins
|
||||
|
||||
from bec_widgets.cli.client import BECDockArea
|
||||
|
||||
# from csaxs_bec.bec_ipython_client.plugins.cSAXS import epics_get, epics_put, fshopen, fshclose
|
||||
|
||||
if builtins.__dict__.get("bec") is not None:
|
||||
bec = builtins.__dict__.get("bec")
|
||||
dev = builtins.__dict__.get("dev")
|
||||
umv = builtins.__dict__.get("umv")
|
||||
umvr = builtins.__dict__.get("umvr")
|
||||
|
||||
|
||||
class OMNYGuiToolsError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class OMNYGuiTools:
|
||||
|
||||
def __init__(self, client):
|
||||
self.gui = getattr(client, "gui", None)
|
||||
self.gui_window = self.gui.windows['main'].widget
|
||||
self.fig200 = None
|
||||
self.fig201 = None
|
||||
self.fig202 = None
|
||||
self.fig203 = None
|
||||
self.progressbar = None
|
||||
self.text_box = None
|
||||
self.idle_text_box = None
|
||||
|
||||
def omnygui_show_gui(self):
|
||||
self.gui_window.show()
|
||||
|
||||
def omnygui_stop_gui(self):
|
||||
self.gui_window.hide()
|
||||
|
||||
def _omnycam_parking(self):
|
||||
self.omnygui_show_omnycam_parking()
|
||||
|
||||
def omnygui_show_omnycam_parking(self):
|
||||
self.omnygui_show_gui()
|
||||
if self.fig200 is None:
|
||||
self._omnycam_clear()
|
||||
self.fig200 = self.gui_window.add_dock(name="omnycam200").add_widget("BECImageWidget")
|
||||
if self._omnycam_check_device_exists(dev.cam200):
|
||||
fig = self.fig200.image("cam200")
|
||||
fig.set_rotation(deg_90=3)
|
||||
self.fig200.lock_aspect_ratio(True)
|
||||
else:
|
||||
print("Cannot open cam200. Device does not exist.")
|
||||
self.fig203 = self.gui_window.add_dock(name="omnycam203").add_widget("BECImageWidget")
|
||||
if self._omnycam_check_device_exists(dev.cam203):
|
||||
fig = self.fig203.image("cam203")
|
||||
fig.set_rotation(deg_90=3)
|
||||
self.fig203.lock_aspect_ratio(True)
|
||||
else:
|
||||
print("Cannot open cam203. Device does not exist.")
|
||||
try:
|
||||
self.gui_window.remove_dock(name="default_figure")
|
||||
except:
|
||||
pass
|
||||
|
||||
def omnygui_remove_all_docks(self):
|
||||
self.gui_window.clear_all()
|
||||
self.fig200 = None
|
||||
self.fig201 = None
|
||||
self.fig202 = None
|
||||
self.fig203 = None
|
||||
self.progressbar = None
|
||||
self.text_box = None
|
||||
self.idle_text_box = None
|
||||
|
||||
def omnygui_idle(self):
|
||||
self.omnygui_show_gui()
|
||||
if self.idle_text_box is None:
|
||||
self.omnygui_remove_all_docks()
|
||||
self.idle_text_box = self.gui_window.add_dock(name="idle_text").add_widget("TextBox")
|
||||
try:
|
||||
self.gui_window.remove_dock(name="default_figure")
|
||||
except:
|
||||
pass
|
||||
text = (
|
||||
"<pre>"
|
||||
+ " ,o888888o. ,8. ,8. b. 8 `8.`8888. ,8' \n"
|
||||
+ " . 8888 `88. ,888. ,888. 888o. 8 `8.`8888. ,8' \n"
|
||||
+ ",8 8888 `8b .`8888. .`8888. Y88888o. 8 `8.`8888. ,8' \n"
|
||||
+ "88 8888 `8b ,8.`8888. ,8.`8888. .`Y888888o. 8 `8.`8888.,8' \n"
|
||||
+ "88 8888 88 ,8'8.`8888,8^8.`8888. 8o. `Y888888o. 8 `8.`88888' \n"
|
||||
+ "88 8888 88 ,8' `8.`8888' `8.`8888. 8`Y8o. `Y88888o8 `8. 8888 \n"
|
||||
+ "88 8888 ,8P ,8' `8.`88' `8.`8888. 8 `Y8o. `Y8888 `8 8888 \n"
|
||||
+ "`8 8888 ,8P ,8' `8.`' `8.`8888. 8 `Y8o. `Y8 8 8888 \n"
|
||||
+ " ` 8888 ,88' ,8' `8 `8.`8888. 8 `Y8o.` 8 8888 \n"
|
||||
+ " `8888888P' ,8' ` `8.`8888. 8 `Yo 8 8888 \n"
|
||||
+ "</pre>"
|
||||
)
|
||||
self.idle_text_box.set_html_text(text)
|
||||
|
||||
def _omnycam_clear(self):
|
||||
self.omnygui_remove_all_docks()
|
||||
|
||||
def _omnycam_check_device_exists(self, device):
|
||||
try:
|
||||
device
|
||||
except:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def _omnycam_samplestage(self):
|
||||
self.omnygui_show_omnycam_samplestage()
|
||||
|
||||
def omnygui_show_omnycam_samplestage(self):
|
||||
self.omnygui_show_gui()
|
||||
if self.fig201 is None:
|
||||
self.omnygui_remove_all_docks()
|
||||
self.fig201 = self.gui_window.add_dock(name="omnycam201").add_widget("BECImageWidget")
|
||||
if self._omnycam_check_device_exists(dev.cam201):
|
||||
fig = self.fig201.image("cam201")
|
||||
fig.set_rotation(deg_90=3)
|
||||
self.fig201.lock_aspect_ratio(True)
|
||||
else:
|
||||
print("Cannot open cam201. Device does not exist.")
|
||||
self.fig202 = self.gui_window.add_dock(name="omnycam202").add_widget("BECImageWidget")
|
||||
if self._omnycam_check_device_exists(dev.cam202):
|
||||
fig = self.fig202.image("cam202")
|
||||
fig.set_rotation(deg_90=3)
|
||||
self.fig202.lock_aspect_ratio(True)
|
||||
else:
|
||||
print("Cannot open cam202. Device does not exist.")
|
||||
try:
|
||||
self.gui_window.remove_dock(name="default_figure")
|
||||
except:
|
||||
pass
|
||||
|
||||
def omnygui_show_progress(self):
|
||||
self.omnygui_show_gui()
|
||||
if self.progressbar is None:
|
||||
self.omnygui_remove_all_docks()
|
||||
# Add a new dock with a RingProgressBar widget
|
||||
self.progressbar = self.gui_window.add_dock(name="progress").add_widget("RingProgressBar")
|
||||
# Customize the size of the progress ring
|
||||
self.progressbar.set_line_widths(20)
|
||||
# Disable automatic updates and manually set the self.progressbar value
|
||||
self.progressbar.enable_auto_updates(False)
|
||||
# Set precision for the self.progressbar display
|
||||
self.progressbar.set_precision(1) # Display self.progressbar with one decimal places
|
||||
# Setting multiple rigns with different values
|
||||
self.progressbar.set_number_of_bars(3)
|
||||
self.progressbar.rings[2].set_update("scan")
|
||||
# Set the values of the rings to 50, 75, and 25 from outer to inner ring
|
||||
# self.progressbar.set_value([50, 75])
|
||||
# Add a new dock with a TextBox widget
|
||||
self.text_box = self.gui_window.add_dock(name="progress_text").add_widget("TextBox")
|
||||
try:
|
||||
self.gui_window.remove_dock(name="default_figure")
|
||||
except:
|
||||
pass
|
||||
self._omnygui_update_progress()
|
||||
|
||||
def _omnygui_update_progress(self):
|
||||
if self.progressbar is not None:
|
||||
progress = self.progress["projection"] / self.progress["total_projections"] * 100
|
||||
subotmo_progress = (
|
||||
self.progress["subtomo_projection"]
|
||||
/ self.progress["subtomo_total_projections"]
|
||||
* 100
|
||||
)
|
||||
self.progressbar.set_value([progress, subotmo_progress])
|
||||
|
||||
text = f"Progress report:\n Tomo type: ....................... {self.progress['tomo_type']}\n Projection: ...................... {self.progress['projection']:.0f}\n Total projections expected ....... {self.progress['total_projections']}\n Angle: ........................... {self.progress['angle']}\n Current subtomo: ................. {self.progress['subtomo']}\n Current projection within subtomo: {self.progress['subtomo_projection']}\n Total projections per subtomo: ... {self.progress['subtomo_total_projections']}"
|
||||
self.text_box.set_plain_text(text)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,246 +0,0 @@
|
||||
import time
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
from rich import box
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
|
||||
from typeguard import typechecked
|
||||
from bec_lib import bec_logger
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
|
||||
class OMNYAlignmentError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class OMNYAlignmentMixin:
|
||||
default_correction_file = "correction_omny_202204.txt"
|
||||
default_correction_file_x = "correction_omny_202204_x.txt"
|
||||
|
||||
def reset_correction(self, use_default_correction=True):
|
||||
"""
|
||||
Reset the correction to the default values.
|
||||
If use_default_correction is False, the correction will be set to empty values.
|
||||
Otherwise the default values will be loaded.
|
||||
|
||||
Args:
|
||||
use_default_correction (bool, optional): If set to true, a call reset the correction to the default values. Defaults to True.
|
||||
"""
|
||||
self.corr_pos_x = []
|
||||
self.corr_angle_x = []
|
||||
self.corr_pos_y = []
|
||||
self.corr_angle_y = []
|
||||
self.corr_pos_y_2 = []
|
||||
self.corr_angle_y_2 = []
|
||||
|
||||
if use_default_correction:
|
||||
try:
|
||||
self.read_additional_correction_x(self.default_correction_file_x)
|
||||
logger.info(f"Applying default x correction from {self.default_correction_file_x}")
|
||||
except FileNotFoundError:
|
||||
logger.warning(
|
||||
f"Could not find default correction file {self.default_correction_file_x}."
|
||||
)
|
||||
logger.warning("Not applying any correction.")
|
||||
try:
|
||||
self.read_additional_correction_y(self.default_correction_file)
|
||||
logger.info(f"Applying default y correction from {self.default_correction_file}")
|
||||
except FileNotFoundError:
|
||||
logger.warning(
|
||||
f"Could not find default correction file {self.default_correction_file}."
|
||||
)
|
||||
logger.warning("Not applying any correction.")
|
||||
|
||||
def reset_tomo_alignment_fit(self):
|
||||
self.client.delete_global_var("tomo_alignment_fit")
|
||||
|
||||
def read_alignment_offset(
|
||||
self,
|
||||
dir_path=os.path.expanduser("~/Data10/specES1/internal/"),
|
||||
setup="omny",
|
||||
use_vertical_default_values=True,
|
||||
):
|
||||
"""
|
||||
Read the alignment offset from the given directory and set the global parameter
|
||||
tomo_alignment_fit.
|
||||
|
||||
Args:
|
||||
dir_path (str, optional): The directory to read the alignment offset from. Defaults to os.path.expanduser("~/Data10/specES1/internal/").
|
||||
"""
|
||||
tomo_alignment_fit = np.zeros((2, 5))
|
||||
with open(os.path.join(dir_path, "ptychotomoalign_Ax.txt"), "r") as file:
|
||||
tomo_alignment_fit[0][0] = file.readline()
|
||||
|
||||
with open(os.path.join(dir_path, "ptychotomoalign_Bx.txt"), "r") as file:
|
||||
tomo_alignment_fit[0][1] = file.readline()
|
||||
|
||||
with open(os.path.join(dir_path, "ptychotomoalign_Cx.txt"), "r") as file:
|
||||
tomo_alignment_fit[0][2] = file.readline()
|
||||
|
||||
with open(os.path.join(dir_path, "ptychotomoalign_Ay.txt"), "r") as file:
|
||||
tomo_alignment_fit[1][0] = file.readline()
|
||||
|
||||
with open(os.path.join(dir_path, "ptychotomoalign_By.txt"), "r") as file:
|
||||
tomo_alignment_fit[1][1] = file.readline()
|
||||
|
||||
with open(os.path.join(dir_path, "ptychotomoalign_Cy.txt"), "r") as file:
|
||||
tomo_alignment_fit[1][2] = file.readline()
|
||||
|
||||
with open(os.path.join(dir_path, "ptychotomoalign_Ay3.txt"), "r") as file:
|
||||
tomo_alignment_fit[1][3] = file.readline()
|
||||
|
||||
with open(os.path.join(dir_path, "ptychotomoalign_Cy3.txt"), "r") as file:
|
||||
tomo_alignment_fit[1][4] = file.readline()
|
||||
|
||||
print("New alignment parameters loaded:")
|
||||
print(
|
||||
f"X Amplitude {tomo_alignment_fit[0][0]}, "
|
||||
f"X Phase {tomo_alignment_fit[0][1]}, "
|
||||
f"X Offset {tomo_alignment_fit[0][2]}, "
|
||||
f"Y Amplitude {tomo_alignment_fit[1][0]}, "
|
||||
f"Y Phase {tomo_alignment_fit[1][1]}, "
|
||||
f"Y Offset {tomo_alignment_fit[1][2]}, "
|
||||
f"Y 3rd Order Amplitude {tomo_alignment_fit[1][3]}, "
|
||||
f"Y 3rd Order Phase {tomo_alignment_fit[1][4]} ."
|
||||
)
|
||||
|
||||
if use_vertical_default_values:
|
||||
print(
|
||||
f"Using default values for vertical alignment for setup {setup}. Optional: use_vertical_default_values=False"
|
||||
)
|
||||
if setup == "flomni":
|
||||
tomo_alignment_fit[1][0] = 0
|
||||
tomo_alignment_fit[1][1] = 0
|
||||
tomo_alignment_fit[1][2] = 0
|
||||
tomo_alignment_fit[1][3] = 0
|
||||
tomo_alignment_fit[1][4] = 0
|
||||
elif setup == "omny":
|
||||
tomo_alignment_fit[1][0] = 2.588628
|
||||
tomo_alignment_fit[1][1] = -2.385422
|
||||
tomo_alignment_fit[1][2] = 0
|
||||
tomo_alignment_fit[1][3] = 1.010583
|
||||
tomo_alignment_fit[1][4] = -1.359157
|
||||
|
||||
print("Follwing parameters will be used:")
|
||||
print(
|
||||
f"X Amplitude {tomo_alignment_fit[0][0]}, "
|
||||
f"X Phase {tomo_alignment_fit[0][1]}, "
|
||||
f"X Offset {tomo_alignment_fit[0][2]}, "
|
||||
f"Y Amplitude {tomo_alignment_fit[1][0]}, "
|
||||
f"Y Phase {tomo_alignment_fit[1][1]}, "
|
||||
f"Y Offset {tomo_alignment_fit[1][2]}, "
|
||||
f"Y 3rd Order Amplitude {tomo_alignment_fit[1][3]}, "
|
||||
f"Y 3rd Order Phase {tomo_alignment_fit[1][4]} ."
|
||||
)
|
||||
|
||||
self.client.set_global_var("tomo_alignment_fit", tomo_alignment_fit.tolist())
|
||||
# x amp, phase, offset, y amp, phase, offset, 3rd order amp, 3rd order phase
|
||||
# 0 0 0 1 0 2 1 0 1 1 1 2 1 3 1 4
|
||||
|
||||
def get_alignment_offset(self, angle: float):
|
||||
"""
|
||||
Compute the alignment offset for the given angle.
|
||||
|
||||
Args:
|
||||
angle (float): The angle to compute the alignment offset for.
|
||||
|
||||
Returns:
|
||||
tuple: The alignment offset in x, y and z direction.
|
||||
"""
|
||||
tomo_alignment_fit = self.client.get_global_var("tomo_alignment_fit")
|
||||
if tomo_alignment_fit is None:
|
||||
print("Not applying any alignment offsets. No tomo alignment fit data available.\n")
|
||||
return (0, 0, 0)
|
||||
|
||||
# x amp, phase, offset, y amp, phase, offset
|
||||
# 0 0 0 1 0 2 1 0 1 1 1 2
|
||||
correction_x = (
|
||||
tomo_alignment_fit[0][0] * np.sin(np.radians(angle) + tomo_alignment_fit[0][1])
|
||||
+ tomo_alignment_fit[0][2]
|
||||
)
|
||||
correction_y = (
|
||||
tomo_alignment_fit[1][0] * np.sin(np.radians(angle) + tomo_alignment_fit[1][1])
|
||||
+ tomo_alignment_fit[1][2]
|
||||
+ tomo_alignment_fit[1][3] * np.sin(3 * np.radians(angle) + tomo_alignment_fit[1][4])
|
||||
)
|
||||
correction_z = tomo_alignment_fit[0][0] * np.sin(
|
||||
np.radians(angle + 90) + tomo_alignment_fit[0][1]
|
||||
)
|
||||
|
||||
print(
|
||||
f"Alignment offset x {correction_x}, y {correction_y}, z {correction_z} for angle"
|
||||
f" {angle}\n"
|
||||
)
|
||||
return (correction_x, correction_y, correction_z)
|
||||
|
||||
def _read_correction_file(self, correction_file: str):
|
||||
with open(correction_file, "r") as f:
|
||||
num_elements = f.readline()
|
||||
int_num_elements = int(num_elements.split(" ")[2])
|
||||
corr_pos = []
|
||||
corr_angle = []
|
||||
for j in range(int_num_elements * 2):
|
||||
line = f.readline()
|
||||
value = line.split(" ")[2]
|
||||
name = line.split(" ")[0].split("[")[0]
|
||||
if name == "corr_pos":
|
||||
corr_pos.append(float(value))
|
||||
elif name == "corr_angle":
|
||||
corr_angle.append(float(value))
|
||||
print(
|
||||
f"Loading default mirror correction from file {correction_file} containing {int_num_elements} elements."
|
||||
)
|
||||
# print(corr_pos)
|
||||
return corr_pos, corr_angle
|
||||
|
||||
def read_additional_correction_x(self, correction_file: str):
|
||||
self.corr_pos_x, self.corr_angle_x = self._read_correction_file(correction_file)
|
||||
|
||||
def read_additional_correction_y(self, correction_file: str):
|
||||
self.corr_pos_y, self.corr_angle_y = self._read_correction_file(correction_file)
|
||||
|
||||
def read_additional_correction_y_2(self, correction_file: str):
|
||||
self.corr_pos_y_2, self.corr_angle_y_2 = self._read_correction_file(correction_file)
|
||||
|
||||
def compute_additional_correction_x(self, angle):
|
||||
return self._compute_additional_correction(angle, iteration="x1")
|
||||
|
||||
def compute_additional_correction_y(self, angle):
|
||||
return self._compute_additional_correction(angle, iteration="y1")
|
||||
|
||||
def compute_additional_correction_y_2(self, angle):
|
||||
return self._compute_additional_correction(angle, iteration="y2")
|
||||
|
||||
def _compute_additional_correction(self, angle, iteration="y1"):
|
||||
if iteration == "x1":
|
||||
corr_pos = self.corr_pos_x
|
||||
corr_angle = self.corr_angle_x
|
||||
elif iteration == "y1":
|
||||
corr_pos = self.corr_pos_y
|
||||
corr_angle = self.corr_angle_y
|
||||
elif iteration == "y2":
|
||||
corr_pos = self.corr_pos_y_2
|
||||
corr_angle = self.corr_angle_y_2
|
||||
if not corr_pos:
|
||||
print(f"Not applying any additional correction {iteration}. No data available.\n")
|
||||
return 0
|
||||
|
||||
# find index of closest angle
|
||||
for j, _ in enumerate(corr_pos):
|
||||
newangledelta = np.fabs(corr_angle[j] - angle)
|
||||
if j == 0:
|
||||
angledelta = newangledelta
|
||||
additional_correction_shift = corr_pos[j]
|
||||
continue
|
||||
|
||||
if newangledelta < angledelta:
|
||||
additional_correction_shift = corr_pos[j]
|
||||
angledelta = newangledelta
|
||||
|
||||
if additional_correction_shift == 0 and angle > corr_angle[-1]:
|
||||
additional_correction_shift = corr_pos[-1]
|
||||
print(f"Additional correction shift {iteration}: {additional_correction_shift}")
|
||||
return additional_correction_shift
|
||||
@@ -1,153 +0,0 @@
|
||||
import time
|
||||
import numpy as np
|
||||
import sys
|
||||
import termios
|
||||
import tty
|
||||
import fcntl
|
||||
import os
|
||||
import builtins
|
||||
|
||||
from rich import box
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
|
||||
# from csaxs_bec.bec_ipython_client.plugins.cSAXS import epics_get, epics_put, fshopen, fshclose
|
||||
|
||||
if builtins.__dict__.get("bec") is not None:
|
||||
bec = builtins.__dict__.get("bec")
|
||||
dev = builtins.__dict__.get("dev")
|
||||
umv = builtins.__dict__.get("umv")
|
||||
umvr = builtins.__dict__.get("umvr")
|
||||
|
||||
|
||||
class OMNYToolsError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class OMNYTools:
|
||||
|
||||
HEADER = "\033[95m"
|
||||
OKBLUE = "\033[94m"
|
||||
OKCYAN = "\033[96m"
|
||||
OKGREEN = "\033[92m"
|
||||
WARNING = "\033[93m"
|
||||
FAIL = "\033[91m"
|
||||
ENDC = "\033[0m"
|
||||
BOLD = "\033[1m"
|
||||
UNDERLINE = "\033[4m"
|
||||
|
||||
def __init__(self, client) -> None:
|
||||
self.client = client
|
||||
|
||||
@staticmethod
|
||||
def _get_user_param_safe(device, var):
|
||||
param = dev[device].user_parameter
|
||||
if not param or param.get(var) is None:
|
||||
raise ValueError(f"Device {device} has no user parameter definition for {var}.")
|
||||
return param.get(var)
|
||||
|
||||
def printgreen(self, string: str):
|
||||
print(self.OKGREEN + string + self.ENDC)
|
||||
|
||||
def printgreenbold(self, string: str):
|
||||
print(self.BOLD + self.OKGREEN + string + self.ENDC)
|
||||
|
||||
def yesno(self, message: str, default="none", autoconfirm=0) -> bool:
|
||||
if autoconfirm and default == "y":
|
||||
self.printgreen(message + " Automatically confirming default: yes")
|
||||
return True
|
||||
elif autoconfirm and default == "n":
|
||||
self.printgreen(message + " Automatically confirming default: no")
|
||||
return False
|
||||
if default == "y":
|
||||
message_ending = " [Y]/n? "
|
||||
elif default == "n":
|
||||
message_ending = " y/[N]? "
|
||||
else:
|
||||
message_ending = " y/n? "
|
||||
while True:
|
||||
user_input = input(self.OKBLUE + message + message_ending + self.ENDC)
|
||||
if (
|
||||
user_input == "Y" or user_input == "y" or user_input == "yes" or user_input == "Yes"
|
||||
) or (default == "y" and user_input == ""):
|
||||
return True
|
||||
if (
|
||||
user_input == "N" or user_input == "n" or user_input == "no" or user_input == "No"
|
||||
) or (default == "n" and user_input == ""):
|
||||
return False
|
||||
else:
|
||||
print("Please expicitely confirm y or n.")
|
||||
|
||||
def tweak_cursor(
|
||||
self, dev1, step1: float, dev2="none", step2: float = "0", special_command="none"
|
||||
):
|
||||
if dev1 not in dev.enabled_devices:
|
||||
print(f"Device 1 {dev} is not in enabled devices.")
|
||||
return
|
||||
if dev2 not in dev.enabled_devices and dev2 != "none":
|
||||
print(f"Device 2 {dev} is not in enabled devices.")
|
||||
return
|
||||
# Save the current terminal settings
|
||||
fd = sys.stdin.fileno()
|
||||
old_term = termios.tcgetattr(fd)
|
||||
try:
|
||||
# Set the terminal to raw mode to capture single key presses
|
||||
tty.setraw(fd)
|
||||
# Set stdin to non-blocking mode
|
||||
old_flags = fcntl.fcntl(fd, fcntl.F_GETFL)
|
||||
fcntl.fcntl(fd, fcntl.F_SETFL, old_flags | os.O_NONBLOCK)
|
||||
print("Tweak Cursor." + self.BOLD + self.OKBLUE + "Press (q) to quit!\r" + self.ENDC)
|
||||
while True:
|
||||
try:
|
||||
# Read single character input
|
||||
key = sys.stdin.read(1)
|
||||
if key == "q":
|
||||
print("\n\rExiting tweak mode\r")
|
||||
break
|
||||
elif key == "\x1b": # Escape sequences for arrow keys
|
||||
next1, next2 = sys.stdin.read(2)
|
||||
if next1 == "[":
|
||||
if next2 == "A":
|
||||
# print("up")
|
||||
if dev2 != "none":
|
||||
umvr(dev2, step2)
|
||||
if special_command != "none":
|
||||
special_command()
|
||||
elif next2 == "B":
|
||||
# print(" down")
|
||||
if dev2 != "none":
|
||||
umvr(dev2, -step2)
|
||||
if special_command != "none":
|
||||
special_command()
|
||||
elif next2 == "C":
|
||||
# print("right")
|
||||
umvr(dev1, step1)
|
||||
if special_command != "none":
|
||||
special_command()
|
||||
elif next2 == "D":
|
||||
# print("left")
|
||||
umvr(dev1, -step1)
|
||||
if special_command != "none":
|
||||
special_command()
|
||||
|
||||
elif key == "+":
|
||||
step1 = step1 * 2
|
||||
if dev2 != "none":
|
||||
step2 = step2 * 2
|
||||
print(f"\rDouble step size. New step size: {step1}, {step2}\r")
|
||||
elif key == "-":
|
||||
step1 = step1 / 2
|
||||
if dev2 != "none":
|
||||
step2 = step2 / 2
|
||||
print(f"\rHalf step size. New step size: {step1}, {step2}\r")
|
||||
except IOError:
|
||||
# No input available, keep looping
|
||||
pass
|
||||
|
||||
# Sleep for a short period to avoid high CPU usage
|
||||
time.sleep(0.02)
|
||||
|
||||
finally:
|
||||
# Restore the terminal to its original state
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old_term)
|
||||
fcntl.fcntl(fd, fcntl.F_SETFL, old_flags)
|
||||
@@ -1,384 +0,0 @@
|
||||
import time
|
||||
import numpy as np
|
||||
|
||||
from rich import box
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
|
||||
from csaxs_bec.bec_ipython_client.plugins.cSAXS import epics_put, fshclose
|
||||
|
||||
|
||||
class OMNYError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class OMNYOpticsMixin:
|
||||
@staticmethod
|
||||
def _get_user_param_safe(device, var):
|
||||
param = dev[device].user_parameter
|
||||
if not param or param.get(var) is None:
|
||||
raise ValueError(f"Device {device} has no user parameter definition for {var}.")
|
||||
return param.get(var)
|
||||
|
||||
def ooptics_in(self):
|
||||
self.ofzp_in()
|
||||
# ocs_in
|
||||
self.oosa_in()
|
||||
|
||||
if "rtx" in dev and dev.rtx.enabled:
|
||||
dev.rtx.controller.feedback_enable()
|
||||
|
||||
self.align.update_frame()
|
||||
|
||||
user_input = input(
|
||||
"Is the direct beam gone on the xray eye? Do you see the cone of the FZP?"
|
||||
)
|
||||
if user_input == "y":
|
||||
printf("Next oeye_out...\n")
|
||||
else:
|
||||
raise OMNYError("Failed to properly move in the Xray optics")
|
||||
|
||||
def _oeyey_mv(self, position):
|
||||
# direction dependent speeds
|
||||
if dev.oeyez.get().readback < position:
|
||||
dev.oeyez.controller.socket_put_confirmed("axspeed[7]=15000")
|
||||
else:
|
||||
dev.oeyez.controller.socket_put_confirmed("axspeed[7]=10000")
|
||||
umv(dev.oeyey, position)
|
||||
dev.oeyez.controller.socket_put_confirmed("axspeed[7]=10000")
|
||||
|
||||
def oeye_out(self):
|
||||
fshclose()
|
||||
if self.OMNYTools.yesno("Did you move in the optics?"):
|
||||
umv(dev.oeyez, -2)
|
||||
self._oeyey_mv(-60.3)
|
||||
# free camera
|
||||
epics_put("XOMNYI-XEYE-ACQ:0", 2)
|
||||
else:
|
||||
raise OMNYError("The optics were not moved in. Please do so prior to eyey_out")
|
||||
self.OMNYTools.printgreen("Oeye is out.")
|
||||
|
||||
def oeye_cam_in(self):
|
||||
if dev.oeyez.get().readback < -80:
|
||||
umv(dev.oeyez, -50)
|
||||
|
||||
if np.fabs(dev.oeyey.get().readback + 4.8) > 0.1:
|
||||
self._oeyey_mv(-4.8)
|
||||
|
||||
if np.fabs(dev.oeyez.get().readback + 2) > 0.1 or np.fabs(dev.oeyex.get().readback) > 0.1:
|
||||
umv(dev.oeyez, -2, dev.oeyex, 0)
|
||||
# if still too close in z -- safety check
|
||||
if np.fabs(dev.oeyez.get().readback + 2) > 0.1:
|
||||
raise OMNYError("The oeye is too close in z for transfer. ERROR! Aborting.")
|
||||
self.OMNYTools.printgreen("Oeye is at cam position.")
|
||||
|
||||
def _oeye_xray_is_in(self) -> bool:
|
||||
omny_oeye_xray_inx = self._get_user_param_safe("oeyex", "xray_in")
|
||||
omny_oeye_xray_iny = self._get_user_param_safe("oeyey", "xray_in")
|
||||
omny_oeye_currentx = dev.oeyex.get().readback
|
||||
omny_oeye_currenty = dev.oeyey.get().readback
|
||||
|
||||
if (
|
||||
np.fabs(omny_oeye_currentx - omny_oeye_xray_inx) < 0.1
|
||||
and np.fabs(omny_oeye_currenty - omny_oeye_xray_iny) < 0.1
|
||||
):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def oeye_xray_in(self):
|
||||
if self._oeye_xray_is_in():
|
||||
pass
|
||||
else:
|
||||
# todo
|
||||
# self._otransfer_gripper_safe_xray_in_operation()
|
||||
# if(!_oshield_is_ST_closed())
|
||||
# {
|
||||
# printf("The shield of the sample stage is not closed. Aborting.\n")
|
||||
# exit
|
||||
# }
|
||||
omny_oeye_xray_inx = self._get_user_param_safe("oeyex", "xray_in")
|
||||
omny_oeye_xray_iny = self._get_user_param_safe("oeyey", "xray_in")
|
||||
omny_oeye_xray_inz = self._get_user_param_safe("oeyez", "xray_in")
|
||||
|
||||
self._oeyey_mv(omny_oeye_xray_iny)
|
||||
omny_oeye_currenty = dev.oeyey.get().readback
|
||||
if np.fabs(omny_oeye_currenty - omny_oeye_xray_iny) > 0.1:
|
||||
raise OMNYError("The oeye did not move up.\n")
|
||||
umv(dev.oeyex, omny_oeye_xray_inx, dev.oeyez, omny_oeye_xray_inz)
|
||||
self.OMNYTools.printgreen("Oeye is at X-ray position.")
|
||||
|
||||
# some notes for the vis microscope:
|
||||
# initial position for the vis light microscope
|
||||
# do not open the shield when the microscope is at the vis mic position
|
||||
# found eoeyx -45.13, z -84.9, y 0.64
|
||||
# for a samy position of 2.8 with delta off
|
||||
# the osa position should be in z around 7.4. in x it seems better
|
||||
# around -0.6, where potentially xrays dont pass anymore
|
||||
#
|
||||
|
||||
def _oosa_check_y(self):
|
||||
omny_oosa_currenty = dev.oosay.get().readback
|
||||
if np.fabs(omny_oosa_currenty - 0.9) > 0.05:
|
||||
umv(dev.oosay, 0.9)
|
||||
omny_oosa_currenty = dev.oosay.get().readback
|
||||
if np.fabs(omny_oosa_currenty - 0.9) > 0.05:
|
||||
raise OMNYError("oosay is not around 0.9. Aborting.")
|
||||
|
||||
def _oosa_to_move_corridor(self):
|
||||
self._oosa_check_y()
|
||||
dev.oosax.limits = [-3, 3.7] # risk collision with shield
|
||||
umv(dev.oosax, -2)
|
||||
dev.oosax.read(cached=False)
|
||||
omny_oosa_currentx = dev.oosax.get().readback
|
||||
if np.fabs(omny_oosa_currentx + 2) > 0.1:
|
||||
raise OMNYError("oosax did not reach target position. Not moving in z.\n")
|
||||
|
||||
def oosa_in(self):
|
||||
self._oosa_check_y()
|
||||
dev.oshield.read(cached=False)
|
||||
omny_oshield_current = dev.oshield.get().readback
|
||||
if omny_oshield_current < 15:
|
||||
self._oshield_ST_close()
|
||||
if self.near_field == False:
|
||||
x_in_pos = self._get_user_param_safe("oosax", "far_field_in")
|
||||
y_in_pos = self._get_user_param_safe("oosay", "far_field_in")
|
||||
z_in_pos = self._get_user_param_safe("oosaz", "far_field_in")
|
||||
print("OSA movement in far-field mode.")
|
||||
dev.oosaz.read(cached=False)
|
||||
omny_oosa_currentz = dev.oosaz.get().readback
|
||||
if omny_oosa_currentz < 6.4:
|
||||
self._oosa_to_move_corridor()
|
||||
dev.oosaz.limits = [6.4, 6.6]
|
||||
umv(dev.oosaz, z_in_pos)
|
||||
umv(dev.oosax, x_in_pos)
|
||||
umv(dev.oosay, y_in_pos)
|
||||
#### For the 30 nm FZP 220 um we use this part
|
||||
# umv oosaz 6.5
|
||||
# umv oosax 3.2453
|
||||
# umv oosay 0.386015
|
||||
|
||||
if self.near_field == True:
|
||||
x_in_pos = self._get_user_param_safe("oosax", "near_field_in")
|
||||
y_in_pos = self._get_user_param_safe("oosay", "near_field_in")
|
||||
z_in_pos = self._get_user_param_safe("oosaz", "near_field_in")
|
||||
print("OSA movement in near-field mode.")
|
||||
dev.oosaz.read(cached=False)
|
||||
omny_oosa_currentz = dev.oosaz.get().readback
|
||||
if omny_oosa_currentz > 0:
|
||||
self._oosa_to_move_corridor()
|
||||
dev.oosaz.limits = [-0.4, -0.6]
|
||||
umv(dev.oosaz, z_in_pos)
|
||||
umv(dev.oosax, x_in_pos)
|
||||
omny_osamy_current = dev.osamy.get().readback
|
||||
if omny_osamy_current < 3.25:
|
||||
umv(dev.oosay, y_in_pos)
|
||||
else:
|
||||
raise OMNYError("Failed to move oosa in. osamy position is too large.")
|
||||
|
||||
self.OMNYTools.printgreen("OSA is in.")
|
||||
|
||||
# todo
|
||||
# _omny_interferometer_align_tracking
|
||||
# rt_feedback_enable
|
||||
|
||||
def oosa_out(self):
|
||||
self._oosa_check_y()
|
||||
dev.oshield.read(cached=False)
|
||||
omny_oshield_current = dev.oshield.get().readback
|
||||
if omny_oshield_current < 15:
|
||||
self._oshield_ST_close()
|
||||
omny_oosaz_current = dev.oosaz.get().readback
|
||||
if self.near_field == False:
|
||||
print("OSA movement in far-field mode.")
|
||||
if omny_oosaz_current < 6.4:
|
||||
self._oosa_to_move_corridor()
|
||||
dev.oosaz.limits = [6.4, 6.6]
|
||||
umv(dev.oosaz, 6.5)
|
||||
umv(dev.oosax, -2)
|
||||
if self.near_field == True:
|
||||
print("OSA movement in near-field mode.")
|
||||
if omny_oosaz_current > 0:
|
||||
self._oosa_to_move_corridor()
|
||||
dev.oosaz.limits = [-0.4, -0.6]
|
||||
umv(dev.oosaz, -0.45)
|
||||
umv(dev.oosax, -2)
|
||||
# todo _omny_interferometer_align_tracking
|
||||
|
||||
self.OMNYTools.printgreen("OSA is out.")
|
||||
|
||||
def oosa_move_out_of_shield(self):
|
||||
# todo: _omnycam_samplestage
|
||||
self._oosa_check_y()
|
||||
self._oosa_to_move_corridor()
|
||||
omny_osamx_current = dev.osamx.get().readback
|
||||
if np.fabs(omny_osamx_current) > 0.2:
|
||||
umv(dev.osamx, 0)
|
||||
omny_oosaz_current = dev.oosaz.get().readback
|
||||
if omny_oosaz_current > 0.1:
|
||||
dev.oosaz.limits = [-0.1, 0.1]
|
||||
umv(dev.oosaz, 0)
|
||||
|
||||
self.OMNYTools.printgreen("OSA is out of shield.")
|
||||
|
||||
def ofzp_out(self):
|
||||
if "rtx" in dev and dev.rtx.enabled:
|
||||
dev.rtx.controller.feedback_disable()
|
||||
y_out_pos = self._get_user_param_safe("ofzpy", "out")
|
||||
if np.fabs(dev.ofzpy.get().readback - y_out_pos) > 0.02:
|
||||
umv(dev.ofzpy, y_out_pos)
|
||||
self.OMNYTools.printgreen("FZP at out position")
|
||||
|
||||
def ofzp_in(self):
|
||||
if "rtx" in dev and dev.rtx.enabled:
|
||||
dev.rtx.controller.feedback_disable()
|
||||
x_in_pos = self._get_user_param_safe("ofzpx", "in")
|
||||
y_in_pos = self._get_user_param_safe("ofzpy", "in")
|
||||
if np.fabs(dev.ofzpy.get().readback - y_in_pos) > 0.02:
|
||||
umv(dev.ofzpy, y_in_pos)
|
||||
|
||||
if np.fabs(dev.ofzpx.get().readback - x_in_pos) > 0.02:
|
||||
umv(dev.ofzpx, x_in_pos)
|
||||
self.OMNYTools.printgreen("FZP at in position")
|
||||
# 220 mu FZP at ofzpz 31.8025 for eiger probe (about 2.4 mm propagation after focus)
|
||||
# umv(dev.ofzpy, 0.7944)
|
||||
# if np.fabs(dev.ofzpx.get().readback+0.4317)>0.05:
|
||||
# umv(dev.ofzpx, -0.4317)
|
||||
# note the 220 fzp also works for near field 6.2 kev by just moving back osa and fzp
|
||||
# ofzpz 24.8 leads to a 9.5 mm propagation distance.
|
||||
# With the 220 mu FZP this gives 100 nm pixel recons
|
||||
# for the oosa macro set near_field=1
|
||||
# 170 mu FZP at 6.2 kev for large beam at ofzpz 31.8025 of about 58 mu diameter
|
||||
# 120 mu FZP at ofzpz 28.1991
|
||||
|
||||
# 250 mu FZP 60 nm at 5.65 keV
|
||||
# ofzpz 29.7 for propagation distance 2.2
|
||||
# umv ofzpx -0.4457
|
||||
# umv ofzpy 0.193630
|
||||
|
||||
# 150 um fzp, 60 nm, ofzpz 33.8 at 8.9 kev for propagation of 1.7 mm after focus
|
||||
# umv ofzpx -0.756678
|
||||
# umv ofzpy 0.193515
|
||||
|
||||
# 250 um 30 nm FZP upper right
|
||||
# small abberrations, seems to give good results in weak objects
|
||||
# ofzpx -0.609240
|
||||
# umv ofzpy 0.118265
|
||||
# 250 um 30 nm FZP lower right very aberated
|
||||
# ofzpx -0.881935
|
||||
# umv ofzpy 0.537050
|
||||
|
||||
# ofzpz 28.4027
|
||||
# 5.30 mm prop at 8.9 keV, 45 nm pixel in near field
|
||||
|
||||
# ofzpz 33.103
|
||||
# 0.6 mm prop at 8.9 kev far field 7 m flight tube at foptz
|
||||
|
||||
# ofzpz 49.4 is reachable just without interferometer swap
|
||||
# which at 6.2 keV and 250 um diam, 30 nm should gives a propagation of 0.8 after focus
|
||||
# and a beam size of 6 microns diamter
|
||||
###coordinates 30 nm FZP for comparing them
|
||||
# not sure if that is really correct
|
||||
# FZP 1 - FZP 2
|
||||
# FZP 5
|
||||
# FZP 4 - FZP 1
|
||||
|
||||
# FZP
|
||||
##upper right
|
||||
# umv ofzpx -0.6154 ofzpy 0.1183
|
||||
# umv ocsx -0.6070 ocsy 0.0540
|
||||
|
||||
# lower right
|
||||
# umv ofzpx -0.8341 ofzpy 0.5683
|
||||
# umv ocsx -0.3880 ocsy -0.3960
|
||||
|
||||
# lower left
|
||||
# umv ofzpx -0.3876 ofzpy 0.7902
|
||||
# umv ocsx -0.8380 ocsy -0.6180
|
||||
|
||||
# upper left
|
||||
# umv ofzpx -0.1678 ofzpy 0.3403
|
||||
# umv ocsx -1.0550 ocsy -0.1680
|
||||
|
||||
def ofzp_info(self, mokev_val=-1, ofzpz_val=-1):
|
||||
print(f"{ofzpz_val}")
|
||||
|
||||
if mokev_val == -1:
|
||||
try:
|
||||
mokev_val = dev.mokev.readback.get()
|
||||
except:
|
||||
print(
|
||||
"Device mokev does not exist. You can specify the energy in keV as an argument instead."
|
||||
)
|
||||
return
|
||||
if ofzpz_val == -1:
|
||||
ofzpz_val = dev.ofzpz.readback.get()
|
||||
distance = 66 + 2.4 + 31.8025 - ofzpz_val
|
||||
print(
|
||||
f"\nThe sample is in a distance of \033[1m{distance:.1f} mm\033[0m from the 60 nm FZP.\n"
|
||||
)
|
||||
print(f"At the current energy of {mokev_val:.4f} keV we have following options:\n")
|
||||
|
||||
diameters = [80e-6, 100e-6, 120e-6, 150e-6, 170e-6, 200e-6, 220e-6, 250e-6]
|
||||
|
||||
console = Console()
|
||||
table = Table(title="Outermost zone width \033[1m60 nm\033[0m", box=box.SQUARE)
|
||||
table.add_column("Diameter", justify="center")
|
||||
table.add_column("Focal distance", justify="center")
|
||||
table.add_column("Current beam size", justify="center")
|
||||
|
||||
wavelength = 1.2398e-9 / mokev_val
|
||||
|
||||
for diameter in diameters:
|
||||
outermost_zonewidth = 60e-9
|
||||
focal_distance = diameter * outermost_zonewidth / wavelength * 1000
|
||||
beam_size = -diameter / (focal_distance * 1000) * (focal_distance - distance) * 1e9
|
||||
table.add_row(
|
||||
f"{diameter*1e6:.2f} microns",
|
||||
f"{focal_distance:.2f} mm",
|
||||
f"{beam_size:.2f} microns",
|
||||
)
|
||||
|
||||
console.print(table)
|
||||
|
||||
# 30 nm with additional spacer
|
||||
distance = 53.84 + 0.6 + 33.1 - ofzpz_val
|
||||
print(
|
||||
f"\nThe sample is in a distance of \033[1m{distance:.1f} mm\033[0m from the 30 nm FZP.\n"
|
||||
)
|
||||
|
||||
diameters = [150e-6, 250e-6]
|
||||
|
||||
console = Console()
|
||||
table = Table(title="Outermost zone width \033[1m30 nm\033[0m", box=box.SQUARE)
|
||||
table.add_column("Diameter", justify="center")
|
||||
table.add_column("Focal distance", justify="center")
|
||||
table.add_column("Current beam size", justify="center")
|
||||
|
||||
wavelength = 1.2398e-9 / mokev_val
|
||||
|
||||
for diameter in diameters:
|
||||
outermost_zonewidth = 30e-9
|
||||
focal_distance = diameter * outermost_zonewidth / wavelength * 1000
|
||||
beam_size = -diameter / (focal_distance * 1000) * (focal_distance - distance) * 1e9
|
||||
table.add_row(
|
||||
f"{diameter*1e6:.2f} microns",
|
||||
f"{focal_distance:.2f} mm",
|
||||
f"{beam_size:.2f} microns",
|
||||
)
|
||||
|
||||
console.print(table)
|
||||
|
||||
print(
|
||||
"This function can be called with explicit energy and ofzpz position.\n Example: omny.ffzp_info(mokev_val=6.2, ofzpz_val=33.2)"
|
||||
)
|
||||
|
||||
# from flomni
|
||||
# oosaz_val = dev.oosaz.readback.get()
|
||||
|
||||
# print("\nOSA Information:")
|
||||
# print(f" Current fosaz {fosaz_val:.1f}")
|
||||
# print(
|
||||
# f" The OSA will collide with a normal OMNY pin at fosaz \033[1m{(33-fosaz_val):.1f}\033[0m"
|
||||
# )
|
||||
# print(f" Remaining space: \033[1m{-fosaz_val+(33-foptz_val):.1f}\033[0m")
|
||||
@@ -1,241 +0,0 @@
|
||||
import time
|
||||
import numpy as np
|
||||
import sys
|
||||
import termios
|
||||
import tty
|
||||
import fcntl
|
||||
import os
|
||||
|
||||
|
||||
from rich import box
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
|
||||
from csaxs_bec.bec_ipython_client.plugins.cSAXS import epics_get, epics_put, fshopen, fshclose
|
||||
|
||||
|
||||
class OMNY_rt_clientError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class OMNY_rt_client:
|
||||
def __init__(self):
|
||||
self.mirror_channel = -1
|
||||
self.mirror_amplitutde_increase = 0
|
||||
self.mirror_parameters = {}
|
||||
for j in range(1, 9):
|
||||
self.mirror_parameters[j] = dev.rtx.controller.get_mirror_parameters(j)
|
||||
|
||||
@staticmethod
|
||||
def _get_user_param_safe(device, var):
|
||||
param = dev[device].user_parameter
|
||||
if not param or param.get(var) is None:
|
||||
raise OMNY_rt_clientError(
|
||||
f"Device {device} has no user parameter definition for {var}."
|
||||
)
|
||||
return param.get(var)
|
||||
|
||||
def _omny_interferometer_openloop_steps(self, channel, steps, amplitude):
|
||||
dev.rtx.controller._omny_interferometer_openloop_steps(channel, steps, amplitude)
|
||||
|
||||
def interferometer_tweaking(self):
|
||||
self._tweak_interferometer()
|
||||
|
||||
def _tweak_interferometer(self):
|
||||
self.mirror_channel = -1
|
||||
|
||||
# Save the current terminal settings
|
||||
fd = sys.stdin.fileno()
|
||||
old_term = termios.tcgetattr(fd)
|
||||
|
||||
print("Ready to tweak the interferometer. Press q to quit.")
|
||||
print("The arrows adjust directions.")
|
||||
print("Numbers select the mirror aligner.")
|
||||
|
||||
try:
|
||||
# Set the terminal to raw mode to capture single key presses
|
||||
tty.setraw(fd)
|
||||
# Set stdin to non-blocking mode
|
||||
old_flags = fcntl.fcntl(fd, fcntl.F_GETFL)
|
||||
fcntl.fcntl(fd, fcntl.F_SETFL, old_flags | os.O_NONBLOCK)
|
||||
opt_mirrorname = "none"
|
||||
max = 0
|
||||
while True:
|
||||
try:
|
||||
# Read single character input
|
||||
key = sys.stdin.read(1)
|
||||
|
||||
if key == "q":
|
||||
self.mirror_amplitutde_increase = 0
|
||||
self.mirror_channel = -1
|
||||
print("\n\rExiting tweak mode\r")
|
||||
break
|
||||
elif key == "\x1b": # Escape sequences for arrow keys
|
||||
next1, next2 = sys.stdin.read(2)
|
||||
|
||||
if next1 == "[":
|
||||
printit = True
|
||||
if next2 == "A":
|
||||
# print("up")
|
||||
if self.mirror_channel != -1:
|
||||
self._omny_interferometer_openloop_steps(
|
||||
4,
|
||||
-self.mirror_parameters[self.mirror_channel][
|
||||
"opt_steps2_neg"
|
||||
],
|
||||
self.mirror_parameters[self.mirror_channel][
|
||||
"opt_amplitude2_neg"
|
||||
]
|
||||
+ self.mirror_amplitutde_increase,
|
||||
)
|
||||
elif next2 == "B":
|
||||
# print(" down")
|
||||
if self.mirror_channel != -1:
|
||||
self._omny_interferometer_openloop_steps(
|
||||
4,
|
||||
self.mirror_parameters[self.mirror_channel][
|
||||
"opt_steps2_pos"
|
||||
],
|
||||
self.mirror_parameters[self.mirror_channel][
|
||||
"opt_amplitude2_pos"
|
||||
]
|
||||
+ self.mirror_amplitutde_increase,
|
||||
)
|
||||
elif next2 == "C":
|
||||
# print("right")
|
||||
if self.mirror_channel != -1:
|
||||
self._omny_interferometer_openloop_steps(
|
||||
3,
|
||||
-self.mirror_parameters[self.mirror_channel][
|
||||
"opt_steps1_neg"
|
||||
],
|
||||
self.mirror_parameters[self.mirror_channel][
|
||||
"opt_amplitude1_neg"
|
||||
]
|
||||
+ self.mirror_amplitutde_increase,
|
||||
)
|
||||
elif next2 == "D":
|
||||
# print("left")
|
||||
if self.mirror_channel != -1:
|
||||
self._omny_interferometer_openloop_steps(
|
||||
3,
|
||||
self.mirror_parameters[self.mirror_channel][
|
||||
"opt_steps1_pos"
|
||||
],
|
||||
self.mirror_parameters[self.mirror_channel][
|
||||
"opt_amplitude1_pos"
|
||||
]
|
||||
+ self.mirror_amplitutde_increase,
|
||||
)
|
||||
elif key.isdigit() and 1 <= int(key) <= 8:
|
||||
self.mirror_channel = int(key)
|
||||
opt_mirrorname = self.mirror_parameters[self.mirror_channel][
|
||||
"opt_mirrorname"
|
||||
]
|
||||
autostop = self.mirror_parameters[self.mirror_channel]["opt_signal_stop"]
|
||||
averaging_time = self.mirror_parameters[self.mirror_channel][
|
||||
"opt_averaging_time"
|
||||
]
|
||||
print(
|
||||
f"\nSelected mirror channel {self.mirror_channel}: {opt_mirrorname}. Autostop {autostop}. Signal averaging time: {averaging_time}\r"
|
||||
)
|
||||
if int(key) == 6:
|
||||
dev.rtx.controller.laser_tracker_on()
|
||||
dev.rtx.controller._omny_interferometer_switch_channel(self.mirror_channel)
|
||||
max = 0
|
||||
printit = True
|
||||
elif key == "+":
|
||||
print("\nIncreasing voltage amplitudes by 100.\r")
|
||||
self.mirror_amplitutde_increase += 100
|
||||
elif key == "-":
|
||||
print("\nDecreasing voltage amplitudes by 100.\r")
|
||||
self.mirror_amplitutde_increase -= 100
|
||||
elif key == "a":
|
||||
if self.mirror_channel != -1:
|
||||
dev.rtx.controller._omny_interferometer_optimize(
|
||||
mirror_channel=self.mirror_channel, channel=3
|
||||
)
|
||||
dev.rtx.controller._omny_interferometer_optimize(
|
||||
mirror_channel=self.mirror_channel, channel=4
|
||||
)
|
||||
dev.rtx.controller._omny_interferometer_optimize(
|
||||
mirror_channel=self.mirror_channel, channel=3
|
||||
)
|
||||
dev.rtx.controller._omny_interferometer_optimize(
|
||||
mirror_channel=self.mirror_channel, channel=4
|
||||
)
|
||||
if self.mirror_channel != -1 and printit:
|
||||
printit = False
|
||||
signal = dev.rtx.controller._omny_interferometer_get_signalsample(
|
||||
self.mirror_parameters[self.mirror_channel]["opt_signalchannel"],
|
||||
self.mirror_parameters[self.mirror_channel]["opt_averaging_time"],
|
||||
)
|
||||
if signal > max:
|
||||
max = signal
|
||||
info_str = f"Channel {self.mirror_channel}, {opt_mirrorname}, Current signal: {signal:.0f}"
|
||||
filling = " " * (50 - len(info_str))
|
||||
# Calculate the number of filled and unfilled segments
|
||||
length = 30
|
||||
percentage = signal / max
|
||||
filled_length = int(length * percentage)
|
||||
unfilled_length = length - filled_length
|
||||
bar = "#" * filled_length + "-" * unfilled_length
|
||||
print(info_str + filling + "0 " + bar + f" {max:.0f} (q)uit\r", end="")
|
||||
|
||||
except IOError:
|
||||
# No input available, keep looping
|
||||
pass
|
||||
|
||||
# Sleep for a short period to avoid high CPU usage
|
||||
time.sleep(0.02)
|
||||
|
||||
finally:
|
||||
# Restore the terminal to its original state
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old_term)
|
||||
fcntl.fcntl(fd, fcntl.F_SETFL, old_flags)
|
||||
dev.rtx.controller._omny_interferometer_switch_alloff()
|
||||
self.mirror_channel = -1
|
||||
self.mirror_amplitutde_increase = 0
|
||||
dev.rtx.controller.show_signal_strength_interferometer()
|
||||
|
||||
def show_signal_strength_interferometer(self):
|
||||
dev.rtx.controller.show_signal_strength_interferometer()
|
||||
|
||||
def omny_interferometer_align_incoupling_angle(self):
|
||||
dev.rtx.controller.omny_interferometer_align_incoupling_angle()
|
||||
|
||||
def interferometer_tweak_otrack(self):
|
||||
self.OMNYTools.tweak_cursor(
|
||||
dev.otrackz,
|
||||
0.1,
|
||||
dev.otracky,
|
||||
0.1,
|
||||
special_command=dev.rtx.controller.laser_tracker_print_intensity_for_otrack_tweaking,
|
||||
)
|
||||
|
||||
def feedback_enable_with_reset(self):
|
||||
dev.rtx.controller.feedback_enable_with_reset()
|
||||
|
||||
def feedback_disable(self):
|
||||
dev.rtx.controller.feedback_disable()
|
||||
|
||||
def feedback_status(self):
|
||||
if dev.rtx.controller.feedback_is_running():
|
||||
print("Feedback is running.")
|
||||
else:
|
||||
print("Feedback is NOT running.")
|
||||
|
||||
def laser_tracker_on(self):
|
||||
dev.rtx.controller.laser_tracker_on()
|
||||
|
||||
def laser_tracker_off(self):
|
||||
dev.rtx.controller.laser_tracker_off()
|
||||
|
||||
def laser_tracker_show_all(self):
|
||||
dev.rtx.controller.laser_tracker_show_all()
|
||||
|
||||
def omny_interferometer_align_tracking(self):
|
||||
dev.rtx.controller.omny_interferometer_align_tracking()
|
||||
|
||||
def laser_tracker_check_and_wait_for_signalstrength(self):
|
||||
dev.rtx.controller.laser_tracker_check_and_wait_for_signalstrength()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,235 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import builtins
|
||||
import os
|
||||
import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from bec_lib import bec_logger
|
||||
|
||||
from csaxs_bec.bec_ipython_client.plugins.cSAXS import epics_get, epics_put, fshopen
|
||||
|
||||
logger = bec_logger.logger
|
||||
# import builtins to avoid linter errors
|
||||
bec = builtins.__dict__.get("bec")
|
||||
dev = builtins.__dict__.get("dev")
|
||||
umv = builtins.__dict__.get("umv")
|
||||
umvr = builtins.__dict__.get("umvr")
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bec_ipython_client.plugins.omny import OMNY
|
||||
|
||||
|
||||
class XrayEyeAlign:
|
||||
# pixel calibration, multiply to get mm
|
||||
PIXEL_CALIBRATION = 0.2 / 218 # .2 with binning
|
||||
|
||||
def __init__(self, client, omny: OMNY) -> None:
|
||||
self.client = client
|
||||
self.omny = omny
|
||||
self.device_manager = client.device_manager
|
||||
self.scans = client.scans
|
||||
self.alignment_values = {}
|
||||
self.omny.reset_correction()
|
||||
self.omny.reset_tomo_alignment_fit()
|
||||
|
||||
def _reset_init_values(self):
|
||||
self.shift_xy = [0, 0]
|
||||
self._xray_fov_xy = [0, 0]
|
||||
|
||||
def save_frame(self):
|
||||
epics_put("XOMNYI-XEYE-SAVFRAME:0", 1)
|
||||
|
||||
def update_frame(self):
|
||||
epics_put("XOMNYI-XEYE-ACQDONE:0", 0)
|
||||
# start live
|
||||
epics_put("XOMNYI-XEYE-ACQ:0", 1)
|
||||
# wait for start live
|
||||
while epics_get("XOMNYI-XEYE-ACQDONE:0") == 0:
|
||||
time.sleep(0.5)
|
||||
print("waiting for live view to start...")
|
||||
fshopen()
|
||||
|
||||
epics_put("XOMNYI-XEYE-ACQDONE:0", 0)
|
||||
|
||||
while epics_get("XOMNYI-XEYE-ACQDONE:0") == 0:
|
||||
print("waiting for new frame...")
|
||||
time.sleep(0.5)
|
||||
|
||||
time.sleep(0.5)
|
||||
# stop live view
|
||||
epics_put("XOMNYI-XEYE-ACQ:0", 0)
|
||||
time.sleep(1)
|
||||
# fshclose
|
||||
print("got new frame")
|
||||
|
||||
def tomo_rotate(self, val: float):
|
||||
# pylint: disable=undefined-variable
|
||||
umv(self.device_manager.devices.osamroy, val)
|
||||
|
||||
def get_tomo_angle(self):
|
||||
return self.device_manager.devices.osamroy.readback.get()
|
||||
|
||||
def update_fov(self, k: int):
|
||||
self._xray_fov_xy[0] = max(epics_get(f"XOMNYI-XEYE-XWIDTH_X:{k}"), self._xray_fov_xy[0])
|
||||
self._xray_fov_xy[1] = max(0, self._xray_fov_xy[0])
|
||||
|
||||
@property
|
||||
def movement_buttons_enabled(self):
|
||||
return [epics_get("XOMNYI-XEYE-ENAMVX:0"), epics_get("XOMNYI-XEYE-ENAMVY:0")]
|
||||
|
||||
@movement_buttons_enabled.setter
|
||||
def movement_buttons_enabled(self, enabled: bool):
|
||||
enabled = int(enabled)
|
||||
epics_put("XOMNYI-XEYE-ENAMVX:0", enabled)
|
||||
epics_put("XOMNYI-XEYE-ENAMVY:0", enabled)
|
||||
|
||||
def send_message(self, msg: str):
|
||||
epics_put("XOMNYI-XEYE-MESSAGE:0.DESC", msg)
|
||||
|
||||
def align(self):
|
||||
# reset shift xy and fov params
|
||||
self._reset_init_values()
|
||||
|
||||
self.tomo_rotate(0)
|
||||
epics_put("XOMNYI-XEYE-ANGLE:0", 0)
|
||||
|
||||
self.omny.oeye_xray_in()
|
||||
|
||||
self.omny.feedback_enable_with_reset()
|
||||
|
||||
# disable movement buttons
|
||||
self.movement_buttons_enabled = False
|
||||
|
||||
sample_name = dev.omny_samples.get_sample_name_in_samplestage()
|
||||
epics_put("XOMNYI-XEYE-SAMPLENAME:0.DESC", sample_name)
|
||||
|
||||
# this makes sure we are in a defined state
|
||||
self.omny.feedback_disable()
|
||||
|
||||
epics_put("XOMNYI-XEYE-PIXELSIZE:0", self.PIXEL_CALIBRATION)
|
||||
|
||||
osamx_in = self.omny.OMNYTools._get_user_param_safe("osamx", "in")
|
||||
umv(dev.osamx, osamx_in - 0.35)
|
||||
|
||||
self.omny.ofzp_in()
|
||||
self.update_frame()
|
||||
|
||||
# enable submit buttons
|
||||
self.movement_buttons_enabled = False
|
||||
epics_put("XOMNYI-XEYE-SUBMIT:0", 0)
|
||||
epics_put("XOMNYI-XEYE-STEP:0", 0)
|
||||
self.send_message("Submit center value of FZP.")
|
||||
|
||||
k = 0
|
||||
while True:
|
||||
if epics_get("XOMNYI-XEYE-SUBMIT:0") == 1:
|
||||
val_x = epics_get(f"XOMNYI-XEYE-XVAL_X:{k}") / 2 * self.PIXEL_CALIBRATION # in mm
|
||||
self.alignment_values[k] = val_x
|
||||
print(f"Clicked position {k}: x {self.alignment_values[k]}")
|
||||
rtx_position = dev.rtx.readback.get() / 1000
|
||||
print(f"Current rtx position {rtx_position}")
|
||||
self.alignment_values[k] -= rtx_position
|
||||
print(f"Corrected position {k}: x {self.alignment_values[k]}")
|
||||
|
||||
if k == 0: # received center value of FZP
|
||||
self.send_message("please wait ...")
|
||||
self.movement_buttons_enabled = False
|
||||
epics_put("XOMNYI-XEYE-SUBMIT:0", -1) # disable submit button
|
||||
|
||||
self.omny.feedback_disable()
|
||||
osamx_in = self.omny.OMNYTools._get_user_param_safe("osamx", "in")
|
||||
umv(dev.osamx, osamx_in)
|
||||
|
||||
self.omny.ofzp_out()
|
||||
|
||||
self.update_frame()
|
||||
epics_put("XOMNYI-XEYE-RECBG:0", 1)
|
||||
while epics_get("XOMNYI-XEYE-RECBG:0") == 1:
|
||||
time.sleep(0.5)
|
||||
print("waiting for background frame...")
|
||||
|
||||
umv(dev.osamx, osamx_in)
|
||||
time.sleep(0.5)
|
||||
self.omny.feedback_enable_with_reset()
|
||||
|
||||
self.update_frame()
|
||||
self.send_message("Adjust sample height and submit center")
|
||||
epics_put("XOMNYI-XEYE-SUBMIT:0", 0)
|
||||
self.movement_buttons_enabled = True
|
||||
|
||||
elif 1 <= k < 5: # received sample center value at samroy 0 ... 315
|
||||
self.send_message("please wait ...")
|
||||
epics_put("XOMNYI-XEYE-SUBMIT:0", -1)
|
||||
self.movement_buttons_enabled = False
|
||||
|
||||
umv(dev.rtx, 0)
|
||||
self.tomo_rotate(k * 45)
|
||||
epics_put("XOMNYI-XEYE-ANGLE:0", self.get_tomo_angle())
|
||||
self.update_frame()
|
||||
self.send_message("Submit sample center")
|
||||
epics_put("XOMNYI-XEYE-SUBMIT:0", 0)
|
||||
epics_put("XOMNYI-XEYE-ENAMVX:0", 1)
|
||||
self.update_fov(k)
|
||||
|
||||
elif k == 5: # received sample center value at samroy 270 and done
|
||||
self.send_message("done...")
|
||||
epics_put("XOMNYI-XEYE-SUBMIT:0", -1) # disable submit button
|
||||
self.movement_buttons_enabled = False
|
||||
self.update_fov(k)
|
||||
break
|
||||
|
||||
k += 1
|
||||
epics_put("XOMNYI-XEYE-STEP:0", k)
|
||||
|
||||
_xrayeyalignmvx = epics_get("XOMNYI-XEYE-MVX:0")
|
||||
if _xrayeyalignmvx != 0:
|
||||
umvr(dev.rtx, _xrayeyalignmvx)
|
||||
print(f"Current rtx position {dev.rtx.readback.get() / 1000}")
|
||||
epics_put("XOMNYI-XEYE-MVX:0", 0)
|
||||
if k > 0:
|
||||
epics_put(f"XOMNYI-XEYE-STAGEPOSX:{k}", dev.rtx.readback.get() / 1000)
|
||||
time.sleep(3)
|
||||
self.update_frame()
|
||||
|
||||
if k < 2:
|
||||
# allow movements, store movements to calculate center
|
||||
_xrayeyalignmvy = epics_get("XOMNYI-XEYE-MVY:0")
|
||||
if _xrayeyalignmvy != 0:
|
||||
self.omny.feedback_disable()
|
||||
umvr(dev.osamy, _xrayeyalignmvy / 1000)
|
||||
time.sleep(2)
|
||||
epics_put("XOMNYI-XEYE-MVY:0", 0)
|
||||
self.omny.feedback_enable_with_reset()
|
||||
self.update_frame()
|
||||
time.sleep(0.2)
|
||||
|
||||
self.write_output()
|
||||
fovx = self._xray_fov_xy[0] * self.PIXEL_CALIBRATION * 1000 / 2
|
||||
fovy = self._xray_fov_xy[1] * self.PIXEL_CALIBRATION * 1000 / 2
|
||||
|
||||
self.tomo_rotate(0)
|
||||
|
||||
umv(dev.rtx, 0)
|
||||
|
||||
# free camera
|
||||
epics_put("XOMNYI-XEYE-ACQ:0", 2)
|
||||
|
||||
print(
|
||||
f"The largest field of view from the xrayeyealign was \nfovx = {fovx:.0f} microns, fovy"
|
||||
f" = {fovy:.0f} microns"
|
||||
)
|
||||
print("Use the matlab routine to FIT the current alignment...")
|
||||
|
||||
print("Then LOAD ALIGNMENT PARAMETERS by running omny.read_alignment_offset()\n")
|
||||
|
||||
def write_output(self):
|
||||
file = os.path.expanduser("~/Data10/specES1/internal/xrayeye_alignmentvalues")
|
||||
if not os.path.exists(file):
|
||||
os.makedirs(os.path.dirname(file), exist_ok=True)
|
||||
with open(file, "w") as alignment_values_file:
|
||||
alignment_values_file.write("angle\thorizontal\n")
|
||||
for k in range(1, 6):
|
||||
fovx_offset = self.alignment_values[0] - self.alignment_values[k]
|
||||
print(f"Writing to file new alignment: number {k}, value x {fovx_offset}")
|
||||
alignment_values_file.write(f"{(k-1)*45}\t{fovx_offset*1000}\n")
|
||||
@@ -1,85 +0,0 @@
|
||||
"""
|
||||
Post startup script for the BEC client. This script is executed after the
|
||||
IPython shell is started. It is used to load the beamline specific
|
||||
information and to setup the prompts.
|
||||
|
||||
The script is executed in the global namespace of the IPython shell. This
|
||||
means that all variables defined here are available in the shell.
|
||||
|
||||
If needed, bec command-line arguments can be parsed here. For example, to
|
||||
parse the --session argument, add the following lines to the script:
|
||||
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--session", help="Session name", type=str, default="my_default_session")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.session == "my_session":
|
||||
print("Loading my_session session")
|
||||
from bec_plugins.bec_ipython_client.plugins.my_session import *
|
||||
else:
|
||||
print("Loading default session")
|
||||
from bec_plugins.bec_ipython_client.plugins.default_session import *
|
||||
"""
|
||||
|
||||
# pylint: disable=invalid-name, unused-import, import-error, undefined-variable, unused-variable, unused-argument, no-name-in-module
|
||||
|
||||
from bec_lib import bec_logger
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
logger.info("Using the cSAXS startup script.")
|
||||
|
||||
# pylint: disable=import-error
|
||||
_args = _main_dict["args"]
|
||||
|
||||
_session_name = "cSAXS"
|
||||
if _args.session.lower() == "lamni":
|
||||
from csaxs_bec.bec_ipython_client.plugins.cSAXS import *
|
||||
from csaxs_bec.bec_ipython_client.plugins.LamNI import *
|
||||
|
||||
_session_name = "LamNI"
|
||||
lamni = LamNI(bec)
|
||||
logger.success("LamNI session loaded.")
|
||||
|
||||
elif _args.session.lower() == "csaxs":
|
||||
print("Loading cSAXS session")
|
||||
from csaxs_bec.bec_ipython_client.plugins.cSAXS import *
|
||||
|
||||
logger.success("cSAXS session loaded.")
|
||||
|
||||
|
||||
# SETUP BEAMLINE INFO
|
||||
from bec_ipython_client.plugins.SLS.sls_info import OperatorInfo, SLSInfo
|
||||
|
||||
from csaxs_bec.bec_ipython_client.plugins.cSAXS.beamline_info import BeamlineInfo
|
||||
|
||||
bec._beamline_mixin._bl_info_register(BeamlineInfo)
|
||||
bec._beamline_mixin._bl_info_register(SLSInfo)
|
||||
bec._beamline_mixin._bl_info_register(OperatorInfo)
|
||||
|
||||
# SETUP PROMPTS
|
||||
bec._ip.prompts.username = _session_name
|
||||
bec._ip.prompts.status = 1
|
||||
|
||||
# REGISTER BEAMLINE CHECKS
|
||||
from bec_lib.bl_conditions import (
|
||||
FastOrbitFeedbackCondition,
|
||||
LightAvailableCondition,
|
||||
ShutterCondition,
|
||||
)
|
||||
|
||||
if "sls_machine_status" in dev:
|
||||
print("Registering light available condition for SLS machine status")
|
||||
_light_available_condition = LightAvailableCondition(dev.sls_machine_status)
|
||||
bec.bl_checks.register(_light_available_condition)
|
||||
|
||||
if "x12sa_es1_shutter_status" in dev:
|
||||
print("Registering shutter condition for X12SA ES1 shutter status")
|
||||
_shutter_condition = ShutterCondition(dev.x12sa_es1_shutter_status)
|
||||
bec.bl_checks.register(_shutter_condition)
|
||||
|
||||
# if hasattr(dev, "sls_fast_orbit_feedback"):
|
||||
# print("Registering fast orbit feedback condition for SLS fast orbit feedback")
|
||||
# _fast_orbit_feedback_condition = FastOrbitFeedbackCondition(dev.sls_fast_orbit_feedback)
|
||||
# bec.bl_checks.register(_fast_orbit_feedback_condition)
|
||||
@@ -1,21 +0,0 @@
|
||||
"""
|
||||
Pre-startup script for BEC client. This script is executed before the BEC client
|
||||
is started. It can be used to add additional command line arguments.
|
||||
"""
|
||||
|
||||
|
||||
def extend_command_line_args(parser):
|
||||
"""
|
||||
Extend the command line arguments of the BEC client.
|
||||
"""
|
||||
|
||||
parser.add_argument("--session", help="Session name", type=str, default="cSAXS")
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
# def get_config() -> ServiceConfig:
|
||||
# """
|
||||
# Create and return the service configuration.
|
||||
# """
|
||||
# return ServiceConfig(redis={"host": "localhost", "port": 6379})
|
||||
@@ -1,63 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from bec_widgets.widgets.containers.auto_update.auto_updates import AutoUpdates
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from bec_lib.messages import ScanStatusMessage
|
||||
|
||||
|
||||
class cSAXSUpdate(AutoUpdates):
|
||||
|
||||
#######################################################################
|
||||
################# GUI Callbacks #######################################
|
||||
#######################################################################
|
||||
|
||||
def on_start(self) -> None:
|
||||
"""
|
||||
Procedure to run when the auto updates are enabled.
|
||||
"""
|
||||
self.start_default_dock()
|
||||
|
||||
def on_stop(self) -> None:
|
||||
"""
|
||||
Procedure to run when the auto updates are disabled.
|
||||
"""
|
||||
|
||||
def on_scan_open(self, msg: ScanStatusMessage) -> None:
|
||||
"""
|
||||
Procedure to run when a scan starts.
|
||||
|
||||
Args:
|
||||
msg (ScanStatusMessage): The scan status message.
|
||||
"""
|
||||
if msg.scan_name == "line_scan" and msg.scan_report_devices:
|
||||
return self.simple_line_scan(msg)
|
||||
if msg.scan_name == "grid_scan" and msg.scan_report_devices:
|
||||
return self.simple_grid_scan(msg)
|
||||
if msg.scan_report_devices:
|
||||
return self.best_effort(msg)
|
||||
return None
|
||||
|
||||
def on_scan_closed(self, msg: ScanStatusMessage) -> None:
|
||||
"""
|
||||
Procedure to run when a scan ends.
|
||||
|
||||
Args:
|
||||
msg (ScanStatusMessage): The scan status message.
|
||||
"""
|
||||
|
||||
def on_scan_abort(self, msg: ScanStatusMessage) -> None:
|
||||
"""
|
||||
Procedure to run when a scan is aborted.
|
||||
|
||||
Args:
|
||||
msg (ScanStatusMessage): The scan status message.
|
||||
"""
|
||||
|
||||
|
||||
class cSAXSUpdateAlignment(AutoUpdates): ...
|
||||
|
||||
|
||||
class cSAXSUpdateScan(AutoUpdates): ...
|
||||
@@ -1,75 +0,0 @@
|
||||
# This file was automatically generated by generate_cli.py
|
||||
# type: ignore
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from bec_lib.logger import bec_logger
|
||||
|
||||
from bec_widgets.cli.rpc.rpc_base import RPCBase, rpc_call
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
# pylint: skip-file
|
||||
|
||||
|
||||
_Widgets = {
|
||||
"OmnyAlignment": "OmnyAlignment",
|
||||
}
|
||||
|
||||
|
||||
class OmnyAlignment(RPCBase):
|
||||
@property
|
||||
@rpc_call
|
||||
def enable_live_view(self):
|
||||
"""
|
||||
None
|
||||
"""
|
||||
|
||||
@enable_live_view.setter
|
||||
@rpc_call
|
||||
def enable_live_view(self):
|
||||
"""
|
||||
None
|
||||
"""
|
||||
|
||||
@property
|
||||
@rpc_call
|
||||
def user_message(self):
|
||||
"""
|
||||
None
|
||||
"""
|
||||
|
||||
@user_message.setter
|
||||
@rpc_call
|
||||
def user_message(self):
|
||||
"""
|
||||
None
|
||||
"""
|
||||
|
||||
@property
|
||||
@rpc_call
|
||||
def sample_name(self):
|
||||
"""
|
||||
None
|
||||
"""
|
||||
|
||||
@sample_name.setter
|
||||
@rpc_call
|
||||
def sample_name(self):
|
||||
"""
|
||||
None
|
||||
"""
|
||||
|
||||
@property
|
||||
@rpc_call
|
||||
def enable_move_buttons(self):
|
||||
"""
|
||||
None
|
||||
"""
|
||||
|
||||
@enable_move_buttons.setter
|
||||
@rpc_call
|
||||
def enable_move_buttons(self):
|
||||
"""
|
||||
None
|
||||
"""
|
||||
@@ -1,139 +0,0 @@
|
||||
|
||||
|
||||
from typing import TypedDict
|
||||
from bec_widgets.utils.error_popups import SafeSlot
|
||||
import os
|
||||
from bec_widgets.utils.bec_widget import BECWidget
|
||||
from bec_widgets.utils.ui_loader import UILoader
|
||||
from qtpy.QtWidgets import QWidget, QPushButton, QLineEdit, QLabel, QVBoxLayout
|
||||
from bec_qthemes import material_icon
|
||||
from bec_lib.logger import bec_logger
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
|
||||
# class OmnyAlignmentUIComponents(TypedDict):
|
||||
# moveRightButton: QPushButton
|
||||
# moveLeftButton: QPushButton
|
||||
# moveUpButton: QPushButton
|
||||
# moveDownButton: QPushButton
|
||||
# image: Image
|
||||
|
||||
|
||||
class OmnyAlignment(BECWidget, QWidget):
|
||||
USER_ACCESS = ["enable_live_view", "enable_live_view.setter", "user_message", "user_message.setter","sample_name", "sample_name.setter", "enable_move_buttons", "enable_move_buttons.setter"]
|
||||
PLUGIN = True
|
||||
ui_file = "./omny_alignment.ui"
|
||||
|
||||
def __init__(self, parent=None, **kwargs):
|
||||
super().__init__(parent=parent, **kwargs)
|
||||
|
||||
self._load_ui()
|
||||
|
||||
def _load_ui(self):
|
||||
current_path = os.path.dirname(__file__)
|
||||
self.ui = UILoader(self).loader(os.path.join(current_path, self.ui_file))
|
||||
layout = QVBoxLayout()
|
||||
layout.addWidget(self.ui)
|
||||
self.setLayout(layout)
|
||||
|
||||
icon_options = {"size": (16, 16), "convert_to_pixmap": False}
|
||||
self.ui.moveRightButton.setText("")
|
||||
self.ui.moveRightButton.setIcon(
|
||||
material_icon(icon_name="keyboard_arrow_right", **icon_options)
|
||||
)
|
||||
|
||||
self.ui.moveLeftButton.setText("")
|
||||
self.ui.moveLeftButton.setIcon(
|
||||
material_icon(icon_name="keyboard_arrow_left", **icon_options)
|
||||
)
|
||||
|
||||
self.ui.moveUpButton.setText("")
|
||||
self.ui.moveUpButton.setIcon(
|
||||
material_icon(icon_name="keyboard_arrow_up", **icon_options)
|
||||
)
|
||||
|
||||
self.ui.moveDownButton.setText("")
|
||||
self.ui.moveDownButton.setIcon(
|
||||
material_icon(icon_name="keyboard_arrow_down", **icon_options)
|
||||
)
|
||||
|
||||
self.ui.confirmButton.setText("OK")
|
||||
|
||||
|
||||
self.ui.liveViewSwitch.enabled.connect(self.on_live_view_enabled)
|
||||
|
||||
|
||||
@property
|
||||
def enable_live_view(self):
|
||||
return self.ui.liveViewSwitch.checked
|
||||
|
||||
@enable_live_view.setter
|
||||
def enable_live_view(self, enable:bool):
|
||||
self.ui.liveViewSwitch.checked = enable
|
||||
|
||||
|
||||
@property
|
||||
def user_message(self):
|
||||
return self.ui.messageLineEdit.text()
|
||||
|
||||
@user_message.setter
|
||||
def user_message(self, message:str):
|
||||
self.ui.messageLineEdit.setText(message)
|
||||
|
||||
@property
|
||||
def sample_name(self):
|
||||
return self.ui.sampleLineEdit.text()
|
||||
|
||||
@sample_name.setter
|
||||
def sample_name(self, message:str):
|
||||
self.ui.sampleLineEdit.setText(message)
|
||||
|
||||
|
||||
@SafeSlot(bool)
|
||||
def on_live_view_enabled(self, enabled:bool):
|
||||
from bec_widgets.widgets.plots.image.image import Image
|
||||
logger.info(f"Live view is enabled: {enabled}")
|
||||
image: Image = self.ui.image
|
||||
if enabled:
|
||||
image.image("cam200")
|
||||
return
|
||||
|
||||
image.disconnect_monitor("cam200")
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def enable_move_buttons(self):
|
||||
move_up:QPushButton = self.ui.moveUpButton
|
||||
move_down:QPushButton = self.ui.moveDownButton
|
||||
move_left:QPushButton = self.ui.moveLeftButton
|
||||
move_right:QPushButton = self.ui.moveRightButton
|
||||
return move_up.isEnabled() and move_down.isEnabled() and move_left.isEnabled() and move_right.isEnabled()
|
||||
|
||||
@enable_move_buttons.setter
|
||||
def enable_move_buttons(self, enabled:bool):
|
||||
move_up:QPushButton = self.ui.moveUpButton
|
||||
move_down:QPushButton = self.ui.moveDownButton
|
||||
move_left:QPushButton = self.ui.moveLeftButton
|
||||
move_right:QPushButton = self.ui.moveRightButton
|
||||
|
||||
move_up.setEnabled(enabled)
|
||||
move_down.setEnabled(enabled)
|
||||
move_left.setEnabled(enabled)
|
||||
move_right.setEnabled(enabled)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from qtpy.QtWidgets import QApplication
|
||||
import sys
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
widget = OmnyAlignment()
|
||||
|
||||
widget.show()
|
||||
sys.exit(app.exec_())
|
||||
@@ -1 +0,0 @@
|
||||
{'files': ['omny_alignment.py']}
|
||||
@@ -1,125 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Form</class>
|
||||
<widget class="QWidget" name="Form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>988</width>
|
||||
<height>821</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="2" column="2">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="moveRightButton">
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="moveLeftButton">
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="moveUpButton">
|
||||
<property name="text">
|
||||
<string>Up</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QPushButton" name="moveDownButton">
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="confirmButton">
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="sampleLineEdit"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="messageLineEdit"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Sample</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Message</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="3">
|
||||
<widget class="Image" name="image">
|
||||
<property name="enable_toolbar" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="inner_axes" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="monitor" stdset="0">
|
||||
<string>cam200</string>
|
||||
</property>
|
||||
<property name="rotation" stdset="0">
|
||||
<number>3</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="ToggleSwitch" name="liveViewSwitch"/>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Live View</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Image</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>image</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ToggleSwitch</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>toggle_switch</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,54 +0,0 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
||||
|
||||
from bec_widgets.utils.bec_designer import designer_material_icon
|
||||
from csaxs_bec.bec_widgets.widgets.omny_alignment.omny_alignment import OmnyAlignment
|
||||
|
||||
DOM_XML = """
|
||||
<ui language='c++'>
|
||||
<widget class='OmnyAlignment' name='omny_alignment'>
|
||||
</widget>
|
||||
</ui>
|
||||
"""
|
||||
|
||||
|
||||
class OmnyAlignmentPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._form_editor = None
|
||||
|
||||
def createWidget(self, parent):
|
||||
t = OmnyAlignment(parent)
|
||||
return t
|
||||
|
||||
def domXml(self):
|
||||
return DOM_XML
|
||||
|
||||
def group(self):
|
||||
return ""
|
||||
|
||||
def icon(self):
|
||||
return designer_material_icon(OmnyAlignment.ICON_NAME)
|
||||
|
||||
def includeFile(self):
|
||||
return "omny_alignment"
|
||||
|
||||
def initialize(self, form_editor):
|
||||
self._form_editor = form_editor
|
||||
|
||||
def isContainer(self):
|
||||
return False
|
||||
|
||||
def isInitialized(self):
|
||||
return self._form_editor is not None
|
||||
|
||||
def name(self):
|
||||
return "OmnyAlignment"
|
||||
|
||||
def toolTip(self):
|
||||
return "OmnyAlignment"
|
||||
|
||||
def whatsThis(self):
|
||||
return self.toolTip()
|
||||
@@ -1,15 +0,0 @@
|
||||
def main(): # pragma: no cover
|
||||
from qtpy import PYSIDE6
|
||||
|
||||
if not PYSIDE6:
|
||||
print("PYSIDE6 is not available in the environment. Cannot patch designer.")
|
||||
return
|
||||
from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
|
||||
|
||||
from csaxs_bec.bec_widgets.widgets.omny_alignment.omny_alignment_plugin import OmnyAlignmentPlugin
|
||||
|
||||
QPyDesignerCustomWidgetCollection.addCustomWidget(OmnyAlignmentPlugin())
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
main()
|
||||
@@ -1,11 +0,0 @@
|
||||
import os
|
||||
|
||||
|
||||
def setup_epics_ca():
|
||||
# os.environ["EPICS_CA_AUTO_ADDR_LIST"] = "NO"
|
||||
# os.environ["EPICS_CA_ADDR_LIST"] = "129.129.122.255 sls-x12sa-cagw.psi.ch:5836"
|
||||
os.environ["PYTHONIOENCODING"] = "latin1"
|
||||
|
||||
|
||||
def run():
|
||||
setup_epics_ca()
|
||||
@@ -1,295 +0,0 @@
|
||||
# This configuration file was used for the cSAXS beamtimes in September 2023
|
||||
##################################################
|
||||
#############Config for cSAXS SAXS imaging########
|
||||
##################################################
|
||||
|
||||
bpm4i:
|
||||
description: 'XBPM 4: integrated counts'
|
||||
deviceClass: ophyd.EpicsSignalRO
|
||||
deviceConfig:
|
||||
read_pv: X12SA-OP1-SCALER.
|
||||
deviceTags:
|
||||
- monitor
|
||||
enabled: true
|
||||
readOnly: false
|
||||
onFailure: buffer
|
||||
readoutPriority: baseline
|
||||
softwareTrigger: false
|
||||
mokev:
|
||||
description: Monochromator energy in keV
|
||||
deviceClass: csaxs_bec.devices.epics.specMotors.EnergyKev
|
||||
deviceConfig:
|
||||
read_pv: X12SA-OP-MO:ROX2
|
||||
deviceTags:
|
||||
- monitor
|
||||
enabled: true
|
||||
readOnly: false
|
||||
onFailure: buffer
|
||||
readoutPriority: baseline
|
||||
softwareTrigger: false
|
||||
mcs:
|
||||
description: Mcs scalar card for transmission readout
|
||||
deviceClass: csaxs_bec.devices.epics.mcs_csaxs.MCScSAXS
|
||||
deviceConfig:
|
||||
prefix: 'X12SA-MCS:'
|
||||
mcs_config:
|
||||
num_lines: 1
|
||||
deviceTags:
|
||||
- cSAXS
|
||||
- mcs
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readoutPriority: monitored
|
||||
softwareTrigger: false
|
||||
eiger9m:
|
||||
description: Eiger9m HPC area detector 9M
|
||||
deviceClass: csaxs_bec.devices.epics.eiger9m_csaxs.Eiger9McSAXS
|
||||
deviceConfig:
|
||||
prefix: 'X12SA-ES-EIGER9M:'
|
||||
deviceTags:
|
||||
- cSAXS
|
||||
- eiger9m
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readoutPriority: async
|
||||
softwareTrigger: false
|
||||
ddg_detectors:
|
||||
description: DelayGenerator for detector triggering
|
||||
deviceClass: csaxs_bec.devices.epics.delay_generator_csaxs.DelayGeneratorcSAXS
|
||||
deviceConfig:
|
||||
prefix: 'delaygen:DG1:'
|
||||
ddg_config:
|
||||
delay_burst: 40.e-3
|
||||
delta_width: 0
|
||||
additional_triggers: 0
|
||||
polarity:
|
||||
- 1 # T0 -> DDG MCS
|
||||
- 0 # eiger
|
||||
- 1 # falcon
|
||||
- 1
|
||||
- 1
|
||||
amplitude: 4.5
|
||||
offset: 0
|
||||
thres_trig_level: 2.5
|
||||
set_high_on_exposure: False
|
||||
set_high_on_stage: False
|
||||
deviceTags:
|
||||
- cSAXS
|
||||
- ddg_detectors
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readoutPriority: async
|
||||
softwareTrigger: false
|
||||
ddg_mcs:
|
||||
description: DelayGenerator for mcs triggering
|
||||
deviceClass: csaxs_bec.devices.epics.delay_generator_csaxs.DelayGeneratorcSAXS
|
||||
deviceConfig:
|
||||
prefix: 'delaygen:DG2:'
|
||||
ddg_config:
|
||||
delay_burst: 0
|
||||
delta_width: 0
|
||||
additional_triggers: 1
|
||||
polarity:
|
||||
- 1
|
||||
- 0
|
||||
- 1
|
||||
- 1
|
||||
- 1
|
||||
amplitude: 4.5
|
||||
offset: 0
|
||||
thres_trig_level: 2.5
|
||||
set_high_on_exposure: False
|
||||
set_high_on_stage: False
|
||||
set_trigger_source: EXT_RISING_EDGE
|
||||
trigger_width: 3.e-3
|
||||
deviceTags:
|
||||
- cSAXS
|
||||
- ddg_mcs
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readoutPriority: async
|
||||
softwareTrigger: false
|
||||
ddg_fsh:
|
||||
description: DelayGenerator for fast shutter control
|
||||
deviceClass: csaxs_bec.devices.epics.delay_generator_csaxs.DelayGeneratorcSAXS
|
||||
deviceConfig:
|
||||
prefix: 'delaygen:DG3:'
|
||||
ddg_config:
|
||||
delay_burst: 0
|
||||
delta_width: 80.e-3
|
||||
additional_triggers: 0
|
||||
polarity:
|
||||
- 1
|
||||
- 1
|
||||
- 1
|
||||
- 1
|
||||
- 1
|
||||
amplitude: 4.5
|
||||
offset: 0
|
||||
thres_trig_level: 2.5
|
||||
set_high_on_exposure: True
|
||||
set_high_on_stage: False
|
||||
deviceTags:
|
||||
- cSAXS
|
||||
- ddg_fsh
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readoutPriority: async
|
||||
softwareTrigger: false
|
||||
falcon:
|
||||
description: Falcon detector x-ray fluoresence
|
||||
deviceClass: csaxs_bec.devices.epics.falcon_csaxs.FalconcSAXS
|
||||
deviceConfig:
|
||||
prefix: 'X12SA-SITORO:'
|
||||
deviceTags:
|
||||
- cSAXS
|
||||
- falcon
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readoutPriority: async
|
||||
softwareTrigger: false
|
||||
pilatus_2:
|
||||
description: Pilatus2 HPC area detector 300k
|
||||
deviceClass: csaxs_bec.devices.epics.pilatus_csaxs.PilatuscSAXS
|
||||
deviceConfig:
|
||||
prefix: 'X12SA-ES-PILATUS300K:'
|
||||
deviceTags:
|
||||
- cSAXS
|
||||
- pilatus_2
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readoutPriority: async
|
||||
softwareTrigger: false
|
||||
samx:
|
||||
description: SGalil motor stage
|
||||
deviceClass: csaxs_bec.devices.omny.galil.SGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: "E"
|
||||
host: '129.129.122.26'
|
||||
port: 23
|
||||
sign: -1
|
||||
limits:
|
||||
- -181
|
||||
- -0.1
|
||||
deviceTags:
|
||||
- cSAXS
|
||||
- sgalil
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readoutPriority: baseline
|
||||
softwareTrigger: false
|
||||
samy:
|
||||
description: SGalil motor stage
|
||||
deviceClass: csaxs_bec.devices.omny.galil.SGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: "C"
|
||||
host: '129.129.122.26'
|
||||
port: 23
|
||||
sign: -1
|
||||
limits:
|
||||
- -66
|
||||
- -12
|
||||
deviceTags:
|
||||
- cSAXS
|
||||
- sgalil
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readoutPriority: baseline
|
||||
softwareTrigger: false
|
||||
micfoc:
|
||||
description: Focusing motor of Microscope stage
|
||||
deviceClass: ophyd_devices.devices.EpicsMotorEx
|
||||
deviceConfig:
|
||||
prefix: X12SA-ES2-ES06
|
||||
motor_resolution: 0.00125
|
||||
base_velocity: 0.25
|
||||
velocity: 2.5
|
||||
backlash_distance: 0.125
|
||||
acceleration: 0.4
|
||||
user_offset_dir: 0
|
||||
deviceTags:
|
||||
- cSAXS
|
||||
- micfoc
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readoutPriority: baseline
|
||||
softwareTrigger: false
|
||||
owis_samx:
|
||||
description: Owis motor stage samx
|
||||
deviceClass: ophyd_devices.devices.EpicsMotorEx
|
||||
deviceConfig:
|
||||
prefix: X12SA-ES2-ES01
|
||||
motor_resolution: 0.00125
|
||||
base_velocity: 0.0625
|
||||
velocity: 10
|
||||
backlash_distance: 0.125
|
||||
acceleration: 0.2
|
||||
user_offset_dir: 0
|
||||
deviceTags:
|
||||
- cSAXS
|
||||
- owis_samx
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readoutPriority: baseline
|
||||
softwareTrigger: false
|
||||
owis_samy:
|
||||
description: Owis motor stage samx
|
||||
deviceClass: ophyd_devices.devices.EpicsMotorEx
|
||||
deviceConfig:
|
||||
prefix: X12SA-ES2-ES02
|
||||
motor_resolution: 0.00125
|
||||
base_velocity: 0.0625
|
||||
velocity: 10
|
||||
backlash_distance: 0.125
|
||||
acceleration: 0.2
|
||||
user_offset_dir: 0
|
||||
deviceTags:
|
||||
- cSAXS
|
||||
- owis_samx
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readoutPriority: baseline
|
||||
softwareTrigger: false
|
||||
rotx:
|
||||
description: Rotation stage rotx
|
||||
deviceClass: ophyd_devices.devices.EpicsMotorEx
|
||||
deviceConfig:
|
||||
prefix: X12SA-ES2-ES05
|
||||
motor_resolution: 0.0025
|
||||
base_velocity: 0.5
|
||||
velocity: 7.5
|
||||
backlash_distance: 0.25
|
||||
acceleration: 0.2
|
||||
user_offset_dir: 1
|
||||
limits:
|
||||
- -0.1
|
||||
- 0.1
|
||||
deviceTags:
|
||||
- cSAXS
|
||||
- rotx
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readoutPriority: baseline
|
||||
softwareTrigger: false
|
||||
roty:
|
||||
description: Rotation stage rotx
|
||||
deviceClass: ophyd_devices.devices.EpicsMotorEx
|
||||
deviceConfig:
|
||||
prefix: X12SA-ES2-ES04
|
||||
motor_resolution: 0.0025
|
||||
base_velocity: 0.5
|
||||
velocity: 7.5
|
||||
backlash_distance: 0.25
|
||||
acceleration: 0.2
|
||||
user_offset_dir: 1
|
||||
limits:
|
||||
- -0.1
|
||||
- 0.1
|
||||
deviceTags:
|
||||
- cSAXS
|
||||
- rotx
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readoutPriority: baseline
|
||||
softwareTrigger: false
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,50 +0,0 @@
|
||||
ddg_detectors:
|
||||
description: DelayGenerator for detector triggering
|
||||
deviceClass: csaxs_bec.devices.epics.delay_generator_csaxs.DelayGeneratorcSAXS
|
||||
deviceConfig:
|
||||
prefix: 'X12SA-CPCL-DDG3:'
|
||||
ddg_config:
|
||||
delay_burst: 40.e-3
|
||||
delta_width: 0
|
||||
additional_triggers: 0
|
||||
polarity:
|
||||
- 1 # T0 -> DDG MCS
|
||||
- 0 # eiger
|
||||
- 1 # falcon
|
||||
- 1
|
||||
- 1
|
||||
amplitude: 4.5
|
||||
offset: 0
|
||||
thres_trig_level: 2.5
|
||||
set_high_on_exposure: False
|
||||
set_high_on_stage: False
|
||||
deviceTags:
|
||||
- cSAXS
|
||||
- ddg_detectors
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readoutPriority: async
|
||||
softwareTrigger: True
|
||||
bpm4i:
|
||||
readoutPriority: monitored
|
||||
deviceClass: ophyd_devices.SimMonitor
|
||||
deviceConfig:
|
||||
deviceTags:
|
||||
- beamline
|
||||
enabled: true
|
||||
readOnly: false
|
||||
samx:
|
||||
readoutPriority: baseline
|
||||
deviceClass: ophyd_devices.SimPositioner
|
||||
deviceConfig:
|
||||
delay: 1
|
||||
limits:
|
||||
- -50
|
||||
- 50
|
||||
tolerance: 0.01
|
||||
update_frequency: 400
|
||||
deviceTags:
|
||||
- user motors
|
||||
enabled: true
|
||||
readOnly: false
|
||||
|
||||
@@ -1,364 +0,0 @@
|
||||
############################################################
|
||||
#################### flOMNI Galil motors ###################
|
||||
############################################################
|
||||
|
||||
feyex:
|
||||
description: Xray eye X
|
||||
deviceClass: csaxs_bec.devices.omny.galil.fgalil_ophyd.FlomniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: D
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- -30
|
||||
- -1
|
||||
port: 8082
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: -16.267
|
||||
out: -1
|
||||
feyey:
|
||||
description: Xray eye Y
|
||||
deviceClass: csaxs_bec.devices.omny.galil.fgalil_ophyd.FlomniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: E
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- -1
|
||||
- -10
|
||||
port: 8082
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: -10.467
|
||||
fheater:
|
||||
description: Heater Y
|
||||
deviceClass: csaxs_bec.devices.omny.galil.fgalil_ophyd.FlomniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: C
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- -15
|
||||
- 0
|
||||
port: 8082
|
||||
sign: -1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
foptx:
|
||||
description: Optics X
|
||||
deviceClass: csaxs_bec.devices.omny.galil.fgalil_ophyd.FlomniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: B
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- -17
|
||||
- -12
|
||||
port: 8082
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: true
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: -13.761
|
||||
fopty:
|
||||
description: Optics Y
|
||||
deviceClass: csaxs_bec.devices.omny.galil.fgalil_ophyd.FlomniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: F
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 4
|
||||
port: 8082
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: true
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 0.552
|
||||
out: 0.752
|
||||
foptz:
|
||||
description: Optics Z
|
||||
deviceClass: csaxs_bec.devices.omny.galil.fgalil_ophyd.FlomniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: A
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 27
|
||||
port: 8082
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 23
|
||||
fsamroy:
|
||||
description: Sample rotation
|
||||
deviceClass: csaxs_bec.devices.omny.galil.fupr_ophyd.FuprGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: A
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- -5
|
||||
- 365
|
||||
port: 8084
|
||||
sign: -1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
fsamx:
|
||||
description: Sample coarse X
|
||||
deviceClass: csaxs_bec.devices.omny.galil.fgalil_ophyd.FlomniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: E
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- -162
|
||||
- 0
|
||||
port: 8081
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: true
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: -1.1
|
||||
fsamy:
|
||||
description: Sample coarse Y
|
||||
deviceClass: csaxs_bec.devices.omny.galil.fgalil_ophyd.FlomniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: F
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- 2
|
||||
- 3.1
|
||||
port: 8081
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: true
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 2.75
|
||||
ftracky:
|
||||
description: Laser Tracker coarse Y
|
||||
deviceClass: csaxs_bec.devices.omny.galil.fgalil_ophyd.FlomniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: H
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- 2.2
|
||||
- 2.8
|
||||
port: 8082
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
ftrackz:
|
||||
description: Laser Tracker coarse Z
|
||||
deviceClass: csaxs_bec.devices.omny.galil.fgalil_ophyd.FlomniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: G
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- 4.5
|
||||
- 5.5
|
||||
port: 8082
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
ftransx:
|
||||
description: Sample transer X
|
||||
deviceClass: csaxs_bec.devices.omny.galil.fgalil_ophyd.FlomniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: C
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 50
|
||||
port: 8081
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
ftransy:
|
||||
description: Sample transer Y
|
||||
deviceClass: csaxs_bec.devices.omny.galil.fgalil_ophyd.FlomniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: A
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- -100
|
||||
- 0
|
||||
port: 8081
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
ftransz:
|
||||
description: Sample transer Z
|
||||
deviceClass: csaxs_bec.devices.omny.galil.fgalil_ophyd.FlomniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: B
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 145
|
||||
port: 8081
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
ftray:
|
||||
description: Sample transfer tray
|
||||
deviceClass: csaxs_bec.devices.omny.galil.fgalil_ophyd.FlomniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: D
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- -200
|
||||
- 0
|
||||
port: 8081
|
||||
sign: -1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
|
||||
|
||||
############################################################
|
||||
#################### flOMNI Sample Names ###################
|
||||
############################################################
|
||||
|
||||
flomni_samples:
|
||||
description: Sample names and storage
|
||||
deviceClass: csaxs_bec.devices.omny.flomni_sample_storage.FlomniSampleStorage
|
||||
deviceConfig: {}
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
|
||||
############################################################
|
||||
#################### flOMNI Smaract motors #################
|
||||
############################################################
|
||||
|
||||
fosax:
|
||||
description: OSA X
|
||||
deviceClass: csaxs_bec.devices.smaract.smaract_ophyd.SmaractMotor
|
||||
deviceConfig:
|
||||
axis_Id: A
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- 10.2
|
||||
- 10.6
|
||||
port: 3334
|
||||
sign: -1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 9.124
|
||||
out: 5.3
|
||||
fosay:
|
||||
description: OSA Y
|
||||
deviceClass: csaxs_bec.devices.smaract.smaract_ophyd.SmaractMotor
|
||||
deviceConfig:
|
||||
axis_Id: B
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- -3.1
|
||||
- -2.9
|
||||
port: 3334
|
||||
sign: -1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 0.367
|
||||
fosaz:
|
||||
description: OSA Z
|
||||
deviceClass: csaxs_bec.devices.smaract.smaract_ophyd.SmaractMotor
|
||||
deviceConfig:
|
||||
axis_Id: C
|
||||
host: mpc2844.psi.ch
|
||||
limits:
|
||||
- -6
|
||||
- -4
|
||||
port: 3334
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 8.5
|
||||
out: 6
|
||||
|
||||
############################################################
|
||||
#################### flOMNI RT motors ######################
|
||||
############################################################
|
||||
|
||||
rtx:
|
||||
description: flomni rt
|
||||
deviceClass: csaxs_bec.devices.omny.rt.rt_flomni_ophyd.RtFlomniMotor
|
||||
deviceConfig:
|
||||
axis_Id: A
|
||||
host: mpc2844.psi.ch
|
||||
port: 2222
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: on_request
|
||||
userParameter:
|
||||
low_signal: 11000
|
||||
min_signal: 10000
|
||||
rt_pid_voltage: -0.06219
|
||||
rty:
|
||||
description: flomni rt
|
||||
deviceClass: csaxs_bec.devices.omny.rt.rt_flomni_ophyd.RtFlomniMotor
|
||||
deviceConfig:
|
||||
axis_Id: B
|
||||
host: mpc2844.psi.ch
|
||||
port: 2222
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: on_request
|
||||
userParameter:
|
||||
tomo_additional_offsety: 0
|
||||
rtz:
|
||||
description: flomni rt
|
||||
deviceClass: csaxs_bec.devices.omny.rt.rt_flomni_ophyd.RtFlomniMotor
|
||||
deviceConfig:
|
||||
axis_Id: C
|
||||
host: mpc2844.psi.ch
|
||||
port: 2222
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: on_request
|
||||
@@ -1,261 +0,0 @@
|
||||
############################################################
|
||||
#################### LamNI Galil motors ####################
|
||||
############################################################
|
||||
|
||||
leyex:
|
||||
description: Xray eye X
|
||||
deviceClass: csaxs_bec.devices.omny.galil.lgalil_ophyd.LamniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: G
|
||||
host: mpc2680.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8081
|
||||
sign: -1
|
||||
deviceTags:
|
||||
- lamni
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 14.117
|
||||
leyey:
|
||||
description: Xray eye Y
|
||||
deviceClass: csaxs_bec.devices.omny.galil.lgalil_ophyd.LamniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: H
|
||||
host: mpc2680.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8081
|
||||
sign: -1
|
||||
deviceTags:
|
||||
- lamni
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 48.069
|
||||
out: 0.5
|
||||
loptx:
|
||||
description: Optics X
|
||||
deviceClass: csaxs_bec.devices.omny.galil.lgalil_ophyd.LamniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: E
|
||||
host: mpc2680.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8081
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- lamni
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: -0.244
|
||||
out: -0.699
|
||||
lopty:
|
||||
description: Optics Y
|
||||
deviceClass: csaxs_bec.devices.omny.galil.lgalil_ophyd.LamniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: F
|
||||
host: mpc2680.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8081
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- lamni
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 3.724
|
||||
out: 3.53
|
||||
loptz:
|
||||
description: Optics Z
|
||||
deviceClass: csaxs_bec.devices.omny.galil.lgalil_ophyd.LamniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: D
|
||||
host: mpc2680.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8081
|
||||
sign: -1
|
||||
deviceTags:
|
||||
- lamni
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
lsamrot:
|
||||
description: Sample rotation
|
||||
deviceClass: csaxs_bec.devices.omny.galil.lgalil_ophyd.LamniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: C
|
||||
host: mpc2680.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8081
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- lamni
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
lsamx:
|
||||
description: Sample coarse X
|
||||
deviceClass: csaxs_bec.devices.omny.galil.lgalil_ophyd.LamniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: A
|
||||
host: mpc2680.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8081
|
||||
sign: -1
|
||||
deviceTags:
|
||||
- lamni
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
center: 8.768
|
||||
lsamy:
|
||||
description: Sample coarse Y
|
||||
deviceClass: csaxs_bec.devices.omny.galil.lgalil_ophyd.LamniGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: B
|
||||
host: mpc2680.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8081
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- lamni
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
center: 10.041
|
||||
|
||||
|
||||
############################################################
|
||||
################ LamNI Smaract motors ######################
|
||||
############################################################
|
||||
|
||||
losax:
|
||||
description: OSA X
|
||||
deviceClass: csaxs_bec.devices.smaract.smaract_ophyd.SmaractMotor
|
||||
deviceConfig:
|
||||
axis_Id: A
|
||||
host: mpc2680.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8085
|
||||
sign: -1
|
||||
deviceTags:
|
||||
- lamni
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: -1.442
|
||||
losay:
|
||||
description: OSA Y
|
||||
deviceClass: csaxs_bec.devices.smaract.smaract_ophyd.SmaractMotor
|
||||
deviceConfig:
|
||||
axis_Id: B
|
||||
host: mpc2680.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8085
|
||||
sign: -1
|
||||
deviceTags:
|
||||
- lamni
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: -0.171
|
||||
out: 3.8
|
||||
losaz:
|
||||
description: OSA Z
|
||||
deviceClass: csaxs_bec.devices.smaract.smaract_ophyd.SmaractMotor
|
||||
deviceConfig:
|
||||
axis_Id: C
|
||||
host: mpc2680.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8085
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- lamni
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: -1
|
||||
out: -3
|
||||
|
||||
############################################################
|
||||
#################### flOMNI RT motors ######################
|
||||
############################################################
|
||||
|
||||
rtx:
|
||||
deviceClass: csaxs_bec.devices.omny.rt.rt_lamni_ophyd.RtLamniMotor
|
||||
deviceConfig:
|
||||
axis_Id: A
|
||||
device_access: true
|
||||
host: mpc2680.psi.ch
|
||||
labels: rtx
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 3333
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- lamni
|
||||
readoutPriority: baseline
|
||||
enabled: true
|
||||
readOnly: False
|
||||
rty:
|
||||
deviceClass: csaxs_bec.devices.omny.rt.rt_lamni_ophyd.RtLamniMotor
|
||||
deviceConfig:
|
||||
axis_Id: B
|
||||
device_access: true
|
||||
host: mpc2680.psi.ch
|
||||
labels: rty
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 3333
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- lamni
|
||||
readoutPriority: baseline
|
||||
enabled: true
|
||||
readOnly: False
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
############################################################
|
||||
#################### npoint motors #########################
|
||||
############################################################
|
||||
|
||||
npx:
|
||||
description: nPoint x axis on the big npoint controller
|
||||
deviceClass: csaxs_bec.devices.npoint.npoint.NPointAxis
|
||||
deviceConfig:
|
||||
axis_Id: A
|
||||
host: "nPoint000003.psi.ch"
|
||||
limits:
|
||||
- -50
|
||||
- 50
|
||||
port: 23
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- npoint
|
||||
npy:
|
||||
description: nPoint y axis on the big npoint controller
|
||||
deviceClass: csaxs_bec.devices.npoint.npoint.NPointAxis
|
||||
deviceConfig:
|
||||
axis_Id: B
|
||||
host: "nPoint000003.psi.ch"
|
||||
limits:
|
||||
- -50
|
||||
- 50
|
||||
port: 23
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
deviceTags:
|
||||
- npoint
|
||||
@@ -1,610 +0,0 @@
|
||||
# ############################################################
|
||||
# #################### IDS Camera ######################
|
||||
# ############################################################
|
||||
cam200:
|
||||
description: Camera200
|
||||
deviceClass: csaxs_bec.devices.ids_cameras.ids_camera.IDSCamera
|
||||
deviceConfig:
|
||||
camera_ID: 200
|
||||
bits_per_pixel: 24
|
||||
channels: 3
|
||||
m_n_colormode: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: async
|
||||
|
||||
cam201:
|
||||
description: Camera201
|
||||
deviceClass: csaxs_bec.devices.ids_cameras.ids_camera.IDSCamera
|
||||
deviceConfig:
|
||||
camera_ID: 201
|
||||
bits_per_pixel: 24
|
||||
channels: 3
|
||||
m_n_colormode: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: async
|
||||
|
||||
cam202:
|
||||
description: Camera202
|
||||
deviceClass: csaxs_bec.devices.ids_cameras.ids_camera.IDSCamera
|
||||
deviceConfig:
|
||||
camera_ID: 202
|
||||
bits_per_pixel: 24
|
||||
channels: 3
|
||||
m_n_colormode: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: async
|
||||
|
||||
cam203:
|
||||
description: Camera203
|
||||
deviceClass: csaxs_bec.devices.ids_cameras.ids_camera.IDSCamera
|
||||
deviceConfig:
|
||||
camera_ID: 203
|
||||
bits_per_pixel: 24
|
||||
channels: 3
|
||||
m_n_colormode: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: async
|
||||
|
||||
############################################################
|
||||
#################### OMNY RT motors ########################
|
||||
############################################################
|
||||
|
||||
rtx:
|
||||
description: OMNY rt
|
||||
deviceClass: csaxs_bec.devices.omny.rt.rt_omny_ophyd.RtOMNYMotor
|
||||
deviceConfig:
|
||||
axis_Id: A
|
||||
host: mpc3217.psi.ch
|
||||
port: 3333
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: on_request
|
||||
userParameter:
|
||||
low_signal: 8500
|
||||
min_signal: 8000
|
||||
rty:
|
||||
description: OMNY rt
|
||||
deviceClass: csaxs_bec.devices.omny.rt.rt_omny_ophyd.RtOMNYMotor
|
||||
deviceConfig:
|
||||
axis_Id: B
|
||||
host: mpc3217.psi.ch
|
||||
port: 3333
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: on_request
|
||||
userParameter:
|
||||
tomo_additional_offsety: 0
|
||||
rtz:
|
||||
description: OMNY rt
|
||||
deviceClass: csaxs_bec.devices.omny.rt.rt_omny_ophyd.RtOMNYMotor
|
||||
deviceConfig:
|
||||
axis_Id: C
|
||||
host: mpc3217.psi.ch
|
||||
port: 3333
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: on_request
|
||||
|
||||
# ############################################################
|
||||
# ##################### OMNY samples #########################
|
||||
# ############################################################
|
||||
omny_samples:
|
||||
description: OMNYSampleStorage
|
||||
deviceClass: csaxs_bec.devices.omny.omny_sample_storage.OMNYSampleStorage
|
||||
deviceConfig: {}
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
# ############################################################
|
||||
# ##################### OMNY vacuum ##########################
|
||||
# ############################################################
|
||||
# omny_vcs:
|
||||
# description: OMNYVCS
|
||||
# deviceClass: csaxs_bec.devices.omny.omny_vcs.OMNYVCS
|
||||
# deviceConfig: {}
|
||||
# enabled: true
|
||||
# onFailure: buffer
|
||||
# readOnly: false
|
||||
# readoutPriority: baseline
|
||||
# ############################################################
|
||||
# ##################### OMNY dewar ###########################
|
||||
# ############################################################
|
||||
omny_dewar:
|
||||
description: OMNY Dewar Information
|
||||
deviceClass: csaxs_bec.devices.omny.omny_dewar.OMNYDewar
|
||||
deviceConfig: {}
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
|
||||
# ############################################################
|
||||
# ##################### OMNY temperatures ####################
|
||||
# ############################################################
|
||||
omny_temperatures:
|
||||
description: OMNY Temperatures and pressures
|
||||
deviceClass: csaxs_bec.devices.omny.omny_temperatures.OMNYTemperatures
|
||||
deviceConfig: {}
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
|
||||
############################################################
|
||||
##################### OMNY Galil motors ####################
|
||||
############################################################
|
||||
ofzpx:
|
||||
description: FZP X
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: A
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8081
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: -0.4317
|
||||
ofzpy:
|
||||
description: FZP Y
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: B
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8081
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 0.7944
|
||||
out: 0.6377
|
||||
ofzpz:
|
||||
description: FZP Z
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: C
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8081
|
||||
sign: -1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 0
|
||||
otransx:
|
||||
description: Transfer X
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: D
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8081
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 0
|
||||
otransy:
|
||||
description: Transfer Y
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: E
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8081
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
up_position: -1.2
|
||||
gripper_sensorvoltagetarget: -2.30
|
||||
otransz:
|
||||
description: Transfer Z
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: F
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8081
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 0
|
||||
osamx:
|
||||
description: Sample X
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: A
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8082
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: -0.1
|
||||
osamz:
|
||||
description: Sample Z
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: B
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8082
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: false
|
||||
onFailure: buffer
|
||||
readOnly: true
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 0
|
||||
oosay:
|
||||
description: OSA Y
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: C
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8082
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
near_field_in: 0.531
|
||||
far_field_in: 0.4122
|
||||
oosax:
|
||||
description: OSA X
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: D
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8082
|
||||
sign: -1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
near_field_in: 3.2044
|
||||
far_field_in: 3.022
|
||||
oosaz:
|
||||
description: OSA Z
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: E
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8082
|
||||
sign: -1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
near_field_in: -0.4452
|
||||
far_field_in: 6.5
|
||||
oparkz:
|
||||
description: OSA Y
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: F
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8082
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 0
|
||||
oshuttleopen:
|
||||
description: Shuttle opener
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: G
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8082
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: true
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 0
|
||||
oshuttlealign:
|
||||
description: Shuttle aligner
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: H
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8082
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: true
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 0
|
||||
osamy:
|
||||
description: Sample Y
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: A
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8083
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 0
|
||||
otracky:
|
||||
description: Laser Tracker Y
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: B
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8083
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
start_pos: -4.3431
|
||||
osamroy:
|
||||
description: Sample rotation
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: C
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8083
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 0
|
||||
otrackz:
|
||||
description: Laser Tracker Z
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: E
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8083
|
||||
sign: -1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
start_pos: -0.6948
|
||||
oeyex:
|
||||
description: Xray eye X
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: F
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8083
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
xray_in: -45.7394
|
||||
oeyez:
|
||||
description: Xray eye Z
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: G
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8083
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
xray_in: -2
|
||||
oeyey:
|
||||
description: Xray eye Y
|
||||
deviceClass: csaxs_bec.devices.omny.galil.ogalil_ophyd.OMNYGalilMotor
|
||||
deviceConfig:
|
||||
axis_Id: H
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- 0
|
||||
- 0
|
||||
port: 8083
|
||||
sign: 1
|
||||
deviceTags:
|
||||
- omny
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
xray_in: 0.0229
|
||||
|
||||
############################################################
|
||||
#################### flOMNI Smaract motors #################
|
||||
############################################################
|
||||
|
||||
ocsx:
|
||||
description: Central Stop X
|
||||
deviceClass: csaxs_bec.devices.smaract.smaract_ophyd.SmaractMotor
|
||||
deviceConfig:
|
||||
axis_Id: B
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- -2
|
||||
- 2
|
||||
port: 3334
|
||||
sign: -1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
nothing: 0
|
||||
ocsy:
|
||||
description: Central Stop Y
|
||||
deviceClass: csaxs_bec.devices.smaract.smaract_ophyd.SmaractMotor
|
||||
deviceConfig:
|
||||
axis_Id: A
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- -2
|
||||
- 2
|
||||
port: 3334
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
nothing: 0
|
||||
oshield:
|
||||
description: Thermal Shield Sample Stage
|
||||
deviceClass: csaxs_bec.devices.smaract.smaract_ophyd.SmaractMotor
|
||||
deviceConfig:
|
||||
axis_Id: C
|
||||
host: mpc3217.psi.ch
|
||||
limits:
|
||||
- -14.5
|
||||
- 15.8
|
||||
port: 3334
|
||||
sign: 1
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
nothing: 0
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,44 +0,0 @@
|
||||
// This file was autogenerated. Do not edit it manually.
|
||||
## Device List
|
||||
### csaxs_bec
|
||||
| Device | Documentation | Module |
|
||||
| :----- | :------------- | :------ |
|
||||
| Bpm4i | | [csaxs_bec.devices.epics.specMotors](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/specMotors.py) |
|
||||
| DelayGeneratorcSAXS | <br> DG645 delay generator at cSAXS (multiple can be in use depending on the setup)<br><br> Default values for setting up DDG.<br> Note: checks of set calues are not (only partially) included, check manual for details on possible settings.<br> https://www.thinksrs.com/downloads/pdfs/manuals/DG645m.pdf<br><br> - delay_burst : (float >=0) Delay between trigger and first pulse in burst mode<br> - delta_width : (float >= 0) Add width to fast shutter signal to make sure its open during acquisition<br> - additional_triggers : (int) add additional triggers to burst mode (mcs card needs +1 triggers per line)<br> - polarity : (list of 0/1) polarity for different channels<br> - amplitude : (float) amplitude voltage of TTLs<br> - offset : (float) offset for ampltitude<br> - thres_trig_level : (float) threshold of trigger amplitude<br><br> Custom signals for logic in different DDGs during scans (for custom_prepare.prepare_ddg):<br><br> - set_high_on_exposure : (bool): if True, then TTL signal should go high during the full acquisition time of a scan.<br> # TODO trigger_width and fixed_ttl could be combined into single list.<br> - fixed_ttl_width : (list of either 1 or 0), one for each channel.<br> - trigger_width : (float) if fixed_ttl_width is True, then the width of the TTL pulse is set to this value.<br> - set_trigger_source : (TriggerSource) specifies the default trigger source for the DDG.<br> - premove_trigger : (bool) if True, then a trigger should be executed before the scan starts (to be implemented in on_pre_scan).<br> - set_high_on_stage : (bool) if True, then TTL signal should go high already on stage.<br> | [csaxs_bec.devices.epics.delay_generator_csaxs](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/delay_generator_csaxs.py) |
|
||||
| Eiger1p5MDetector | | [csaxs_bec.devices.omny.eiger1p5m](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/omny/eiger1p5m.py) |
|
||||
| Eiger9McSAXS | <br> Eiger9M detector for CSAXS<br><br> Parent class: PSIDetectorBase<br><br> class attributes:<br> custom_prepare_cls (FalconSetup) : Custom detector setup class for cSAXS,<br> inherits from CustomDetectorMixin<br> PSIDetectorBase.set_min_readout (float) : Minimum readout time for the detector<br> Various EpicsPVs for controlling the detector<br> | [csaxs_bec.devices.epics.eiger9m_csaxs](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/eiger9m_csaxs.py) |
|
||||
| EpicsDXPFalcon | <br> DXP parameters for Falcon detector<br><br> Base class to map EPICS PVs from DXP parameters to ophyd signals.<br> | [csaxs_bec.devices.epics.falcon_csaxs](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/falcon_csaxs.py) |
|
||||
| FalconcSAXS | <br> Falcon Sitoro detector for CSAXS<br><br> Parent class: PSIDetectorBase<br><br> class attributes:<br> custom_prepare_cls (FalconSetup) : Custom detector setup class for cSAXS,<br> inherits from CustomDetectorMixin<br> PSIDetectorBase.set_min_readout (float) : Minimum readout time for the detector<br> dxp (EpicsDXPFalcon) : DXP parameters for Falcon detector<br> mca (EpicsMCARecord) : MCA parameters for Falcon detector<br> hdf5 (FalconHDF5Plugins) : HDF5 parameters for Falcon detector<br> MIN_READOUT (float) : Minimum readout time for the detector<br> | [csaxs_bec.devices.epics.falcon_csaxs](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/falcon_csaxs.py) |
|
||||
| FalconHDF5Plugins | <br> HDF5 parameters for Falcon detector<br><br> Base class to map EPICS PVs from HDF5 Plugin to ophyd signals.<br> | [csaxs_bec.devices.epics.falcon_csaxs](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/falcon_csaxs.py) |
|
||||
| FlomniGalilMotor | | [csaxs_bec.devices.omny.galil.fgalil_ophyd](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/omny/galil/fgalil_ophyd.py) |
|
||||
| FlomniSampleStorage | | [csaxs_bec.devices.omny.flomni_sample_storage](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/omny/flomni_sample_storage.py) |
|
||||
| FuprGalilMotor | | [csaxs_bec.devices.omny.galil.fupr_ophyd](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/omny/galil/fupr_ophyd.py) |
|
||||
| GirderMotorPITCH | Girder YAW pseudo motor | [csaxs_bec.devices.epics.specMotors](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/specMotors.py) |
|
||||
| GirderMotorROLL | Girder ROLL pseudo motor | [csaxs_bec.devices.epics.specMotors](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/specMotors.py) |
|
||||
| GirderMotorX1 | Girder X translation pseudo motor | [csaxs_bec.devices.epics.specMotors](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/specMotors.py) |
|
||||
| GirderMotorY1 | Girder Y translation pseudo motor | [csaxs_bec.devices.epics.specMotors](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/specMotors.py) |
|
||||
| GirderMotorYAW | Girder YAW pseudo motor | [csaxs_bec.devices.epics.specMotors](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/specMotors.py) |
|
||||
| IDSCamera | | [csaxs_bec.devices.ids_cameras.ids_camera](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/ids_cameras/ids_camera.py) |
|
||||
| InsertionDevice | Python wrapper for the CSAXS insertion device control<br><br> This wrapper provides a positioner interface for the ID control.<br> is completely custom XBPM with templates directly in the<br> VME repo. Thus it needs a custom ophyd template as well...<br><br> WARN: The x and y are not updated by the IOC<br> | [csaxs_bec.devices.epics.InsertionDevice](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/InsertionDevice.py) |
|
||||
| LamniGalilMotor | | [csaxs_bec.devices.omny.galil.lgalil_ophyd](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/omny/galil/lgalil_ophyd.py) |
|
||||
| MCScSAXS | MCS card for cSAXS for implementation at cSAXS beamline | [csaxs_bec.devices.epics.mcs_csaxs](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/mcs_csaxs.py) |
|
||||
| NPointAxis | <br> NPointAxis class, which inherits from Device and PositionerBase. This class<br> represents an axis of an nPoint piezo stage and provides the necessary<br> functionality to move the axis and read its current position.<br> | [csaxs_bec.devices.npoint.npoint](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/npoint/npoint.py) |
|
||||
| OMNYDewar | | [csaxs_bec.devices.omny.omny_dewar](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/omny/omny_dewar.py) |
|
||||
| OMNYGalilMotor | | [csaxs_bec.devices.omny.galil.ogalil_ophyd](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/omny/galil/ogalil_ophyd.py) |
|
||||
| OMNYSampleStorage | | [csaxs_bec.devices.omny.omny_sample_storage](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/omny/omny_sample_storage.py) |
|
||||
| OMNYTemperatures | | [csaxs_bec.devices.omny.omny_temperatures](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/omny/omny_temperatures.py) |
|
||||
| OMNYVCS | | [csaxs_bec.devices.omny.omny_vcs](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/omny/omny_vcs.py) |
|
||||
| PilatuscSAXS | Pilatus_2 300k detector for CSAXS<br><br> Parent class: PSIDetectorBase<br><br> class attributes:<br> custom_prepare_cls (Eiger9MSetup) : Custom detector setup class for cSAXS,<br> inherits from CustomDetectorMixin<br> cam (SLSDetectorCam) : Detector camera<br> MIN_READOUT (float) : Minimum readout time for the detector<br><br> | [csaxs_bec.devices.epics.pilatus_csaxs](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/pilatus_csaxs.py) |
|
||||
| PmDetectorRotation | Detector rotation pseudo motor<br><br> Small wrapper to convert detector pusher position to rotation angle.<br> | [csaxs_bec.devices.epics.specMotors](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/specMotors.py) |
|
||||
| PmMonoBender | Monochromator bender<br><br> Small wrapper to combine the four monochromator bender motors.<br> | [csaxs_bec.devices.epics.specMotors](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/specMotors.py) |
|
||||
| RtFlomniMotor | | [csaxs_bec.devices.omny.rt.rt_flomni_ophyd](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/omny/rt/rt_flomni_ophyd.py) |
|
||||
| RtLamniMotor | | [csaxs_bec.devices.omny.rt.rt_lamni_ophyd](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/omny/rt/rt_lamni_ophyd.py) |
|
||||
| RtOMNYMotor | | [csaxs_bec.devices.omny.rt.rt_omny_ophyd](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/omny/rt/rt_omny_ophyd.py) |
|
||||
| SGalilMotor | "SGalil Motors at cSAXS have a<br> DC motor (y axis - vertical) - implemented as C<br> and a step motor (x-axis horizontal) - implemented as E<br> that require different communication for control<br> | [csaxs_bec.devices.omny.galil.sgalil_ophyd](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/omny/galil/sgalil_ophyd.py) |
|
||||
| SIS38XX | SIS38XX card for access to EPICs PVs at cSAXS beamline | [csaxs_bec.devices.epics.mcs_csaxs](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/mcs_csaxs.py) |
|
||||
| SLSDetectorCam | SLS Detector Camera - Pilatus<br><br> Base class to map EPICS PVs to ophyd signals.<br> | [csaxs_bec.devices.epics.pilatus_csaxs](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/pilatus_csaxs.py) |
|
||||
| SmaractMotor | | [csaxs_bec.devices.smaract.smaract_ophyd](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/smaract/smaract_ophyd.py) |
|
||||
| XbpmBase | Python wrapper for X-ray Beam Position Monitors<br><br> XBPM's consist of a metal-coated diamond window that ejects<br> photoelectrons from the incoming X-ray beam. These electons<br> are collected and their current is measured. Effectively<br> they act as four quadrant photodiodes and are used as BPMs<br> at the undulator beamlines of SLS.<br><br> Note: EPICS provided signals are read only, but the user can<br> change the beam position offset.<br> | [csaxs_bec.devices.epics.XbpmBase](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/XbpmBase.py) |
|
||||
| XbpmCsaxsOp | Python wrapper for custom XBPMs in the cSAXS optics hutch<br><br> This is completely custom XBPM with templates directly in the<br> VME repo. Thus it needs a custom ophyd template as well...<br><br> WARN: The x and y are not updated by the IOC<br> | [csaxs_bec.devices.epics.XbpmBase](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/XbpmBase.py) |
|
||||
| XbpmSim | Python wrapper for simulated X-ray Beam Position Monitors<br><br> XBPM's consist of a metal-coated diamond window that ejects<br> photoelectrons from the incoming X-ray beam. These electons<br> are collected and their current is measured. Effectively<br> they act as four quadrant photodiodes and are used as BPMs<br> at the undulator beamlines of SLS.<br><br> Note: EPICS provided signals are read only, but the user can<br> change the beam position offset.<br><br> This simulation device extends the basic proxy with a script that<br> fills signals with quasi-randomized values.<br> | [csaxs_bec.devices.epics.XbpmBase](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/epics/XbpmBase.py) |
|
||||
| Xeye | | [csaxs_bec.devices.sls_devices.cSAXS.xeye](https://gitlab.psi.ch/bec/csaxs_bec/-/blob/main/csaxs_bec/devices/sls_devices/cSAXS/xeye.py) |
|
||||
@@ -1,28 +0,0 @@
|
||||
from ophyd import Component, EpicsSignal, EpicsSignalRO, Kind, PVPositioner
|
||||
|
||||
|
||||
class InsertionDevice(PVPositioner):
|
||||
"""Python wrapper for the CSAXS insertion device control
|
||||
|
||||
This wrapper provides a positioner interface for the ID control.
|
||||
is completely custom XBPM with templates directly in the
|
||||
VME repo. Thus it needs a custom ophyd template as well...
|
||||
|
||||
WARN: The x and y are not updated by the IOC
|
||||
"""
|
||||
|
||||
status = Component(EpicsSignalRO, "-USER:STATUS", auto_monitor=True)
|
||||
errorSource = Component(EpicsSignalRO, "-USER:ERROR-SOURCE", auto_monitor=True)
|
||||
isOpen = Component(EpicsSignalRO, "-GAP:ISOPEN", auto_monitor=True)
|
||||
|
||||
# PVPositioner interface
|
||||
setpoint = Component(EpicsSignal, "-GAP:SET", auto_monitor=True)
|
||||
readback = Component(EpicsSignalRO, "-GAP:READ", auto_monitor=True, kind=Kind.hinted)
|
||||
done = Component(EpicsSignalRO, ":DONE", auto_monitor=True)
|
||||
stop_signal = Component(EpicsSignal, "-GAP:STOP", kind=Kind.omitted)
|
||||
|
||||
|
||||
# Automatically start simulation if directly invoked
|
||||
# (NA for important devices)
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
@@ -1,136 +0,0 @@
|
||||
import numpy as np
|
||||
from ophyd import Component, Device, EpicsSignal, EpicsSignalRO
|
||||
|
||||
|
||||
class XbpmCsaxsOp(Device):
|
||||
"""Python wrapper for custom XBPMs in the cSAXS optics hutch
|
||||
|
||||
This is completely custom XBPM with templates directly in the
|
||||
VME repo. Thus it needs a custom ophyd template as well...
|
||||
|
||||
WARN: The x and y are not updated by the IOC
|
||||
"""
|
||||
|
||||
sum = Component(EpicsSignalRO, "SUM", auto_monitor=True)
|
||||
x = Component(EpicsSignalRO, "POSH", auto_monitor=True)
|
||||
y = Component(EpicsSignalRO, "POSV", auto_monitor=True)
|
||||
s1 = Component(EpicsSignalRO, "CHAN1", auto_monitor=True)
|
||||
s2 = Component(EpicsSignalRO, "CHAN2", auto_monitor=True)
|
||||
s3 = Component(EpicsSignalRO, "CHAN3", auto_monitor=True)
|
||||
s4 = Component(EpicsSignalRO, "CHAN4", auto_monitor=True)
|
||||
|
||||
|
||||
class XbpmBase(Device):
|
||||
"""Python wrapper for X-ray Beam Position Monitors
|
||||
|
||||
XBPM's consist of a metal-coated diamond window that ejects
|
||||
photoelectrons from the incoming X-ray beam. These electons
|
||||
are collected and their current is measured. Effectively
|
||||
they act as four quadrant photodiodes and are used as BPMs
|
||||
at the undulator beamlines of SLS.
|
||||
|
||||
Note: EPICS provided signals are read only, but the user can
|
||||
change the beam position offset.
|
||||
"""
|
||||
|
||||
# Motor interface
|
||||
s1 = Component(EpicsSignalRO, "Current1", auto_monitor=True)
|
||||
s2 = Component(EpicsSignalRO, "Current2", auto_monitor=True)
|
||||
s3 = Component(EpicsSignalRO, "Current3", auto_monitor=True)
|
||||
s4 = Component(EpicsSignalRO, "Current4", auto_monitor=True)
|
||||
sum = Component(EpicsSignalRO, "SumAll", auto_monitor=True)
|
||||
asymH = Component(EpicsSignalRO, "asymH", auto_monitor=True)
|
||||
asymV = Component(EpicsSignalRO, "asymV", auto_monitor=True)
|
||||
x = Component(EpicsSignalRO, "X", auto_monitor=True)
|
||||
y = Component(EpicsSignalRO, "Y", auto_monitor=True)
|
||||
scaleH = Component(EpicsSignal, "PositionScaleX", auto_monitor=False)
|
||||
offsetH = Component(EpicsSignal, "PositionOffsetX", auto_monitor=False)
|
||||
scaleV = Component(EpicsSignal, "PositionScaleY", auto_monitor=False)
|
||||
offsetV = Component(EpicsSignal, "PositionOffsetY", auto_monitor=False)
|
||||
|
||||
|
||||
class XbpmSim(XbpmBase):
|
||||
"""Python wrapper for simulated X-ray Beam Position Monitors
|
||||
|
||||
XBPM's consist of a metal-coated diamond window that ejects
|
||||
photoelectrons from the incoming X-ray beam. These electons
|
||||
are collected and their current is measured. Effectively
|
||||
they act as four quadrant photodiodes and are used as BPMs
|
||||
at the undulator beamlines of SLS.
|
||||
|
||||
Note: EPICS provided signals are read only, but the user can
|
||||
change the beam position offset.
|
||||
|
||||
This simulation device extends the basic proxy with a script that
|
||||
fills signals with quasi-randomized values.
|
||||
"""
|
||||
|
||||
# Motor interface
|
||||
s1w = Component(EpicsSignal, "Current1:RAW.VAL", auto_monitor=False)
|
||||
s2w = Component(EpicsSignal, "Current2:RAW.VAL", auto_monitor=False)
|
||||
s3w = Component(EpicsSignal, "Current3:RAW.VAL", auto_monitor=False)
|
||||
s4w = Component(EpicsSignal, "Current4:RAW.VAL", auto_monitor=False)
|
||||
rangew = Component(EpicsSignal, "RANGEraw", auto_monitor=False)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self._MX = 0
|
||||
self._MY = 0
|
||||
self._I0 = 255.0
|
||||
self._x = np.linspace(-5, 5, 64)
|
||||
self._y = np.linspace(-5, 5, 64)
|
||||
self._x, self._y = np.meshgrid(self._x, self._y)
|
||||
|
||||
def _simFrame(self):
|
||||
"""Generator to simulate a jumping gaussian"""
|
||||
|
||||
# define normalized 2D gaussian
|
||||
def gaus2d(x=0, y=0, mx=0, my=0, sx=1, sy=1):
|
||||
return np.exp(-((x - mx) ** 2.0 / (2.0 * sx**2.0) + (y - my) ** 2.0 / (2.0 * sy**2.0)))
|
||||
|
||||
# Generator for dynamic values
|
||||
self._MX = 0.75 * self._MX + 0.25 * (10.0 * np.random.random() - 5.0)
|
||||
self._MY = 0.75 * self._MY + 0.25 * (10.0 * np.random.random() - 5.0)
|
||||
self._I0 = 0.75 * self._I0 + 0.25 * (255.0 * np.random.random())
|
||||
|
||||
arr = self._I0 * gaus2d(self._x, self._y, self._MX, self._MY)
|
||||
return arr
|
||||
|
||||
def sim(self):
|
||||
# Get next frame
|
||||
beam = self._simFrame()
|
||||
total = np.sum(beam)
|
||||
rnge = np.floor(np.log10(total) - 0.0)
|
||||
s1 = np.sum(beam[32:64, 32:64]) / 10**rnge
|
||||
s2 = np.sum(beam[0:32, 32:64]) / 10**rnge
|
||||
s3 = np.sum(beam[32:64, 0:32]) / 10**rnge
|
||||
s4 = np.sum(beam[0:32, 0:32]) / 10**rnge
|
||||
|
||||
self.s1w.set(s1).wait()
|
||||
self.s2w.set(s2).wait()
|
||||
self.s3w.set(s3).wait()
|
||||
self.s4w.set(s4).wait()
|
||||
self.rangew.set(rnge).wait()
|
||||
# Print debug info
|
||||
print(f"Raw signals: R={rnge}\t{s1}\t{s2}\t{s3}\t{s4}")
|
||||
# plt.imshow(beam)
|
||||
# plt.show(block=False)
|
||||
# plt.pause(0.5)
|
||||
|
||||
|
||||
# Automatically start simulation if directly invoked
|
||||
if __name__ == "__main__":
|
||||
xbpm1 = XbpmSim("X01DA-FE-XBPM1:", name="xbpm1")
|
||||
xbpm2 = XbpmSim("X01DA-FE-XBPM2:", name="xbpm2")
|
||||
|
||||
xbpm1.wait_for_connection(timeout=5)
|
||||
xbpm2.wait_for_connection(timeout=5)
|
||||
|
||||
xbpm1.rangew.set(1).wait()
|
||||
xbpm2.rangew.set(1).wait()
|
||||
|
||||
while True:
|
||||
print("---")
|
||||
xbpm1.sim()
|
||||
xbpm2.sim()
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
""" TODO This class seems to be missing various imports and appears to have not been tested in motion yet."""
|
||||
|
||||
# TABLES_DT_PUSH_DIST_MM = 890
|
||||
|
||||
|
||||
# class DetectorTableTheta(PseudoPositioner):
|
||||
# """Detector table tilt motor
|
||||
|
||||
# Small wrapper to adjust the detector table tilt as angle.
|
||||
# The table is pushed from one side by a single vertical motor.
|
||||
|
||||
# Note: Rarely used!
|
||||
# """
|
||||
|
||||
# # Real axis (in degrees)
|
||||
# pusher = Component(EpicsMotor, "", name="pusher")
|
||||
# # Virtual axis
|
||||
# theta = Component(PseudoSingle, name="theta")
|
||||
|
||||
# _real = ["pusher"]
|
||||
|
||||
# @pseudo_position_argument
|
||||
# def forward(self, pseudo_pos):
|
||||
# return self.RealPosition(
|
||||
# pusher=tan(pseudo_pos.theta * 3.141592 / 180.0) * TABLES_DT_PUSH_DIST_MM
|
||||
# )
|
||||
|
||||
# @real_position_argument
|
||||
# def inverse(self, real_pos):
|
||||
# return self.PseudoPosition(
|
||||
# theta=-180 * atan(real_pos.pusher / TABLES_DT_PUSH_DIST_MM) / 3.141592
|
||||
# )
|
||||
@@ -1,274 +0,0 @@
|
||||
from bec_lib import bec_logger
|
||||
from ophyd import Component, DeviceStatus, Kind
|
||||
from ophyd_devices.devices.delay_generator_645 import DelayGenerator, TriggerSource
|
||||
from ophyd_devices.interfaces.base_classes.bec_device_base import BECDeviceBase, CustomPrepare
|
||||
from ophyd_devices.sim.sim_signals import SetableSignal
|
||||
from ophyd_devices.utils import bec_utils
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
|
||||
class DelayGeneratorcSAXSError(Exception):
|
||||
"""Exception raised for errors."""
|
||||
|
||||
|
||||
class DDGSetup(CustomPrepare["DelayGeneratorcSAXS"]):
|
||||
"""
|
||||
Custom Prepare class with hooks for beamline specific logic for the DG645 at CSAXS
|
||||
"""
|
||||
|
||||
def on_wait_for_connection(self) -> None:
|
||||
"""Init default parameter after the all signals are connected"""
|
||||
for ii, channel in enumerate(self.parent.all_channels):
|
||||
self.parent.set_channels("polarity", self.parent.polarity.get()[ii], [channel])
|
||||
|
||||
self.parent.set_channels("amplitude", self.parent.amplitude.get())
|
||||
self.parent.set_channels("offset", self.parent.offset.get())
|
||||
# Setup reference
|
||||
self.parent.set_channels(
|
||||
"reference", 0, [f"channel{pair}.ch1" for pair in self.parent.all_delay_pairs]
|
||||
)
|
||||
self.parent.set_channels(
|
||||
"reference", 0, [f"channel{pair}.ch2" for pair in self.parent.all_delay_pairs]
|
||||
)
|
||||
self.parent.set_trigger(getattr(TriggerSource, self.parent.set_trigger_source.get()))
|
||||
# Set threshold level for ext. pulses
|
||||
self.parent.level.put(self.parent.thres_trig_level.get())
|
||||
|
||||
def on_stage(self) -> None:
|
||||
"Hook execute before the scan starts"
|
||||
if self.parent.scaninfo.scan_type == "step":
|
||||
exp_time = self.parent.scaninfo.exp_time
|
||||
delay = 0
|
||||
self.parent.burst_disable()
|
||||
self.parent.set_trigger(TriggerSource.SINGLE_SHOT)
|
||||
self.parent.set_channels(signal="width", value=exp_time)
|
||||
self.parent.set_channels(signal="delay", value=delay)
|
||||
return
|
||||
scan_name = self.parent.scaninfo.scan_msg.content["info"].get("scan_name", "")
|
||||
if scan_name == "jjf_test":
|
||||
# TODO implement the logic for JJF triggering
|
||||
exp_time = 480e-6 # self.parent.scaninfo.exp_time
|
||||
readout = 20e-6 # self.parent.scaninfo.readout_time
|
||||
total_exposure = exp_time + readout
|
||||
num_burst_cycle = self.parent.scaninfo.scan_msg.content["info"]["kwargs"]["num_points"]
|
||||
num_burst_cycle = int(num_burst_cycle * self.parent.scaninfo.exp_time / total_exposure)
|
||||
delay = 0
|
||||
delay_burst = self.parent.delay_burst.get()
|
||||
|
||||
self.parent.set_trigger(trigger_source=TriggerSource.SINGLE_SHOT)
|
||||
|
||||
self.parent.set_channels(signal="width", value=exp_time)
|
||||
self.parent.set_channels(signal="delay", value=delay)
|
||||
self.parent.burst_enable(
|
||||
count=num_burst_cycle, delay=delay_burst, period=total_exposure, config="first"
|
||||
)
|
||||
logger.info(
|
||||
f"{self.parent.name}: On stage with n_burst: {num_burst_cycle} and total_exp {total_exposure}"
|
||||
)
|
||||
|
||||
def on_trigger(self) -> DeviceStatus:
|
||||
"""Method to be executed upon trigger"""
|
||||
if self.parent.scaninfo.scan_type == "step":
|
||||
self.parent.trigger_shot.put(1)
|
||||
return
|
||||
scan_name = self.parent.scaninfo.scan_msg.content["info"].get("scan_name", "")
|
||||
if scan_name == "jjf_test":
|
||||
exp_time = 480e-6 # self.parent.scaninfo.exp_time
|
||||
readout = 20e-6 # self.parent.scaninfo.readout_time
|
||||
total_exposure = exp_time + readout
|
||||
num_burst_cycle = self.parent.scaninfo.scan_msg.content["info"]["kwargs"]["num_points"]
|
||||
num_burst_cycle = int(num_burst_cycle * self.parent.scaninfo.exp_time / total_exposure)
|
||||
|
||||
# Start trigger cycle
|
||||
self.parent.trigger_burst_readout.put(1)
|
||||
|
||||
# Create status object that will wait for the end of the burst cycle
|
||||
status = self.wait_with_status(
|
||||
signal_conditions=[(self.parent.burst_cycle_finished, 1)],
|
||||
timeout=num_burst_cycle * total_exposure + 1, # add 1s to be sure
|
||||
check_stopped=True,
|
||||
exception_on_timeout=DelayGeneratorcSAXSError(
|
||||
f"{self.parent.name} run into timeout in complete call."
|
||||
),
|
||||
)
|
||||
logger.info(f"Return status {self.parent.name}")
|
||||
return status
|
||||
|
||||
def on_complete(self) -> DeviceStatus:
|
||||
pass
|
||||
|
||||
def on_pre_scan(self) -> None:
|
||||
"""
|
||||
Method called by pre_scan hook in parent class.
|
||||
|
||||
Executes trigger if premove_trigger is Trus.
|
||||
"""
|
||||
if self.parent.premove_trigger.get() is True:
|
||||
self.parent.trigger_shot.put(1)
|
||||
|
||||
|
||||
class DelayGeneratorcSAXS(BECDeviceBase, DelayGenerator):
|
||||
"""
|
||||
DG645 delay generator at cSAXS (multiple can be in use depending on the setup)
|
||||
|
||||
Default values for setting up DDG.
|
||||
Note: checks of set calues are not (only partially) included, check manual for details on possible settings.
|
||||
https://www.thinksrs.com/downloads/pdfs/manuals/DG645m.pdf
|
||||
|
||||
- delay_burst : (float >=0) Delay between trigger and first pulse in burst mode
|
||||
- delta_width : (float >= 0) Add width to fast shutter signal to make sure its open during acquisition
|
||||
- additional_triggers : (int) add additional triggers to burst mode (mcs card needs +1 triggers per line)
|
||||
- polarity : (list of 0/1) polarity for different channels
|
||||
- amplitude : (float) amplitude voltage of TTLs
|
||||
- offset : (float) offset for ampltitude
|
||||
- thres_trig_level : (float) threshold of trigger amplitude
|
||||
|
||||
Custom signals for logic in different DDGs during scans (for custom_prepare.prepare_ddg):
|
||||
|
||||
- set_high_on_exposure : (bool): if True, then TTL signal should go high during the full acquisition time of a scan.
|
||||
# TODO trigger_width and fixed_ttl could be combined into single list.
|
||||
- fixed_ttl_width : (list of either 1 or 0), one for each channel.
|
||||
- trigger_width : (float) if fixed_ttl_width is True, then the width of the TTL pulse is set to this value.
|
||||
- set_trigger_source : (TriggerSource) specifies the default trigger source for the DDG.
|
||||
- premove_trigger : (bool) if True, then a trigger should be executed before the scan starts (to be implemented in on_pre_scan).
|
||||
- set_high_on_stage : (bool) if True, then TTL signal should go high already on stage.
|
||||
"""
|
||||
|
||||
custom_prepare_cls = DDGSetup
|
||||
|
||||
# Custom signals passed on during the init procedure via BEC
|
||||
# TODO review whether those should remain here like that
|
||||
|
||||
delay_burst = Component(
|
||||
bec_utils.ConfigSignal, name="delay_burst", kind="config", config_storage_name="ddg_config"
|
||||
)
|
||||
|
||||
delta_width = Component(
|
||||
bec_utils.ConfigSignal, name="delta_width", kind="config", config_storage_name="ddg_config"
|
||||
)
|
||||
|
||||
additional_triggers = Component(
|
||||
bec_utils.ConfigSignal,
|
||||
name="additional_triggers",
|
||||
kind="config",
|
||||
config_storage_name="ddg_config",
|
||||
)
|
||||
|
||||
polarity = Component(
|
||||
bec_utils.ConfigSignal, name="polarity", kind="config", config_storage_name="ddg_config"
|
||||
)
|
||||
|
||||
fixed_ttl_width = Component(
|
||||
bec_utils.ConfigSignal,
|
||||
name="fixed_ttl_width",
|
||||
kind="config",
|
||||
config_storage_name="ddg_config",
|
||||
)
|
||||
|
||||
amplitude = Component(
|
||||
bec_utils.ConfigSignal, name="amplitude", kind="config", config_storage_name="ddg_config"
|
||||
)
|
||||
|
||||
offset = Component(
|
||||
bec_utils.ConfigSignal, name="offset", kind="config", config_storage_name="ddg_config"
|
||||
)
|
||||
|
||||
thres_trig_level = Component(
|
||||
bec_utils.ConfigSignal,
|
||||
name="thres_trig_level",
|
||||
kind="config",
|
||||
config_storage_name="ddg_config",
|
||||
)
|
||||
|
||||
set_high_on_exposure = Component(
|
||||
bec_utils.ConfigSignal,
|
||||
name="set_high_on_exposure",
|
||||
kind="config",
|
||||
config_storage_name="ddg_config",
|
||||
)
|
||||
|
||||
set_high_on_stage = Component(
|
||||
bec_utils.ConfigSignal,
|
||||
name="set_high_on_stage",
|
||||
kind="config",
|
||||
config_storage_name="ddg_config",
|
||||
)
|
||||
|
||||
set_trigger_source = Component(
|
||||
bec_utils.ConfigSignal,
|
||||
name="set_trigger_source",
|
||||
kind="config",
|
||||
config_storage_name="ddg_config",
|
||||
)
|
||||
|
||||
trigger_width = Component(
|
||||
bec_utils.ConfigSignal,
|
||||
name="trigger_width",
|
||||
kind="config",
|
||||
config_storage_name="ddg_config",
|
||||
)
|
||||
premove_trigger = Component(
|
||||
bec_utils.ConfigSignal,
|
||||
name="premove_trigger",
|
||||
kind="config",
|
||||
config_storage_name="ddg_config",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
prefix: str = "",
|
||||
kind: Kind = None,
|
||||
ddg_config: dict = None,
|
||||
parent=None,
|
||||
device_manager=None,
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
Args:
|
||||
prefix (str, optional): Prefix of the device. Defaults to "".
|
||||
name (str): Name of the device.
|
||||
kind (str, optional): Kind of the device. Defaults to None.
|
||||
read_attrs (list, optional): List of attributes to read. Defaults to None.
|
||||
configuration_attrs (list, optional): List of attributes to configure. Defaults to None.
|
||||
parent (Device, optional): Parent device. Defaults to None.
|
||||
device_manager (DeviceManagerBase, optional): DeviceManagerBase object. Defaults to None.
|
||||
sim_mode (bool, optional): Simulation mode flag. Defaults to False.
|
||||
ddg_config (dict, optional): Dictionary of ddg_config signals. Defaults to None.
|
||||
|
||||
"""
|
||||
|
||||
# Default values for ddg_config signals
|
||||
self.ddg_config = {
|
||||
# Setup default values
|
||||
f"{name}_delay_burst": 0,
|
||||
f"{name}_delta_width": 0,
|
||||
f"{name}_additional_triggers": 0,
|
||||
f"{name}_polarity": [1, 1, 1, 1, 1],
|
||||
f"{name}_amplitude": 4.5,
|
||||
f"{name}_offset": 0,
|
||||
f"{name}_thres_trig_level": 2.5,
|
||||
# Values for different behaviour during scans
|
||||
f"{name}_fixed_ttl_width": [0, 0, 0, 0, 0],
|
||||
f"{name}_trigger_width": None,
|
||||
f"{name}_set_high_on_exposure": False,
|
||||
f"{name}_set_high_on_stage": False,
|
||||
f"{name}_set_trigger_source": "SINGLE_SHOT",
|
||||
f"{name}_premove_trigger": False,
|
||||
}
|
||||
if ddg_config is not None:
|
||||
# pylint: disable=expression-not-assigned
|
||||
[self.ddg_config.update({f"{name}_{key}": value}) for key, value in ddg_config.items()]
|
||||
super().__init__(
|
||||
prefix=prefix,
|
||||
name=name,
|
||||
kind=kind,
|
||||
parent=parent,
|
||||
device_manager=device_manager,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
# if __name__ == "__main__":
|
||||
# dgen = DelayGeneratorcSAXS("X12SA-CPCL-DDG3:", name="ddg3")
|
||||
@@ -1,381 +0,0 @@
|
||||
import enum
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
import numpy as np
|
||||
from bec_lib.logger import bec_logger
|
||||
from ophyd import ADComponent as ADCpt
|
||||
from ophyd import Device, EpicsSignal, EpicsSignalRO, EpicsSignalWithRBV
|
||||
from ophyd_devices.interfaces.base_classes.psi_detector_base import (
|
||||
CustomDetectorMixin,
|
||||
PSIDetectorBase,
|
||||
)
|
||||
from std_daq_client import StdDaqClient
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
|
||||
class EigerError(Exception):
|
||||
"""Base class for exceptions in this module."""
|
||||
|
||||
|
||||
class EigerTimeoutError(EigerError):
|
||||
"""Raised when the Eiger does not respond in time."""
|
||||
|
||||
|
||||
class Eiger9MSetup(CustomDetectorMixin):
|
||||
"""Eiger setup class
|
||||
|
||||
Parent class: CustomDetectorMixin
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, parent: Device = None, **kwargs) -> None:
|
||||
super().__init__(*args, parent=parent, **kwargs)
|
||||
self.std_rest_server_url = (
|
||||
kwargs["file_writer_url"] if "file_writer_url" in kwargs else "http://xbl-daq-29:5000"
|
||||
)
|
||||
self.std_client = None
|
||||
self._lock = threading.RLock()
|
||||
|
||||
def on_init(self) -> None:
|
||||
"""Initialize the detector"""
|
||||
self.initialize_default_parameter()
|
||||
self.initialize_detector()
|
||||
self.initialize_detector_backend()
|
||||
|
||||
def initialize_detector(self) -> None:
|
||||
"""Initialize detector"""
|
||||
self.stop_detector()
|
||||
self.parent.cam.trigger_mode.put(TriggerSource.GATING)
|
||||
|
||||
def initialize_default_parameter(self) -> None:
|
||||
"""Set default parameters for Eiger9M detector"""
|
||||
self.update_readout_time()
|
||||
|
||||
def update_readout_time(self) -> None:
|
||||
"""Set readout time for Eiger9M detector"""
|
||||
readout_time = (
|
||||
self.parent.scaninfo.readout_time
|
||||
if hasattr(self.parent.scaninfo, "readout_time")
|
||||
else self.parent.MIN_READOUT
|
||||
)
|
||||
self.parent.readout_time = max(readout_time, self.parent.MIN_READOUT)
|
||||
|
||||
def initialize_detector_backend(self) -> None:
|
||||
"""Initialize detector backend"""
|
||||
|
||||
self.std_client = StdDaqClient(url_base=self.std_rest_server_url)
|
||||
self.std_client.stop_writer()
|
||||
eacc = self.parent.scaninfo.username
|
||||
self.update_std_cfg("writer_user_id", int(eacc.strip(" e")))
|
||||
|
||||
signal_conditions = [(lambda: self.std_client.get_status()["state"], "READY")]
|
||||
if not self.wait_for_signals(
|
||||
signal_conditions=signal_conditions,
|
||||
timeout=self.parent.TIMEOUT_FOR_SIGNALS,
|
||||
all_signals=True,
|
||||
):
|
||||
raise EigerTimeoutError(
|
||||
f"Std client not in READY state, returns: {self.std_client.get_status()}"
|
||||
)
|
||||
|
||||
def update_std_cfg(self, cfg_key: str, value: Any) -> None:
|
||||
"""
|
||||
Update std_daq config
|
||||
|
||||
Checks that the new value matches the type of the former entry.
|
||||
|
||||
Args:
|
||||
cfg_key (str) : config key of value to be updated
|
||||
value (Any) : value to be updated for the specified key
|
||||
|
||||
Raises:
|
||||
Raises EigerError if the key was not in the config before and if the new value does not match the type of the old value
|
||||
|
||||
"""
|
||||
|
||||
cfg = self.std_client.get_config()
|
||||
old_value = cfg.get(cfg_key)
|
||||
if old_value is None:
|
||||
raise EigerError(
|
||||
f"Tried to change entry for key {cfg_key} in std_config that does not exist"
|
||||
)
|
||||
if not isinstance(value, type(old_value)):
|
||||
raise EigerError(
|
||||
f"Type of new value {type(value)}:{value} does not match old value"
|
||||
f" {type(old_value)}:{old_value}"
|
||||
)
|
||||
|
||||
cfg.update({cfg_key: value})
|
||||
logger.debug(cfg)
|
||||
self.std_client.set_config(cfg)
|
||||
logger.debug(f"Updated std_daq config for key {cfg_key} from {old_value} to {value}")
|
||||
|
||||
def on_stage(self) -> None:
|
||||
"""Prepare the detector for scan"""
|
||||
self.prepare_detector()
|
||||
self.prepare_data_backend()
|
||||
self.publish_file_location(done=False, successful=False)
|
||||
self.arm_acquisition()
|
||||
|
||||
def prepare_detector(self) -> None:
|
||||
"""Prepare detector for scan"""
|
||||
self.set_detector_threshold()
|
||||
self.set_acquisition_params()
|
||||
self.parent.cam.trigger_mode.put(TriggerSource.GATING)
|
||||
|
||||
def set_detector_threshold(self) -> None:
|
||||
"""
|
||||
Set the detector threshold
|
||||
|
||||
The function sets the detector threshold automatically to 1/2 of the beam energy.
|
||||
"""
|
||||
mokev = self.parent.device_manager.devices.mokev.obj.read()[
|
||||
self.parent.device_manager.devices.mokev.name
|
||||
]["value"]
|
||||
factor = 1
|
||||
unit = getattr(self.parent.cam.threshold_energy, "units", None)
|
||||
|
||||
if unit is not None and unit == "eV":
|
||||
factor = 1000
|
||||
setpoint = int(mokev * factor)
|
||||
energy = self.parent.cam.beam_energy.read()[self.parent.cam.beam_energy.name]["value"]
|
||||
|
||||
if setpoint != energy:
|
||||
self.parent.cam.beam_energy.set(setpoint)
|
||||
|
||||
threshold = self.parent.cam.threshold_energy.read()[self.parent.cam.threshold_energy.name][
|
||||
"value"
|
||||
]
|
||||
if not np.isclose(setpoint / 2, threshold, rtol=0.05):
|
||||
self.parent.cam.threshold_energy.set(setpoint / 2)
|
||||
|
||||
def set_acquisition_params(self) -> None:
|
||||
"""Set acquisition parameters for the detector"""
|
||||
self.parent.cam.num_images.put(
|
||||
int(self.parent.scaninfo.num_points * self.parent.scaninfo.frames_per_trigger)
|
||||
)
|
||||
self.parent.cam.num_frames.put(1)
|
||||
self.update_readout_time()
|
||||
|
||||
def prepare_data_backend(self) -> None:
|
||||
"""Prepare the data backend for the scan"""
|
||||
self.parent.filepath.set(
|
||||
self.parent.filewriter.compile_full_filename(f"{self.parent.name}.h5")
|
||||
).wait()
|
||||
self.filepath_exists(self.parent.filepath.get())
|
||||
self.stop_detector_backend()
|
||||
try:
|
||||
self.std_client.start_writer_async(
|
||||
{
|
||||
"output_file": self.parent.filepath.get(),
|
||||
"n_images": int(
|
||||
self.parent.scaninfo.num_points * self.parent.scaninfo.frames_per_trigger
|
||||
),
|
||||
}
|
||||
)
|
||||
except Exception as exc:
|
||||
time.sleep(5)
|
||||
if self.std_client.get_status()["state"] == "READY":
|
||||
raise EigerTimeoutError(f"Timeout of start_writer_async with {exc}") from exc
|
||||
|
||||
signal_conditions = [
|
||||
(lambda: self.std_client.get_status()["acquisition"]["state"], "WAITING_IMAGES")
|
||||
]
|
||||
if not self.wait_for_signals(
|
||||
signal_conditions=signal_conditions,
|
||||
timeout=self.parent.TIMEOUT_FOR_SIGNALS,
|
||||
check_stopped=False,
|
||||
all_signals=True,
|
||||
):
|
||||
raise EigerTimeoutError(
|
||||
"Timeout of 5s reached for std_daq start_writer_async with std_daq client status"
|
||||
f" {self.std_client.get_status()}"
|
||||
)
|
||||
|
||||
def on_unstage(self) -> None:
|
||||
"""Unstage the detector"""
|
||||
pass
|
||||
|
||||
def on_complete(self) -> None:
|
||||
"""Complete the detector"""
|
||||
self.finished(timeout=self.parent.TIMEOUT_FOR_SIGNALS)
|
||||
self.publish_file_location(done=True, successful=True)
|
||||
|
||||
def on_stop(self) -> None:
|
||||
"""Stop the detector"""
|
||||
self.stop_detector()
|
||||
self.stop_detector_backend()
|
||||
|
||||
def stop_detector(self) -> None:
|
||||
"""Stop the detector"""
|
||||
|
||||
# Stop detector
|
||||
self.parent.cam.acquire.put(0)
|
||||
signal_conditions = [
|
||||
(
|
||||
lambda: self.parent.cam.detector_state.read()[self.parent.cam.detector_state.name][
|
||||
"value"
|
||||
],
|
||||
DetectorState.IDLE,
|
||||
)
|
||||
]
|
||||
|
||||
if not self.wait_for_signals(
|
||||
signal_conditions=signal_conditions,
|
||||
timeout=self.parent.TIMEOUT_FOR_SIGNALS - self.parent.TIMEOUT_FOR_SIGNALS // 2,
|
||||
check_stopped=True,
|
||||
all_signals=False,
|
||||
):
|
||||
# Retry stop detector and wait for remaining time
|
||||
self.parent.cam.acquire.put(0)
|
||||
if not self.wait_for_signals(
|
||||
signal_conditions=signal_conditions,
|
||||
timeout=self.parent.TIMEOUT_FOR_SIGNALS - self.parent.TIMEOUT_FOR_SIGNALS // 2,
|
||||
check_stopped=True,
|
||||
all_signals=False,
|
||||
):
|
||||
raise EigerTimeoutError(
|
||||
f"Failed to stop detector, detector state {signal_conditions[0][0]}"
|
||||
)
|
||||
|
||||
def stop_detector_backend(self) -> None:
|
||||
"""Close file writer"""
|
||||
self.std_client.stop_writer()
|
||||
|
||||
def filepath_exists(self, filepath: str) -> None:
|
||||
"""Check if filepath exists"""
|
||||
signal_conditions = [(lambda: os.path.exists(os.path.dirname(filepath)), True)]
|
||||
if not self.wait_for_signals(
|
||||
signal_conditions=signal_conditions,
|
||||
timeout=self.parent.TIMEOUT_FOR_SIGNALS,
|
||||
check_stopped=False,
|
||||
all_signals=True,
|
||||
):
|
||||
raise EigerError(f"Timeout of 3s reached for filepath {filepath}")
|
||||
|
||||
def arm_acquisition(self) -> None:
|
||||
"""Arm Eiger detector for acquisition"""
|
||||
self.parent.cam.acquire.put(1)
|
||||
signal_conditions = [
|
||||
(
|
||||
lambda: self.parent.cam.detector_state.read()[self.parent.cam.detector_state.name][
|
||||
"value"
|
||||
],
|
||||
DetectorState.RUNNING,
|
||||
)
|
||||
]
|
||||
if not self.wait_for_signals(
|
||||
signal_conditions=signal_conditions,
|
||||
timeout=self.parent.TIMEOUT_FOR_SIGNALS,
|
||||
check_stopped=True,
|
||||
all_signals=False,
|
||||
):
|
||||
raise EigerTimeoutError(
|
||||
f"Failed to arm the acquisition. Detector state {signal_conditions[0][0]}"
|
||||
)
|
||||
|
||||
def finished(self, timeout: int = 5) -> None:
|
||||
"""Check if acquisition is finished."""
|
||||
with self._lock:
|
||||
signal_conditions = [
|
||||
(
|
||||
lambda: self.parent.cam.acquire.read()[self.parent.cam.acquire.name]["value"],
|
||||
DetectorState.IDLE,
|
||||
),
|
||||
(lambda: self.std_client.get_status()["acquisition"]["state"], "FINISHED"),
|
||||
(
|
||||
lambda: self.std_client.get_status()["acquisition"]["stats"][
|
||||
"n_write_completed"
|
||||
],
|
||||
int(self.parent.scaninfo.num_points * self.parent.scaninfo.frames_per_trigger),
|
||||
),
|
||||
]
|
||||
if not self.wait_for_signals(
|
||||
signal_conditions=signal_conditions,
|
||||
timeout=timeout,
|
||||
check_stopped=True,
|
||||
all_signals=True,
|
||||
):
|
||||
raise EigerTimeoutError(
|
||||
f"Reached timeout with detector state {signal_conditions[0][0]}, std_daq state"
|
||||
f" {signal_conditions[1][0]} and received frames of {signal_conditions[2][0]} for"
|
||||
" the file writer"
|
||||
)
|
||||
self.stop_detector()
|
||||
self.stop_detector_backend()
|
||||
|
||||
|
||||
class SLSDetectorCam(Device):
|
||||
"""
|
||||
SLS Detector Camera - Eiger9M
|
||||
|
||||
Base class to map EPICS PVs to ophyd signals.
|
||||
"""
|
||||
|
||||
threshold_energy = ADCpt(EpicsSignalWithRBV, "ThresholdEnergy")
|
||||
beam_energy = ADCpt(EpicsSignalWithRBV, "BeamEnergy")
|
||||
bit_depth = ADCpt(EpicsSignalWithRBV, "BitDepth")
|
||||
num_images = ADCpt(EpicsSignalWithRBV, "NumCycles")
|
||||
num_frames = ADCpt(EpicsSignalWithRBV, "NumFrames")
|
||||
trigger_mode = ADCpt(EpicsSignalWithRBV, "TimingMode")
|
||||
trigger_software = ADCpt(EpicsSignal, "TriggerSoftware")
|
||||
acquire = ADCpt(EpicsSignal, "Acquire")
|
||||
detector_state = ADCpt(EpicsSignalRO, "DetectorState_RBV")
|
||||
|
||||
|
||||
class TriggerSource(int, enum.Enum):
|
||||
"""Trigger signals for Eiger9M detector"""
|
||||
|
||||
AUTO = 0
|
||||
TRIGGER = 1
|
||||
GATING = 2
|
||||
BURST_TRIGGER = 3
|
||||
|
||||
|
||||
class DetectorState(int, enum.Enum):
|
||||
"""Detector states for Eiger9M detector"""
|
||||
|
||||
IDLE = 0
|
||||
ERROR = 1
|
||||
WAITING = 2
|
||||
FINISHED = 3
|
||||
TRANSMITTING = 4
|
||||
RUNNING = 5
|
||||
STOPPED = 6
|
||||
STILL_WAITING = 7
|
||||
INITIALIZING = 8
|
||||
DISCONNECTED = 9
|
||||
ABORTED = 10
|
||||
|
||||
|
||||
class Eiger9McSAXS(PSIDetectorBase):
|
||||
"""
|
||||
Eiger9M detector for CSAXS
|
||||
|
||||
Parent class: PSIDetectorBase
|
||||
|
||||
class attributes:
|
||||
custom_prepare_cls (FalconSetup) : Custom detector setup class for cSAXS,
|
||||
inherits from CustomDetectorMixin
|
||||
PSIDetectorBase.set_min_readout (float) : Minimum readout time for the detector
|
||||
Various EpicsPVs for controlling the detector
|
||||
"""
|
||||
|
||||
# Specify which functions are revealed to the user in BEC client
|
||||
USER_ACCESS = []
|
||||
|
||||
# specify Setup class
|
||||
custom_prepare_cls = Eiger9MSetup
|
||||
# specify minimum readout time for detector and timeout for checks after unstage
|
||||
MIN_READOUT = 3e-3
|
||||
TIMEOUT_FOR_SIGNALS = 5
|
||||
# specify class attributes
|
||||
cam = ADCpt(SLSDetectorCam, "cam1:")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
eiger = Eiger9McSAXS(name="eiger", prefix="X12SA-ES-EIGER9M:", sim_mode=True)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user